about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2018-03-21 16:59:28 -0400
committerNiko Matsakis <niko@alum.mit.edu>2018-03-22 16:54:52 -0400
commitdf70060bd6cd4f2a589a83999139600087e7bbc9 (patch)
tree37a3752489b28b399288aa3e16a4104cd72450c6
parent1488095b08b0b85bff4b3d6d432e3f7cc7cd6d09 (diff)
downloadrust-df70060bd6cd4f2a589a83999139600087e7bbc9.tar.gz
rust-df70060bd6cd4f2a589a83999139600087e7bbc9.zip
distinguish the three cases where elision occurs
-rw-r--r--src/librustc/hir/lowering.rs36
-rw-r--r--src/librustc/middle/resolve_lifetime.rs157
2 files changed, 119 insertions, 74 deletions
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index b8bacb24c71..36eafb61768 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -129,6 +129,7 @@ pub struct LoweringContext<'a> {
     // This will always be false unless the `in_band_lifetimes` feature is
     // enabled.
     is_collecting_in_band_lifetimes: bool,
+
     // Currently in-scope lifetimes defined in impl headers, fn headers, or HRTB.
     // When `is_collectin_in_band_lifetimes` is true, each lifetime is checked
     // against this list to see if it is already in-scope, or if a definition
@@ -945,7 +946,7 @@ impl<'a> LoweringContext<'a> {
                 let span = t.span.shrink_to_lo();
                 let lifetime = match *region {
                     Some(ref lt) => self.lower_lifetime(lt),
-                    None => self.elided_lifetime(span),
+                    None => self.elided_ref_lifetime(span),
                 };
                 hir::TyRptr(lifetime, self.lower_mt(mt, itctx))
             }
@@ -1013,7 +1014,8 @@ impl<'a> LoweringContext<'a> {
                         }
                     })
                     .collect();
-                let lifetime_bound = lifetime_bound.unwrap_or_else(|| self.elided_lifetime(t.span));
+                let lifetime_bound =
+                    lifetime_bound.unwrap_or_else(|| self.elided_dyn_bound(t.span));
                 if kind != TraitObjectSyntax::Dyn {
                     self.maybe_lint_bare_trait(t.span, t.id, false);
                 }
@@ -1536,9 +1538,7 @@ impl<'a> LoweringContext<'a> {
         };
 
         if !parameters.parenthesized && parameters.lifetimes.is_empty() {
-            parameters.lifetimes = (0..expected_lifetimes)
-                .map(|_| self.elided_lifetime(path_span))
-                .collect();
+            parameters.lifetimes = self.elided_path_lifetimes(path_span, expected_lifetimes);
         }
 
         hir::PathSegment::new(
@@ -3999,7 +3999,7 @@ impl<'a> LoweringContext<'a> {
                     // The original ID is taken by the `PolyTraitRef`,
                     // so the `Ty` itself needs a different one.
                     id = self.next_id();
-                    hir::TyTraitObject(hir_vec![principal], self.elided_lifetime(span))
+                    hir::TyTraitObject(hir_vec![principal], self.elided_dyn_bound(span))
                 } else {
                     hir::TyPath(hir::QPath::Resolved(None, path))
                 }
@@ -4014,7 +4014,29 @@ impl<'a> LoweringContext<'a> {
         })
     }
 
