about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTaylor Cramer <cramertj@google.com>2018-01-17 17:22:40 -0800
committerTaylor Cramer <cramertj@google.com>2018-02-08 08:13:57 -0800
commitdd481d5f462d8c7bd5e81438ccc1ef3013343408 (patch)
tree5e9c13678f9d5c2f6fcff52cf6c0a2b38d43507c
parent932c736479f43dc8893a924946e4335d8e308c2e (diff)
downloadrust-dd481d5f462d8c7bd5e81438ccc1ef3013343408.tar.gz
rust-dd481d5f462d8c7bd5e81438ccc1ef3013343408.zip
fix nested impl trait lifetimes
-rw-r--r--src/librustc/middle/resolve_lifetime.rs82
-rw-r--r--src/test/run-pass/impl-trait/lifetimes.rs8
2 files changed, 79 insertions, 11 deletions
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 59460141166..5201df2119d 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -270,6 +270,19 @@ enum Scope<'a> {
         /// we should use for an early-bound region?
         next_early_index: u32,
 
+        /// Whether or not this binder would serve as the parent
+        /// binder for abstract types introduced within. For example:
+        ///
+        ///     fn foo<'a>() -> impl for<'b> Trait<Item = impl Trait2<'a>>
+        ///
+        /// Here, the abstract types we create for the `impl Trait`
+        /// and `impl Trait2` references will both have the `foo` item
+        /// as their parent. When we get to `impl Trait2`, we find
+        /// that it is nested within the `for<>` binder -- this flag
+        /// allows us to skip that when looking for the parent binder
+        /// of the resulting abstract type.
+        abstract_type_parent: bool,
+
         s: ScopeRef<'a>,
     },
 
