about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2018-03-21 04:57:57 -0400
committerNiko Matsakis <niko@alum.mit.edu>2018-03-22 16:54:51 -0400
commitf07ebc5df806ac9bd2a178f525b5422ce20d4e3c (patch)
tree39b4f0bd2fb23b2908bc588a1f1cf82e008e8cf4
parentf71807d507a83182e010623cd401ea275c43e950 (diff)
downloadrust-f07ebc5df806ac9bd2a178f525b5422ce20d4e3c.tar.gz
rust-f07ebc5df806ac9bd2a178f525b5422ce20d4e3c.zip
add a helper function `maybe_collect_in_band_lifetime`
-rw-r--r--src/librustc/hir/lowering.rs59
1 files changed, 44 insertions, 15 deletions
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 18fc559e5cb..8ac9c46d454 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -600,6 +600,29 @@ impl<'a> LoweringContext<'a> {
         (params, res)
     }
 
+    /// When there is a reference to some lifetime `'a`, and in-band
+    /// lifetimes are enabled, then we want to push that lifetime into
+    /// the vector of names to define later. In that case, it will get
+    /// added to the appropriate generics.
+    fn maybe_collect_in_band_lifetime(&mut self, span: Span, name: Name) {
+        if !self.is_collecting_in_band_lifetimes {
+            return;
+        }
+
+        if self.in_scope_lifetimes.contains(&name) {
+            return;
+        }
+
+        if self.lifetimes_to_define
+            .iter()
+            .any(|(_, lt_name)| *lt_name == name)
+        {
+            return;
+        }
+
+        self.lifetimes_to_define.push((span, name));
+    }
+
     // Evaluates `f` with the lifetimes in `lt_defs` in-scope.
     // This is used to track which lifetimes have already been defined, and
     // which are new in-band lifetimes that need to have a definition created
@@ -1726,15 +1749,7 @@ impl<'a> LoweringContext<'a> {
             x if x == "'_" => hir::LifetimeName::Underscore,
             x if x == "'static" => hir::LifetimeName::Static,
             name => {
-                if self.is_collecting_in_band_lifetimes && !self.in_scope_lifetimes.contains(&name)
-                    && self.lifetimes_to_define
-                        .iter()
-                        .find(|&&(_, lt_name)| lt_name == name)
-                        .is_none()
-                {
-                    self.lifetimes_to_define.push((l.span, name));
-                }
-
+                self.maybe_collect_in_band_lifetime(l.span, name);
                 hir::LifetimeName::Name(name)
             }
         };
@@ -2132,18 +2147,32 @@ impl<'a> LoweringContext<'a> {
                 polarity,
                 defaultness,
                 ref ast_generics,
-                ref ifce,
+                ref trait_ref,
                 ref ty,
                 ref impl_items,
             ) => {
                 let def_id = self.resolver.definitions().local_def_id(id);
-                let (generics, (ifce, lowered_ty)) =
+
+                // Lower the "impl header" first. This ordering is important
+                // for in-band lifetimes! Consider `'a` here:
+                //
+                //     impl Foo<'a> for u32 {
+                //         fn method(&'a self) { .. }
+                //     }
+                //
+                // Because we start by lowering the `Foo<'a> for u32`
+                // part, we will add `'a` to the list of generics on
+                // the impl. When we then encounter it later in the
+                // method, it will not be considered an in-band
+                // lifetime to be added, but rather a reference to a
+                // parent lifetime.
+                let (generics, (trait_ref, lowered_ty)) =
                     self.add_in_band_defs(ast_generics, def_id, |this| {
-                        let ifce = ifce.as_ref().map(|trait_ref| {
+                        let trait_ref = trait_ref.as_ref().map(|trait_ref| {
                             this.lower_trait_ref(trait_ref, ImplTraitContext::Disallowed)
                         });
 
-                        if let Some(ref trait_ref) = ifce {
+                        if let Some(ref trait_ref) = trait_ref {
                             if let Def::Trait(def_id) = trait_ref.path.def {
                                 this.trait_impls.entry(def_id).or_insert(vec![]).push(id);
                             }
@@ -2151,7 +2180,7 @@ impl<'a> LoweringContext<'a> {
 
                         let lowered_ty = this.lower_ty(ty, ImplTraitContext::Disallowed);
 
-                        (ifce, lowered_ty)
+                        (trait_ref, lowered_ty)
                     });
 
                 let new_impl_items = self.with_in_scope_lifetime_defs(
@@ -2172,7 +2201,7 @@ impl<'a> LoweringContext<'a> {
                     self.lower_impl_polarity(polarity),
                     self.lower_defaultness(defaultness, true /* [1] */),
                     generics,
-                    ifce,
+                    trait_ref,
                     lowered_ty,
                     new_impl_items,
                 )