diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2018-03-21 16:59:28 -0400 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2018-03-22 16:54:52 -0400 |
| commit | df70060bd6cd4f2a589a83999139600087e7bbc9 (patch) | |
| tree | 37a3752489b28b399288aa3e16a4104cd72450c6 | |
| parent | 1488095b08b0b85bff4b3d6d432e3f7cc7cd6d09 (diff) | |
| download | rust-df70060bd6cd4f2a589a83999139600087e7bbc9.tar.gz rust-df70060bd6cd4f2a589a83999139600087e7bbc9.zip | |
distinguish the three cases where elision occurs
| -rw-r--r-- | src/librustc/hir/lowering.rs | 36 | ||||
| -rw-r--r-- | src/librustc/middle/resolve_lifetime.rs | 157 |
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 +} |