-    fn elided_lifetime(&mut self, span: Span) -> hir::Lifetime {
+    /// Invoked to create the lifetime argument for a type `&T`
+    /// with no explicit lifetime.
+    fn elided_ref_lifetime(&mut self, span: Span) -> hir::Lifetime {
+        self.new_implicit_lifetime(span)
+    }
+
+    /// Invoked to create the lifetime argument(s) for a path like
+    /// `std::cell::Ref<T>`; note that implicit lifetimes in these
+    /// sorts of cases are deprecated. This may therefore report a warning or an
+    /// error, depending on the mode.
+    fn elided_path_lifetimes(&mut self, span: Span, count: usize) -> P<[hir::Lifetime]> {
+        (0..count).map(|_| self.new_implicit_lifetime(span)).collect()
+    }
+
+    /// Invoked to create the lifetime argument(s) for an elided trait object
+    /// bound, like the bound in `Box<dyn Debug>`. This method is not invoked
+    /// when the bound is written, even if it is written with `'_` like in
+    /// `Box<dyn Debug + '_>`. In those cases, `lower_lifetime` is invoked.
+    fn elided_dyn_bound(&mut self, span: Span) -> hir::Lifetime {
+        self.new_implicit_lifetime(span)
+    }
+
+    fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime {
         hir::Lifetime {
             id: self.next_id().node_id,
             span,
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 0aa750aba06..628cdce0dc7 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -31,6 +31,7 @@ use syntax::ptr::P;
 use syntax_pos::Span;
 use errors::DiagnosticBuilder;
 use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap, NodeSet};
+use session::Session;
 use std::slice;
 use rustc::lint;
 
@@ -468,11 +469,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         match item.node {
             hir::ItemFn(ref decl, _, _, _, ref generics, _) => {
-                self.visit_early_late(None,
-                                      decl,
-                                      generics,
-                                      |this| {
-                                          intravisit::walk_item(this, item);
+                self.visit_early_late(None, decl, generics, |this| {
+                    intravisit::walk_item(this, item);
                 });
             }
 
@@ -505,7 +503,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 } else {
                     0
                 };
-                let lifetimes = generics.lifetimes()
+                let lifetimes = generics
+                    .lifetimes()
                     .map(|def| Region::early(&self.tcx.hir, &mut index, def))
                     .collect();
                 let next_early_index = index + generics.ty_params().count() as u32;
@@ -526,12 +525,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
     fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
         match item.node {
             hir::ForeignItemFn(ref decl, _, ref generics) => {
-                self.visit_early_late(None,
-                                      decl,
-                                      generics,
-                                      |this| {
-                                          intravisit::walk_foreign_item(this, item);
-                                      })
+                self.visit_early_late(None, decl, generics, |this| {
+                    intravisit::walk_foreign_item(this, item);
+                })
             }
             hir::ForeignItemStatic(..) => {
                 intravisit::walk_foreign_item(self, item);
@@ -670,7 +666,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 if let Some(elision_region) = elision {
                     let scope = Scope::Elision {
                         elide: Elide::Exact(elision_region),
-                        s: self.scope
+                        s: self.scope,
                     };
                     self.with(scope, |_old_scope, this| {
                         let scope = Scope::Binder {
@@ -716,12 +712,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     &trait_item.generics,
                     |this| intravisit::walk_trait_item(this, trait_item),
                 );
-            },
+            }
             Type(ref bounds, ref ty) => {
                 let generics = &trait_item.generics;
                 let mut index = self.next_early_index();
                 debug!("visit_ty: index = {}", index);
-                let lifetimes = generics.lifetimes()
+                let lifetimes = generics
+                    .lifetimes()
                     .map(|lt_def| Region::early(&self.tcx.hir, &mut index, lt_def))
                     .collect();
 
@@ -741,12 +738,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         this.visit_ty(ty);
                     }
                 });
-            },
+            }
             Const(_, _) => {
                 // Only methods and types support generics.
                 assert!(trait_item.generics.params.is_empty());
                 intravisit::walk_trait_item(self, trait_item);
-            },
+            }
         }
     }
 
@@ -761,12 +758,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     &impl_item.generics,
                     |this| intravisit::walk_impl_item(this, impl_item),
                 )
-            },
+            }
             Type(ref ty) => {
                 let generics = &impl_item.generics;
                 let mut index = self.next_early_index();
                 debug!("visit_ty: index = {}", index);
-                let lifetimes = generics.lifetimes()
+                let lifetimes = generics
+                    .lifetimes()
                     .map(|lt_def| Region::early(&self.tcx.hir, &mut index, lt_def))
                     .collect();
 
@@ -781,12 +779,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     this.visit_generics(generics);
                     this.visit_ty(ty);
                 });
-            },
+            }
             Const(_, _) => {
                 // Only methods and types support generics.
                 assert!(impl_item.generics.params.is_empty());
                 intravisit::walk_impl_item(self, impl_item);
-            },
+            }
         }
     }
 