@@ -498,6 +511,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 let scope = Scope::Binder {
                     lifetimes,
                     next_early_index,
+                    abstract_type_parent: true,
                     s: ROOT_SCOPE,
                 };
                 self.with(scope, |old_scope, this| {
@@ -541,6 +555,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         .collect(),
                     s: self.scope,
                     next_early_index,
+                    abstract_type_parent: false,
                 };
                 self.with(scope, |old_scope, this| {
                     // a bare fn has no bounds, so everything
@@ -614,7 +629,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     ref generics,
                     ref bounds,
                 } = *exist_ty;
-                let mut index = self.next_early_index();
+
+                // We want to start our early-bound indices at the end of the parent scope,
+                // not including any parent `impl Trait`s.
+                let mut index = self.next_early_index_for_abstract_type();
                 debug!("visit_ty: index = {}", index);
 
                 let mut elision = None;
@@ -638,7 +656,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         s: self.scope
                     };
                     self.with(scope, |_old_scope, this| {
-                        let scope = Scope::Binder { lifetimes, next_early_index, s: this.scope };
+                        let scope = Scope::Binder {
+                            lifetimes,
+                            next_early_index,
+                            s: this.scope,
+                            abstract_type_parent: false,
+                        };
                         this.with(scope, |_old_scope, this| {
                             this.visit_generics(generics);
                             for bound in bounds {
@@ -647,7 +670,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         });
                     });
                 } else {
-                    let scope = Scope::Binder { lifetimes, next_early_index, s: self.scope };
+                    let scope = Scope::Binder {
+                        lifetimes,
+                        next_early_index,
+                        s: self.scope,
+                        abstract_type_parent: false,
+                    };
                     self.with(scope, |_old_scope, this| {
                         this.visit_generics(generics);
                         for bound in bounds {
@@ -681,7 +709,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     .collect();
 
                 let next_early_index = index + generics.ty_params().count() as u32;
-                let scope = Scope::Binder { lifetimes, next_early_index, s: self.scope };
+                let scope = Scope::Binder {
+                    lifetimes,
+                    next_early_index,
+                    s: self.scope,
+                    abstract_type_parent: true,
+                };
                 self.with(scope, |_old_scope, this| {
                     this.visit_generics(generics);
                     for bound in bounds {
@@ -721,7 +754,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     .collect();
 
                 let next_early_index = index + generics.ty_params().count() as u32;
-                let scope = Scope::Binder { lifetimes, next_early_index, s: self.scope };
+                let scope = Scope::Binder {
+                    lifetimes,
+                    next_early_index,
+                    s: self.scope,
+                    abstract_type_parent: true,
+                };
                 self.with(scope, |_old_scope, this| {
                     this.visit_generics(generics);
                     this.visit_ty(ty);
@@ -792,6 +830,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                                 .collect(),
                             s: self.scope,
                             next_early_index,
+                            abstract_type_parent: false,
                         };
                         let result = self.with(scope, |old_scope, this| {
                             this.check_lifetime_params(old_scope, &bound_generic_params);
@@ -853,6 +892,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     .collect(),
                 s: self.scope,
                 next_early_index,
+                abstract_type_parent: false,
             };
             self.with(scope, |old_scope, this| {
                 this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params);
@@ -1046,6 +1086,7 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body) {
                     ref lifetimes,
                     s,
                     next_early_index: _,
+                    abstract_type_parent: _,
                 } => {
                     // FIXME (#24278): non-hygienic comparison
                     if let Some(def) = lifetimes.get(&hir::LifetimeName::Name(label)) {
@@ -1303,6 +1344,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             lifetimes,
             next_early_index,
             s: self.scope,
+            abstract_type_parent: true,
         };
         self.with(scope, move |old_scope, this| {
             this.check_lifetime_params(old_scope, &generics.params);
@@ -1310,25 +1352,41 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         });
     }
 
-    /// Returns the next index one would use for an early-bound-region
-    /// if extending the current scope.
-    fn next_early_index(&self) -> u32 {
+    fn next_early_index_helper(&self, only_abstract_type_parent: bool) -> u32 {
         let mut scope = self.scope;
         loop {
             match *scope {
                 Scope::Root => return 0,
 
                 Scope::Binder {
-                    next_early_index, ..
-                } => return next_early_index,
+                    next_early_index,
+                    abstract_type_parent,
+                    ..
+                } if (!only_abstract_type_parent || abstract_type_parent)
+                => return next_early_index,
 
-                Scope::Body { s, .. }
+                Scope::Binder { s, .. }
+                | Scope::Body { s, .. }
                 | Scope::Elision { s, .. }
                 | Scope::ObjectLifetimeDefault { s, .. } => scope = s,
             }
         }
     }
 
+    /// Returns the next index one would use for an early-bound-region
+    /// if extending the current scope.
+    fn next_early_index(&self) -> u32 {
+        self.next_early_index_helper(true)
+    }
+
+    /// Returns the next index one would use for an `impl Trait` that
+    /// is being converted into an `abstract type`. This will be the
+    /// next early index from the enclosing item, for the most
+    /// part. See the `abstract_type_parent` field for more info.
+    fn next_early_index_for_abstract_type(&self) -> u32 {
+        self.next_early_index_helper(false)
+    }
+
     fn resolve_lifetime_ref(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
         debug!("resolve_lifetime_ref(lifetime_ref={:?})", lifetime_ref);
         // Walk up the scope chain, tracking the number of fn scopes
@@ -1353,6 +1411,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                     ref lifetimes,
                     s,
                     next_early_index: _,
+                    abstract_type_parent: _,
                 } => {
                     if let Some(&def) = lifetimes.get(&lifetime_ref.name) {
                         break Some(def.shifted(late_depth));
@@ -2102,6 +2161,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                     ref lifetimes,
                     s,
                     next_early_index: _,
+                    abstract_type_parent: _,
                 } => {
                     if let Some(&def) = lifetimes.get(&lifetime.name) {
                         let node_id = self.tcx.hir.as_local_node_id(def.id().unwrap()).unwrap();
diff --git a/src/test/run-pass/impl-trait/lifetimes.rs b/src/test/run-pass/impl-trait/lifetimes.rs
index 1f2d76f2894..213a46ded8e 100644
--- a/src/test/run-pass/impl-trait/lifetimes.rs
+++ b/src/test/run-pass/impl-trait/lifetimes.rs
@@ -50,6 +50,14 @@ fn closure_hr_elided_return() -> impl Fn(&u32) -> &u32 { |x| x }
 fn closure_pass_through_elided_return(x: impl Fn(&u32) -> &u32) -> impl Fn(&u32) -> &u32 { x }
 fn closure_pass_through_reference_elided(x: &impl Fn(&u32) -> &u32) -> &impl Fn(&u32) -> &u32 { x }
 
+fn nested_lifetime<'a>(input: &'a str)
+    -> impl Iterator<Item = impl Iterator<Item = i32> + 'a> + 'a
+{
+    input.lines().map(|line| {
+        line.split_whitespace().map(|cell| cell.parse().unwrap())
+    })
+}
+
 fn pass_through_elision(x: &u32) -> impl Into<&u32> { x }
 fn pass_through_elision_with_fn_ptr(x: &fn(&u32) -> &u32) -> impl Into<&fn(&u32) -> &u32> { x }