]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc/middle/resolve_lifetime.rs
fix nested impl trait lifetimes
[rust.git] / src / librustc / middle / resolve_lifetime.rs
index 59460141166b113585fd203453f2269035fd6df0..5201df2119dac8703de1aa9560586a813cbdf49c 100644 (file)
@@ -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 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
                 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 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
                         .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 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
                     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 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
                         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 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
                         });
                     });
                 } 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 @@ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
                     .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 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
                     .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 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
                                 .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 @@ fn visit_poly_trait_ref(
                     .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 check_if_label_shadows_lifetime(
                     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 @@ fn visit_early_late<F>(
             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 @@ fn visit_early_late<F>(
         });
     }
 
-    /// 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 @@ fn resolve_lifetime_ref(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
                     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 @@ fn check_lifetime_def_for_shadowing(&self,
                     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();