@@ -822,7 +820,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
     fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
         check_mixed_explicit_and_in_band_defs(
             self.tcx,
-            &generics.lifetimes().cloned().collect::<Vec<_>>()
+            &generics.lifetimes().cloned().collect::<Vec<_>>(),
         );
         for ty_param in generics.ty_params() {
             walk_list!(self, visit_ty_param_bound, &ty_param.bounds);
@@ -842,7 +840,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         self.trait_ref_hack = true;
                         let next_early_index = self.next_early_index();
                         let scope = Scope::Binder {
-                            lifetimes: bound_generic_params.lifetimes()
+                            lifetimes: bound_generic_params
+                                .lifetimes()
                                 .map(|def| Region::late(&self.tcx.hir, def))
                                 .collect(),
                             s: self.scope,
@@ -890,8 +889,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
     ) {
         debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref);
 
-        if !self.trait_ref_hack ||
-            trait_ref.bound_generic_params.iter().any(|p| p.is_lifetime_param())
+        if !self.trait_ref_hack
+            || trait_ref
+                .bound_generic_params
+                .iter()
+                .any(|p| p.is_lifetime_param())
         {
             if self.trait_ref_hack {
                 span_err!(
@@ -903,7 +905,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
             }
             let next_early_index = self.next_early_index();
             let scope = Scope::Binder {
-                lifetimes: trait_ref.bound_generic_params
+                lifetimes: trait_ref
+                    .bound_generic_params
                     .lifetimes()
                     .map(|def| Region::late(&self.tcx.hir, def))
                     .collect(),
@@ -1144,7 +1147,8 @@ fn compute_object_lifetime_defaults(
                         .map(|set| match *set {
                             Set1::Empty => "BaseDefault".to_string(),
                             Set1::One(Region::Static) => "'static".to_string(),
-                            Set1::One(Region::EarlyBound(i, _, _)) => generics.lifetimes()
+                            Set1::One(Region::EarlyBound(i, _, _)) => generics
+                                .lifetimes()
                                 .nth(i as usize)
                                 .unwrap()
                                 .lifetime
@@ -1182,7 +1186,8 @@ fn object_lifetime_defaults_for_item(
         }
     }
 
-    generics.ty_params()
+    generics
+        .ty_params()
         .map(|param| {
             let mut set = Set1::Empty;
 
@@ -1278,17 +1283,21 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                     if let hir::map::NodeLifetime(hir_lifetime) = this.tcx.hir.get(node_id) {
                         let span = hir_lifetime.span;
                         let id = hir_lifetime.id;
-                        debug!("id ={:?} span = {:?} hir_lifetime = {:?}",
-                            node_id,
-                            span,
-                            hir_lifetime);
+                        debug!(
+                            "id ={:?} span = {:?} hir_lifetime = {:?}",
+                            node_id, span, hir_lifetime
+                        );
 
                         this.tcx
-                            .struct_span_lint_node(lint::builtin::SINGLE_USE_LIFETIME,
-                                                   id,
-                                                   span,
-                                                   &format!("lifetime name `{}` only used once",
-                                                   hir_lifetime.name.name()))
+                            .struct_span_lint_node(
+                                lint::builtin::SINGLE_USE_LIFETIME,
+                                id,
+                                span,
+                                &format!(
+                                    "lifetime name `{}` only used once",
+                                    hir_lifetime.name.name()
+                                ),
+                            )
                             .emit();
                     }
                 }
@@ -1379,8 +1388,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                     next_early_index,
                     abstract_type_parent,
                     ..
-                } if (!only_abstract_type_parent || abstract_type_parent)
-                => return next_early_index,
+                } if (!only_abstract_type_parent || abstract_type_parent) =>
+                {
+                    return next_early_index
+                }
 
                 Scope::Binder { s, .. }
                 | Scope::Body { s, .. }
@@ -1698,8 +1709,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             }
 
             // Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds).
-            hir::map::NodeForeignItem(_) | hir::map::NodeTy(_) | hir::map::NodeTraitRef(_) =>
-                None,
+            hir::map::NodeForeignItem(_) | hir::map::NodeTy(_) | hir::map::NodeTraitRef(_) => None,
             // Everything else (only closures?) doesn't
             // actually enjoy elision in return types.
             _ => {
@@ -1894,7 +1904,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                     lint::builtin::ELIDED_LIFETIME_IN_PATH,
                     id,
                     span,
-                    &format!("hidden lifetime parameters are deprecated, try `Foo<'_>`"))
+                    &format!("hidden lifetime parameters are deprecated, try `Foo<'_>`"),
+                )
                 .emit();
         }
         let error = loop {
@@ -1933,25 +1944,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             }
         };
 
-        let mut err = struct_span_err!(
-            self.tcx.sess,
-            span,
-            E0106,
-            "missing lifetime specifier{}",
-            if lifetime_refs.len() > 1 { "s" } else { "" }
-        );
-        let msg = if lifetime_refs.len() > 1 {
-            format!("expected {} lifetime parameters", lifetime_refs.len())
-        } else {
-            format!("expected lifetime parameter")
-        };
-        err.span_label(span, msg);
+        let mut err = report_missing_lifetime_specifiers(self.tcx.sess, span, lifetime_refs.len());
 
         if let Some(params) = error {
             if lifetime_refs.len() == 1 {
                 self.report_elision_failure(&mut err, params);
             }
         }
+
         err.emit();
     }
 
