about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_typeck/astconv.rs74
-rw-r--r--src/test/compile-fail/issue-20831-debruijn.rs49
-rw-r--r--src/test/run-pass/regions-debruijn-of-object.rs25
3 files changed, 119 insertions, 29 deletions
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 45e05c12713..6c8ab50a993 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -516,8 +516,15 @@ pub fn instantiate_poly_trait_ref<'tcx>(
 {
     let mut projections = Vec::new();
 
+    // the trait reference introduces a binding level here, so
+    // we need to shift the `rscope`. It'd be nice if we could
+    // do away with this rscope stuff and work this knowledge
+    // into resolve_lifetimes, as we do with non-omitted
+    // lifetimes. Oh well, not there yet.
+    let shifted_rscope = ShiftedRscope::new(rscope);
+
     let trait_ref =
-        instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref,
+        instantiate_trait_ref(this, &shifted_rscope, &ast_trait_ref.trait_ref,
                               self_ty, Some(&mut projections));
 
     for projection in projections.into_iter() {
@@ -561,6 +568,29 @@ pub fn instantiate_trait_ref<'tcx>(
     }
 }
 
+fn object_path_to_poly_trait_ref<'a,'tcx>(
+    this: &AstConv<'tcx>,
+    rscope: &RegionScope,
+    trait_def_id: ast::DefId,
+    path: &ast::Path,
+    mut projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
+    -> ty::PolyTraitRef<'tcx>
+{
+    // we are introducing a binder here, so shift the
+    // anonymous regions depth to account for that
+    let shifted_rscope = ShiftedRscope::new(rscope);
+
+    let mut tmp = Vec::new();
+    let trait_ref = ty::Binder(ast_path_to_trait_ref(this,
+                                                     &shifted_rscope,
+                                                     trait_def_id,
+                                                     None,
+                                                     path,
+                                                     Some(&mut tmp)));
+    projections.extend(tmp.into_iter().map(ty::Binder));
+    trait_ref
+}
+
 fn ast_path_to_trait_ref<'a,'tcx>(
     this: &AstConv<'tcx>,
     rscope: &RegionScope,
@@ -573,13 +603,6 @@ fn ast_path_to_trait_ref<'a,'tcx>(
     debug!("ast_path_to_trait_ref {:?}", path);
     let trait_def = this.get_trait_def(trait_def_id);
 
-    // the trait reference introduces a binding level here, so
-    // we need to shift the `rscope`. It'd be nice if we could
-    // do away with this rscope stuff and work this knowledge
-    // into resolve_lifetimes, as we do with non-omitted
-    // lifetimes. Oh well, not there yet.
-    let shifted_rscope = ShiftedRscope::new(rscope);
-
     let (regions, types, assoc_bindings) = match path.segments.last().unwrap().parameters {
         ast::AngleBracketedParameters(ref data) => {
             // For now, require that parenthetical notation be used
@@ -595,7 +618,7 @@ fn ast_path_to_trait_ref<'a,'tcx>(
                             the crate attributes to enable");
             }
 
-            convert_angle_bracketed_parameters(this, &shifted_rscope, data)
+            convert_angle_bracketed_parameters(this, rscope, data)
         }
         ast::ParenthesizedParameters(ref data) => {
             // For now, require that parenthetical notation be used
@@ -616,7 +639,7 @@ fn ast_path_to_trait_ref<'a,'tcx>(
     };
 
     let substs = create_substs_for_ast_path(this,
-                                            &shifted_rscope,
+                                            rscope,
                                             path.span,
                                             &trait_def.generics,
                                             self_ty,
@@ -851,15 +874,11 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>,
             match this.tcx().def_map.borrow().get(&id) {
                 Some(&def::DefTrait(trait_def_id)) => {
                     let mut projection_bounds = Vec::new();
-                    let trait_ref = ty::Binder(ast_path_to_trait_ref(this,
-                                                                     rscope,
-                                                                     trait_def_id,
-                                                                     None,
-                                                                     path,
-                                                                     Some(&mut projection_bounds)));
-                    let projection_bounds = projection_bounds.into_iter()
-                                                             .map(ty::Binder)
-                                                             .collect();
+                    let trait_ref = object_path_to_poly_trait_ref(this,
+                                                                  rscope,
+                                                                  trait_def_id,
+                                                                  path,
+                                                                  &mut projection_bounds);
                     Ok((trait_ref, projection_bounds))
                 }
                 _ => {
@@ -1095,16 +1114,13 @@ pub fn ast_ty_to_ty<'tcx>(
                         // N.B. this case overlaps somewhat with
                         // TyObjectSum, see that fn for details
                         let mut projection_bounds = Vec::new();
-                        let trait_ref = ast_path_to_trait_ref(this,
-                                                              rscope,
-                                                              trait_def_id,
-                                                              None,
-                                                              path,
-                                                              Some(&mut projection_bounds));
-                        let trait_ref = ty::Binder(trait_ref);
-                        let projection_bounds = projection_bounds.into_iter()
-                                                                 .map(ty::Binder)
-                                                                 .collect();
+
+                        let trait_ref = object_path_to_poly_trait_ref(this,
+                                                                      rscope,
+                                                                      trait_def_id,
+                                                                      path,
+                                                                      &mut projection_bounds);
+
                         trait_ref_to_object_type(this, rscope, path.span,
                                                  trait_ref, projection_bounds, &[])
                     }
diff --git a/src/test/compile-fail/issue-20831-debruijn.rs b/src/test/compile-fail/issue-20831-debruijn.rs
new file mode 100644
index 00000000000..aaf45f27398
--- /dev/null
+++ b/src/test/compile-fail/issue-20831-debruijn.rs
@@ -0,0 +1,49 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for #20831: debruijn index account was thrown off
+// by the (anonymous) lifetime in `<Self as Publisher>::Output`
+// below. Note that changing to a named lifetime made the problem go
+// away.
+
+use std::ops::{Shl, Shr};
+use std::cell::RefCell;
+
+pub trait Subscriber {
+    type Input;
+}
+
+pub trait Publisher<'a> {
+    type Output;
+    fn subscribe(&mut self, Box<Subscriber<Input=Self::Output> + 'a>);
+}
+
+pub trait Processor<'a> : Subscriber + Publisher<'a> { }
+
+impl<'a, P> Processor<'a> for P where P : Subscriber + Publisher<'a> { }
+
+struct MyStruct<'a> {
+    sub: Box<Subscriber<Input=u64> + 'a>
+}
+
+impl<'a> Publisher<'a> for MyStruct<'a> {
+    type Output = u64;
+    fn subscribe(&mut self, t : Box<Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
+        // Not obvious, but there is an implicit lifetime here -------^
+        //~^^ ERROR cannot infer
+        //
+        // The fact that `Publisher` is using an implicit lifetime is
+        // what was causing the debruijn accounting to be off, so
+        // leave it that way!
+        self.sub = t;
+    }
+}
+
+fn main() {}
diff --git a/src/test/run-pass/regions-debruijn-of-object.rs b/src/test/run-pass/regions-debruijn-of-object.rs
new file mode 100644
index 00000000000..b9d3ed49c62
--- /dev/null
+++ b/src/test/run-pass/regions-debruijn-of-object.rs
@@ -0,0 +1,25 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct ctxt<'tcx> {
+    x: &'tcx i32
+}
+
+trait AstConv<'tcx> {
+    fn tcx<'a>(&'a self) -> &'a ctxt<'tcx>;
+}
+
+fn foo(conv: &AstConv) { }
+
+fn bar<'tcx>(conv: &AstConv<'tcx>) {
+    foo(conv)
+}
+
+fn main() { }