@@ -2146,9 +2146,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         }
     }
 
-    fn check_lifetime_def_for_shadowing(&self,
-                                        mut old_scope: ScopeRef,
-                                        lifetime: &'tcx hir::Lifetime) {
+    fn check_lifetime_def_for_shadowing(
+        &self,
+        mut old_scope: ScopeRef,
+        lifetime: &'tcx hir::Lifetime,
+    ) {
         for &(label, label_span) in &self.labels_in_fn {
             // FIXME (#24278): non-hygienic comparison
             if lifetime.name.name() == label {
@@ -2216,14 +2218,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         self.map.defs.insert(lifetime_ref.id, def);
 
         match def {
-            Region::LateBoundAnon(..) |
-            Region::Static => {
+            Region::LateBoundAnon(..) | Region::Static => {
                 // These are anonymous lifetimes or lifetimes that are not declared.
             }
 
-            Region::Free(_, def_id) |
-            Region::LateBound(_, def_id, _) |
-            Region::EarlyBound(_, def_id, _) => {
+            Region::Free(_, def_id)
+            | Region::LateBound(_, def_id, _)
+            | Region::EarlyBound(_, def_id, _) => {
                 // A lifetime declared by the user.
                 if !self.lifetime_uses.contains_key(&def_id) {
                     self.lifetime_uses
@@ -2255,8 +2256,7 @@ fn insert_late_bound_lifetimes(
 ) {
     debug!(
         "insert_late_bound_lifetimes(decl={:?}, generics={:?})",
-        decl,
-        generics
+        decl, generics
     );
 
     let mut constrained_by_input = ConstrainedCollector {
@@ -2335,8 +2335,7 @@ fn insert_late_bound_lifetimes(
         debug!(
             "insert_late_bound_lifetimes: \
              lifetime {:?} with id {:?} is late-bound",
-            lifetime.lifetime.name,
-            lifetime.lifetime.id
+            lifetime.lifetime.name, lifetime.lifetime.id
         );
 
         let inserted = map.late_bound.insert(lifetime.lifetime.id);
@@ -2403,3 +2402,27 @@ fn insert_late_bound_lifetimes(
         }
     }
 }
+
+pub fn report_missing_lifetime_specifiers(
+    sess: &Session,
+    span: Span,
+    count: usize,
+) -> DiagnosticBuilder<'_> {
+    let mut err = struct_span_err!(
+        sess,
+        span,
+        E0106,
+        "missing lifetime specifier{}",
+        if count > 1 { "s" } else { "" }
+    );
+
+    let msg = if count > 1 {
+        format!("expected {} lifetime parameters", count)
+    } else {
+        format!("expected lifetime parameter")
+    };
+
+    err.span_label(span, msg);
+
+    err
+}