diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 5f8a58636c0..6926ed24afd 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -1,33 +1,12 @@ -//! Name resolution for lifetimes. -//! -//! Name resolution for lifetimes follows *much* simpler rules than the -//! full resolve. For example, lifetime names are never exported or -//! used between functions, and they operate in a purely top-down -//! way. Therefore, we break lifetime name resolution into a separate pass. +//! Name resolution for lifetimes: type declarations. -use crate::hir::def::{DefKind, Res}; -use crate::hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; -use crate::hir::map::Map; -use crate::hir::{GenericArg, GenericParam, ItemLocalId, LifetimeName, Node, ParamName, QPath}; -use crate::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt}; +use crate::hir::def_id::{DefId, LocalDefId}; +use crate::hir::{GenericParam, ItemLocalId}; +use crate::hir::{GenericParamKind, LifetimeParamKind}; +use crate::ty; -use crate::rustc::lint; -use crate::session::Session; -use crate::util::nodemap::{DefIdMap, FxHashMap, FxHashSet, HirIdMap, HirIdSet}; -use errors::{pluralize, Applicability, DiagnosticBuilder}; +use crate::util::nodemap::{FxHashMap, FxHashSet}; use rustc_macros::HashStable; -use std::borrow::Cow; -use std::cell::Cell; -use std::mem::{replace, take}; -use syntax::ast; -use syntax::attr; -use syntax::symbol::{kw, sym}; -use syntax_pos::Span; - -use crate::hir::intravisit::{self, NestedVisitorMap, Visitor}; -use crate::hir::{self, GenericParamKind, LifetimeParamKind}; - -use rustc_error_codes::*; /// The origin of a named lifetime definition. /// @@ -43,7 +22,7 @@ pub enum LifetimeDefOrigin { } impl LifetimeDefOrigin { - fn from_param(param: &GenericParam<'_>) -> Self { + pub fn from_param(param: &GenericParam<'_>) -> Self { match param.kind { GenericParamKind::Lifetime { kind } => match kind { LifetimeParamKind::InBand => LifetimeDefOrigin::InBand, @@ -56,13 +35,6 @@ impl LifetimeDefOrigin { } } -// This counts the no of times a lifetime is used -#[derive(Clone, Copy, Debug)] -pub enum LifetimeUseSet<'tcx> { - One(&'tcx hir::Lifetime), - Many, -} - #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug, HashStable)] pub enum Region { Static, @@ -72,80 +44,6 @@ pub enum Region { Free(DefId, /* lifetime decl */ DefId), } -impl Region { - fn early(hir_map: &Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region) { - let i = *index; - *index += 1; - let def_id = hir_map.local_def_id(param.hir_id); - let origin = LifetimeDefOrigin::from_param(param); - debug!("Region::early: index={} def_id={:?}", i, def_id); - (param.name.modern(), Region::EarlyBound(i, def_id, origin)) - } - - fn late(hir_map: &Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region) { - let depth = ty::INNERMOST; - let def_id = hir_map.local_def_id(param.hir_id); - let origin = LifetimeDefOrigin::from_param(param); - debug!( - "Region::late: param={:?} depth={:?} def_id={:?} origin={:?}", - param, depth, def_id, origin, - ); - (param.name.modern(), Region::LateBound(depth, def_id, origin)) - } - - fn late_anon(index: &Cell) -> Region { - let i = index.get(); - index.set(i + 1); - let depth = ty::INNERMOST; - Region::LateBoundAnon(depth, i) - } - - fn id(&self) -> Option { - match *self { - Region::Static | Region::LateBoundAnon(..) => None, - - Region::EarlyBound(_, id, _) | Region::LateBound(_, id, _) | Region::Free(_, id) => { - Some(id) - } - } - } - - fn shifted(self, amount: u32) -> Region { - match self { - Region::LateBound(debruijn, id, origin) => { - Region::LateBound(debruijn.shifted_in(amount), id, origin) - } - Region::LateBoundAnon(debruijn, index) => { - Region::LateBoundAnon(debruijn.shifted_in(amount), index) - } - _ => self, - } - } - - fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region { - match self { - Region::LateBound(debruijn, id, origin) => { - Region::LateBound(debruijn.shifted_out_to_binder(binder), id, origin) - } - Region::LateBoundAnon(debruijn, index) => { - Region::LateBoundAnon(debruijn.shifted_out_to_binder(binder), index) - } - _ => self, - } - } - - fn subst<'a, L>(self, mut params: L, map: &NamedRegionMap) -> Option - where - L: Iterator, - { - if let Region::EarlyBound(index, _, _) = self { - params.nth(index as usize).and_then(|lifetime| map.defs.get(&lifetime.hir_id).cloned()) - } else { - Some(self) - } - } -} - /// A set containing, at most, one known element. /// If two distinct values are inserted into a set, then it /// becomes `Many`, which can be used to detect ambiguities. @@ -170,2762 +68,19 @@ pub type ObjectLifetimeDefault = Set1; /// Maps the id of each lifetime reference to the lifetime decl /// that it corresponds to. -/// -/// FIXME. This struct gets converted to a `ResolveLifetimes` for -/// actual use. It has the same data, but indexed by `DefIndex`. This -/// is silly. -#[derive(Default)] -struct NamedRegionMap { - // maps from every use of a named (not anonymous) lifetime to a - // `Region` describing how that region is bound - pub defs: HirIdMap, - - // the set of lifetime def ids that are late-bound; a region can - // be late-bound if (a) it does NOT appear in a where-clause and - // (b) it DOES appear in the arguments. - pub late_bound: HirIdSet, - - // For each type and trait definition, maps type parameters - // to the trait object lifetime defaults computed from them. - pub object_lifetime_defaults: HirIdMap>, -} - -/// See [`NamedRegionMap`]. #[derive(Default, HashStable)] pub struct ResolveLifetimes { - defs: FxHashMap>, - late_bound: FxHashMap>, - object_lifetime_defaults: + /// Maps from every use of a named (not anonymous) lifetime to a + /// `Region` describing how that region is bound + pub defs: FxHashMap>, + + /// Set of lifetime def ids that are late-bound; a region can + /// be late-bound if (a) it does NOT appear in a where-clause and + /// (b) it DOES appear in the arguments. + pub late_bound: FxHashMap>, + + /// For each type and trait definition, maps type parameters + /// to the trait object lifetime defaults computed from them. + pub object_lifetime_defaults: FxHashMap>>, } - -struct LifetimeContext<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - map: &'a mut NamedRegionMap, - scope: ScopeRef<'a>, - - /// This is slightly complicated. Our representation for poly-trait-refs contains a single - /// binder and thus we only allow a single level of quantification. However, - /// the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>` - /// and `for <'a, 'b> &'b T: Foo<'a>`. In order to get the De Bruijn indices - /// correct when representing these constraints, we should only introduce one - /// scope. However, we want to support both locations for the quantifier and - /// during lifetime resolution we want precise information (so we can't - /// desugar in an earlier phase). - /// - /// So, if we encounter a quantifier at the outer scope, we set - /// `trait_ref_hack` to `true` (and introduce a scope), and then if we encounter - /// a quantifier at the inner scope, we error. If `trait_ref_hack` is `false`, - /// then we introduce the scope at the inner quantifier. - trait_ref_hack: bool, - - /// Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax. - is_in_fn_syntax: bool, - - /// List of labels in the function/method currently under analysis. - labels_in_fn: Vec, - - /// Cache for cross-crate per-definition object lifetime defaults. - xcrate_object_lifetime_defaults: DefIdMap>, - - lifetime_uses: &'a mut DefIdMap>, -} - -#[derive(Debug)] -enum Scope<'a> { - /// Declares lifetimes, and each can be early-bound or late-bound. - /// The `DebruijnIndex` of late-bound lifetimes starts at `1` and - /// it should be shifted by the number of `Binder`s in between the - /// declaration `Binder` and the location it's referenced from. - Binder { - lifetimes: FxHashMap, - - /// if we extend this scope with another scope, what is the next index - /// we should use for an early-bound region? - next_early_index: u32, - - /// Flag is set to true if, in this binder, `'_` would be - /// equivalent to a "single-use region". This is true on - /// impls, but not other kinds of items. - track_lifetime_uses: bool, - - /// Whether or not this binder would serve as the parent - /// binder for opaque types introduced within. For example: - /// - /// fn foo<'a>() -> impl for<'b> Trait> - /// - /// Here, the opaque 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 opaque type. - opaque_type_parent: bool, - - s: ScopeRef<'a>, - }, - - /// Lifetimes introduced by a fn are scoped to the call-site for that fn, - /// if this is a fn body, otherwise the original definitions are used. - /// Unspecified lifetimes are inferred, unless an elision scope is nested, - /// e.g., `(&T, fn(&T) -> &T);` becomes `(&'_ T, for<'a> fn(&'a T) -> &'a T)`. - Body { - id: hir::BodyId, - s: ScopeRef<'a>, - }, - - /// A scope which either determines unspecified lifetimes or errors - /// on them (e.g., due to ambiguity). For more details, see `Elide`. - Elision { - elide: Elide, - s: ScopeRef<'a>, - }, - - /// Use a specific lifetime (if `Some`) or leave it unset (to be - /// inferred in a function body or potentially error outside one), - /// for the default choice of lifetime in a trait object type. - ObjectLifetimeDefault { - lifetime: Option, - s: ScopeRef<'a>, - }, - - Root, -} - -#[derive(Clone, Debug)] -enum Elide { - /// Use a fresh anonymous late-bound lifetime each time, by - /// incrementing the counter to generate sequential indices. - FreshLateAnon(Cell), - /// Always use this one lifetime. - Exact(Region), - /// Less or more than one lifetime were found, error on unspecified. - Error(Vec), -} - -#[derive(Clone, Debug)] -struct ElisionFailureInfo { - /// Where we can find the argument pattern. - parent: Option, - /// The index of the argument in the original definition. - index: usize, - lifetime_count: usize, - have_bound_regions: bool, -} - -type ScopeRef<'a> = &'a Scope<'a>; - -const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root; - -pub fn provide(providers: &mut ty::query::Providers<'_>) { - *providers = ty::query::Providers { - resolve_lifetimes, - - named_region_map: |tcx, id| { - let id = LocalDefId::from_def_id(DefId::local(id)); // (*) - tcx.resolve_lifetimes(LOCAL_CRATE).defs.get(&id) - }, - - is_late_bound_map: |tcx, id| { - let id = LocalDefId::from_def_id(DefId::local(id)); // (*) - tcx.resolve_lifetimes(LOCAL_CRATE).late_bound.get(&id) - }, - - object_lifetime_defaults_map: |tcx, id| { - let id = LocalDefId::from_def_id(DefId::local(id)); // (*) - tcx.resolve_lifetimes(LOCAL_CRATE).object_lifetime_defaults.get(&id) - }, - - ..*providers - }; - - // (*) FIXME the query should be defined to take a LocalDefId -} - -/// Computes the `ResolveLifetimes` map that contains data for the -/// entire crate. You should not read the result of this query -/// directly, but rather use `named_region_map`, `is_late_bound_map`, -/// etc. -fn resolve_lifetimes(tcx: TyCtxt<'_>, for_krate: CrateNum) -> &ResolveLifetimes { - assert_eq!(for_krate, LOCAL_CRATE); - - let named_region_map = krate(tcx); - - let mut rl = ResolveLifetimes::default(); - - for (hir_id, v) in named_region_map.defs { - let map = rl.defs.entry(hir_id.owner_local_def_id()).or_default(); - map.insert(hir_id.local_id, v); - } - for hir_id in named_region_map.late_bound { - let map = rl.late_bound.entry(hir_id.owner_local_def_id()).or_default(); - map.insert(hir_id.local_id); - } - for (hir_id, v) in named_region_map.object_lifetime_defaults { - let map = rl.object_lifetime_defaults.entry(hir_id.owner_local_def_id()).or_default(); - map.insert(hir_id.local_id, v); - } - - tcx.arena.alloc(rl) -} - -fn krate(tcx: TyCtxt<'_>) -> NamedRegionMap { - let krate = tcx.hir().krate(); - let mut map = NamedRegionMap { - defs: Default::default(), - late_bound: Default::default(), - object_lifetime_defaults: compute_object_lifetime_defaults(tcx), - }; - { - let mut visitor = LifetimeContext { - tcx, - map: &mut map, - scope: ROOT_SCOPE, - trait_ref_hack: false, - is_in_fn_syntax: false, - labels_in_fn: vec![], - xcrate_object_lifetime_defaults: Default::default(), - lifetime_uses: &mut Default::default(), - }; - for (_, item) in &krate.items { - visitor.visit_item(item); - } - } - map -} - -/// In traits, there is an implicit `Self` type parameter which comes before the generics. -/// We have to account for this when computing the index of the other generic parameters. -/// This function returns whether there is such an implicit parameter defined on the given item. -fn sub_items_have_self_param(node: &hir::ItemKind<'_>) -> bool { - match *node { - hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => true, - _ => false, - } -} - -impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::All(&self.tcx.hir()) - } - - // We want to nest trait/impl items in their parent, but nothing else. - fn visit_nested_item(&mut self, _: hir::ItemId) {} - - fn visit_nested_body(&mut self, body: hir::BodyId) { - // Each body has their own set of labels, save labels. - let saved = take(&mut self.labels_in_fn); - let body = self.tcx.hir().body(body); - extract_labels(self, body); - self.with(Scope::Body { id: body.id(), s: self.scope }, |_, this| { - this.visit_body(body); - }); - replace(&mut self.labels_in_fn, saved); - } - - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - match item.kind { - hir::ItemKind::Fn(ref sig, ref generics, _) => { - self.visit_early_late(None, &sig.decl, generics, |this| { - intravisit::walk_item(this, item); - }); - } - - hir::ItemKind::ExternCrate(_) - | hir::ItemKind::Use(..) - | hir::ItemKind::Mod(..) - | hir::ItemKind::ForeignMod(..) - | hir::ItemKind::GlobalAsm(..) => { - // These sorts of items have no lifetime parameters at all. - intravisit::walk_item(self, item); - } - hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => { - // No lifetime parameters, but implied 'static. - let scope = Scope::Elision { elide: Elide::Exact(Region::Static), s: ROOT_SCOPE }; - self.with(scope, |_, this| intravisit::walk_item(this, item)); - } - hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(_), .. }) => { - // Currently opaque type declarations are just generated from `impl Trait` - // items. Doing anything on this node is irrelevant, as we currently don't need - // it. - } - hir::ItemKind::TyAlias(_, ref generics) - | hir::ItemKind::OpaqueTy(hir::OpaqueTy { - impl_trait_fn: None, ref generics, .. - }) - | hir::ItemKind::Enum(_, ref generics) - | hir::ItemKind::Struct(_, ref generics) - | hir::ItemKind::Union(_, ref generics) - | hir::ItemKind::Trait(_, _, ref generics, ..) - | hir::ItemKind::TraitAlias(ref generics, ..) - | hir::ItemKind::Impl(_, _, _, ref generics, ..) => { - // Impls permit `'_` to be used and it is equivalent to "some fresh lifetime name". - // This is not true for other kinds of items.x - let track_lifetime_uses = match item.kind { - hir::ItemKind::Impl(..) => true, - _ => false, - }; - // These kinds of items have only early-bound lifetime parameters. - let mut index = if sub_items_have_self_param(&item.kind) { - 1 // Self comes before lifetimes - } else { - 0 - }; - let mut non_lifetime_count = 0; - let lifetimes = generics - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some(Region::early(&self.tcx.hir(), &mut index, param)) - } - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - non_lifetime_count += 1; - None - } - }) - .collect(); - let scope = Scope::Binder { - lifetimes, - next_early_index: index + non_lifetime_count, - opaque_type_parent: true, - track_lifetime_uses, - s: ROOT_SCOPE, - }; - self.with(scope, |old_scope, this| { - this.check_lifetime_params(old_scope, &generics.params); - intravisit::walk_item(this, item); - }); - } - } - } - - fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { - match item.kind { - hir::ForeignItemKind::Fn(ref decl, _, ref generics) => { - self.visit_early_late(None, decl, generics, |this| { - intravisit::walk_foreign_item(this, item); - }) - } - hir::ForeignItemKind::Static(..) => { - intravisit::walk_foreign_item(self, item); - } - hir::ForeignItemKind::Type => { - intravisit::walk_foreign_item(self, item); - } - } - } - - fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { - debug!("visit_ty: id={:?} ty={:?}", ty.hir_id, ty); - debug!("visit_ty: ty.kind={:?}", ty.kind); - match ty.kind { - hir::TyKind::BareFn(ref c) => { - let next_early_index = self.next_early_index(); - let was_in_fn_syntax = self.is_in_fn_syntax; - self.is_in_fn_syntax = true; - let scope = Scope::Binder { - lifetimes: c - .generic_params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some(Region::late(&self.tcx.hir(), param)) - } - _ => None, - }) - .collect(), - s: self.scope, - next_early_index, - track_lifetime_uses: true, - opaque_type_parent: false, - }; - self.with(scope, |old_scope, this| { - // a bare fn has no bounds, so everything - // contained within is scoped within its binder. - this.check_lifetime_params(old_scope, &c.generic_params); - intravisit::walk_ty(this, ty); - }); - self.is_in_fn_syntax = was_in_fn_syntax; - } - hir::TyKind::TraitObject(bounds, ref lifetime) => { - debug!("visit_ty: TraitObject(bounds={:?}, lifetime={:?})", bounds, lifetime); - for bound in bounds { - self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); - } - match lifetime.name { - LifetimeName::Implicit => { - // For types like `dyn Foo`, we should - // generate a special form of elided. - span_bug!(ty.span, "object-lifetime-default expected, not implict",); - } - LifetimeName::ImplicitObjectLifetimeDefault => { - // If the user does not write *anything*, we - // use the object lifetime defaulting - // rules. So e.g., `Box` becomes - // `Box`. - self.resolve_object_lifetime_default(lifetime) - } - LifetimeName::Underscore => { - // If the user writes `'_`, we use the *ordinary* elision - // rules. So the `'_` in e.g., `Box` will be - // resolved the same as the `'_` in `&'_ Foo`. - // - // cc #48468 - self.resolve_elided_lifetimes(vec![lifetime]) - } - LifetimeName::Param(_) | LifetimeName::Static => { - // If the user wrote an explicit name, use that. - self.visit_lifetime(lifetime); - } - LifetimeName::Error => {} - } - } - hir::TyKind::Rptr(ref lifetime_ref, ref mt) => { - self.visit_lifetime(lifetime_ref); - let scope = Scope::ObjectLifetimeDefault { - lifetime: self.map.defs.get(&lifetime_ref.hir_id).cloned(), - s: self.scope, - }; - self.with(scope, |_, this| this.visit_ty(&mt.ty)); - } - hir::TyKind::Def(item_id, lifetimes) => { - // Resolve the lifetimes in the bounds to the lifetime defs in the generics. - // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to - // `type MyAnonTy<'b> = impl MyTrait<'b>;` - // ^ ^ this gets resolved in the scope of - // the opaque_ty generics - let (generics, bounds) = match self.tcx.hir().expect_item(item_id.id).kind { - // Named opaque `impl Trait` types are reached via `TyKind::Path`. - // This arm is for `impl Trait` in the types of statics, constants and locals. - hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: None, .. }) => { - intravisit::walk_ty(self, ty); - return; - } - // RPIT (return position impl trait) - hir::ItemKind::OpaqueTy(hir::OpaqueTy { ref generics, bounds, .. }) => { - (generics, bounds) - } - ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), - }; - - // Resolve the lifetimes that are applied to the opaque type. - // These are resolved in the current scope. - // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to - // `fn foo<'a>() -> MyAnonTy<'a> { ... }` - // ^ ^this gets resolved in the current scope - for lifetime in lifetimes { - if let hir::GenericArg::Lifetime(lifetime) = lifetime { - self.visit_lifetime(lifetime); - - // Check for predicates like `impl for<'a> Trait>` - // and ban them. Type variables instantiated inside binders aren't - // well-supported at the moment, so this doesn't work. - // In the future, this should be fixed and this error should be removed. - let def = self.map.defs.get(&lifetime.hir_id).cloned(); - if let Some(Region::LateBound(_, def_id, _)) = def { - if let Some(hir_id) = self.tcx.hir().as_local_hir_id(def_id) { - // Ensure that the parent of the def is an item, not HRTB - let parent_id = self.tcx.hir().get_parent_node(hir_id); - let parent_impl_id = hir::ImplItemId { hir_id: parent_id }; - let parent_trait_id = hir::TraitItemId { hir_id: parent_id }; - let krate = self.tcx.hir().forest.krate(); - - if !(krate.items.contains_key(&parent_id) - || krate.impl_items.contains_key(&parent_impl_id) - || krate.trait_items.contains_key(&parent_trait_id)) - { - span_err!( - self.tcx.sess, - lifetime.span, - E0657, - "`impl Trait` can only capture lifetimes \ - bound at the fn or impl level" - ); - self.uninsert_lifetime_on_error(lifetime, def.unwrap()); - } - } - } - } - } - - // 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_opaque_type(); - debug!("visit_ty: index = {}", index); - - let mut elision = None; - let mut lifetimes = FxHashMap::default(); - let mut non_lifetime_count = 0; - for param in generics.params { - match param.kind { - GenericParamKind::Lifetime { .. } => { - let (name, reg) = Region::early(&self.tcx.hir(), &mut index, ¶m); - let def_id = if let Region::EarlyBound(_, def_id, _) = reg { - def_id - } else { - bug!(); - }; - if let hir::ParamName::Plain(param_name) = name { - if param_name.name == kw::UnderscoreLifetime { - // Pick the elided lifetime "definition" if one exists - // and use it to make an elision scope. - self.lifetime_uses.insert(def_id.clone(), LifetimeUseSet::Many); - elision = Some(reg); - } else { - lifetimes.insert(name, reg); - } - } else { - self.lifetime_uses.insert(def_id.clone(), LifetimeUseSet::Many); - lifetimes.insert(name, reg); - } - } - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - non_lifetime_count += 1; - } - } - } - let next_early_index = index + non_lifetime_count; - - if let Some(elision_region) = elision { - let scope = - Scope::Elision { elide: Elide::Exact(elision_region), s: self.scope }; - self.with(scope, |_old_scope, this| { - let scope = Scope::Binder { - lifetimes, - next_early_index, - s: this.scope, - track_lifetime_uses: true, - opaque_type_parent: false, - }; - this.with(scope, |_old_scope, this| { - this.visit_generics(generics); - for bound in bounds { - this.visit_param_bound(bound); - } - }); - }); - } else { - let scope = Scope::Binder { - lifetimes, - next_early_index, - s: self.scope, - track_lifetime_uses: true, - opaque_type_parent: false, - }; - self.with(scope, |_old_scope, this| { - this.visit_generics(generics); - for bound in bounds { - this.visit_param_bound(bound); - } - }); - } - } - _ => intravisit::walk_ty(self, ty), - } - } - - fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { - use self::hir::TraitItemKind::*; - match trait_item.kind { - Method(ref sig, _) => { - let tcx = self.tcx; - self.visit_early_late( - Some(tcx.hir().get_parent_item(trait_item.hir_id)), - &sig.decl, - &trait_item.generics, - |this| intravisit::walk_trait_item(this, trait_item), - ); - } - Type(bounds, ref ty) => { - let generics = &trait_item.generics; - let mut index = self.next_early_index(); - debug!("visit_ty: index = {}", index); - let mut non_lifetime_count = 0; - let lifetimes = generics - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some(Region::early(&self.tcx.hir(), &mut index, param)) - } - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - non_lifetime_count += 1; - None - } - }) - .collect(); - let scope = Scope::Binder { - lifetimes, - next_early_index: index + non_lifetime_count, - s: self.scope, - track_lifetime_uses: true, - opaque_type_parent: true, - }; - self.with(scope, |_old_scope, this| { - this.visit_generics(generics); - for bound in bounds { - this.visit_param_bound(bound); - } - if let Some(ty) = ty { - 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); - } - } - } - - fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { - use self::hir::ImplItemKind::*; - match impl_item.kind { - Method(ref sig, _) => { - let tcx = self.tcx; - self.visit_early_late( - Some(tcx.hir().get_parent_item(impl_item.hir_id)), - &sig.decl, - &impl_item.generics, - |this| intravisit::walk_impl_item(this, impl_item), - ) - } - TyAlias(ref ty) => { - let generics = &impl_item.generics; - let mut index = self.next_early_index(); - let mut non_lifetime_count = 0; - debug!("visit_ty: index = {}", index); - let lifetimes = generics - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some(Region::early(&self.tcx.hir(), &mut index, param)) - } - GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => { - non_lifetime_count += 1; - None - } - }) - .collect(); - let scope = Scope::Binder { - lifetimes, - next_early_index: index + non_lifetime_count, - s: self.scope, - track_lifetime_uses: true, - opaque_type_parent: true, - }; - self.with(scope, |_old_scope, this| { - this.visit_generics(generics); - this.visit_ty(ty); - }); - } - OpaqueTy(bounds) => { - let generics = &impl_item.generics; - let mut index = self.next_early_index(); - let mut next_early_index = index; - debug!("visit_ty: index = {}", index); - let lifetimes = generics - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some(Region::early(&self.tcx.hir(), &mut index, param)) - } - GenericParamKind::Type { .. } => { - next_early_index += 1; - None - } - GenericParamKind::Const { .. } => { - next_early_index += 1; - None - } - }) - .collect(); - - let scope = Scope::Binder { - lifetimes, - next_early_index, - s: self.scope, - track_lifetime_uses: true, - opaque_type_parent: true, - }; - self.with(scope, |_old_scope, this| { - this.visit_generics(generics); - for bound in bounds { - this.visit_param_bound(bound); - } - }); - } - Const(_, _) => { - // Only methods and types support generics. - assert!(impl_item.generics.params.is_empty()); - intravisit::walk_impl_item(self, impl_item); - } - } - } - - fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { - debug!("visit_lifetime(lifetime_ref={:?})", lifetime_ref); - if lifetime_ref.is_elided() { - self.resolve_elided_lifetimes(vec![lifetime_ref]); - return; - } - if lifetime_ref.is_static() { - self.insert_lifetime(lifetime_ref, Region::Static); - return; - } - self.resolve_lifetime_ref(lifetime_ref); - } - - fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) { - for (i, segment) in path.segments.iter().enumerate() { - let depth = path.segments.len() - i - 1; - if let Some(ref args) = segment.args { - self.visit_segment_args(path.res, depth, args); - } - } - } - - fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) { - let output = match fd.output { - hir::DefaultReturn(_) => None, - hir::Return(ref ty) => Some(&**ty), - }; - self.visit_fn_like_elision(&fd.inputs, output); - } - - fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) { - check_mixed_explicit_and_in_band_defs(self.tcx, &generics.params); - for param in generics.params { - match param.kind { - GenericParamKind::Lifetime { .. } => {} - GenericParamKind::Type { ref default, .. } => { - walk_list!(self, visit_param_bound, param.bounds); - if let Some(ref ty) = default { - self.visit_ty(&ty); - } - } - GenericParamKind::Const { ref ty, .. } => { - walk_list!(self, visit_param_bound, param.bounds); - self.visit_ty(&ty); - } - } - } - for predicate in generics.where_clause.predicates { - match predicate { - &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { - ref bounded_ty, - bounds, - ref bound_generic_params, - .. - }) => { - let lifetimes: FxHashMap<_, _> = bound_generic_params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some(Region::late(&self.tcx.hir(), param)) - } - _ => None, - }) - .collect(); - if !lifetimes.is_empty() { - self.trait_ref_hack = true; - let next_early_index = self.next_early_index(); - let scope = Scope::Binder { - lifetimes, - s: self.scope, - next_early_index, - track_lifetime_uses: true, - opaque_type_parent: false, - }; - let result = self.with(scope, |old_scope, this| { - this.check_lifetime_params(old_scope, &bound_generic_params); - this.visit_ty(&bounded_ty); - walk_list!(this, visit_param_bound, bounds); - }); - self.trait_ref_hack = false; - result - } else { - self.visit_ty(&bounded_ty); - walk_list!(self, visit_param_bound, bounds); - } - } - &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { - ref lifetime, - bounds, - .. - }) => { - self.visit_lifetime(lifetime); - walk_list!(self, visit_param_bound, bounds); - } - &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { - ref lhs_ty, - ref rhs_ty, - .. - }) => { - self.visit_ty(lhs_ty); - self.visit_ty(rhs_ty); - } - } - } - } - - fn visit_poly_trait_ref( - &mut self, - trait_ref: &'tcx hir::PolyTraitRef<'tcx>, - _modifier: hir::TraitBoundModifier, - ) { - debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref); - - if !self.trait_ref_hack - || trait_ref.bound_generic_params.iter().any(|param| match param.kind { - GenericParamKind::Lifetime { .. } => true, - _ => false, - }) - { - if self.trait_ref_hack { - span_err!( - self.tcx.sess, - trait_ref.span, - E0316, - "nested quantification of lifetimes" - ); - } - let next_early_index = self.next_early_index(); - let scope = Scope::Binder { - lifetimes: trait_ref - .bound_generic_params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some(Region::late(&self.tcx.hir(), param)) - } - _ => None, - }) - .collect(), - s: self.scope, - next_early_index, - track_lifetime_uses: true, - opaque_type_parent: false, - }; - self.with(scope, |old_scope, this| { - this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params); - walk_list!(this, visit_generic_param, trait_ref.bound_generic_params); - this.visit_trait_ref(&trait_ref.trait_ref) - }) - } else { - self.visit_trait_ref(&trait_ref.trait_ref) - } - } -} - -#[derive(Copy, Clone, PartialEq)] -enum ShadowKind { - Label, - Lifetime, -} -struct Original { - kind: ShadowKind, - span: Span, -} -struct Shadower { - kind: ShadowKind, - span: Span, -} - -fn original_label(span: Span) -> Original { - Original { kind: ShadowKind::Label, span: span } -} -fn shadower_label(span: Span) -> Shadower { - Shadower { kind: ShadowKind::Label, span: span } -} -fn original_lifetime(span: Span) -> Original { - Original { kind: ShadowKind::Lifetime, span: span } -} -fn shadower_lifetime(param: &hir::GenericParam<'_>) -> Shadower { - Shadower { kind: ShadowKind::Lifetime, span: param.span } -} - -impl ShadowKind { - fn desc(&self) -> &'static str { - match *self { - ShadowKind::Label => "label", - ShadowKind::Lifetime => "lifetime", - } - } -} - -fn check_mixed_explicit_and_in_band_defs(tcx: TyCtxt<'_>, params: &[hir::GenericParam<'_>]) { - let lifetime_params: Vec<_> = params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { kind, .. } => Some((kind, param.span)), - _ => None, - }) - .collect(); - let explicit = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::Explicit); - let in_band = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::InBand); - - if let (Some((_, explicit_span)), Some((_, in_band_span))) = (explicit, in_band) { - struct_span_err!( - tcx.sess, - *in_band_span, - E0688, - "cannot mix in-band and explicit lifetime definitions" - ) - .span_label(*in_band_span, "in-band lifetime definition here") - .span_label(*explicit_span, "explicit lifetime definition here") - .emit(); - } -} - -fn signal_shadowing_problem(tcx: TyCtxt<'_>, name: ast::Name, orig: Original, shadower: Shadower) { - let mut err = if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) { - // lifetime/lifetime shadowing is an error - struct_span_err!( - tcx.sess, - shadower.span, - E0496, - "{} name `{}` shadows a \ - {} name that is already in scope", - shadower.kind.desc(), - name, - orig.kind.desc() - ) - } else { - // shadowing involving a label is only a warning, due to issues with - // labels and lifetimes not being macro-hygienic. - tcx.sess.struct_span_warn( - shadower.span, - &format!( - "{} name `{}` shadows a \ - {} name that is already in scope", - shadower.kind.desc(), - name, - orig.kind.desc() - ), - ) - }; - err.span_label(orig.span, "first declared here"); - err.span_label(shadower.span, format!("lifetime {} already in scope", name)); - err.emit(); -} - -// Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning -// if one of the label shadows a lifetime or another label. -fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body<'_>) { - struct GatherLabels<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - scope: ScopeRef<'a>, - labels_in_fn: &'a mut Vec, - } - - let mut gather = - GatherLabels { tcx: ctxt.tcx, scope: ctxt.scope, labels_in_fn: &mut ctxt.labels_in_fn }; - gather.visit_body(body); - - impl<'v, 'a, 'tcx> Visitor<'v> for GatherLabels<'a, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> { - NestedVisitorMap::None - } - - fn visit_expr(&mut self, ex: &hir::Expr<'_>) { - if let Some(label) = expression_label(ex) { - for prior_label in &self.labels_in_fn[..] { - // FIXME (#24278): non-hygienic comparison - if label.name == prior_label.name { - signal_shadowing_problem( - self.tcx, - label.name, - original_label(prior_label.span), - shadower_label(label.span), - ); - } - } - - check_if_label_shadows_lifetime(self.tcx, self.scope, label); - - self.labels_in_fn.push(label); - } - intravisit::walk_expr(self, ex) - } - } - - fn expression_label(ex: &hir::Expr<'_>) -> Option { - if let hir::ExprKind::Loop(_, Some(label), _) = ex.kind { Some(label.ident) } else { None } - } - - fn check_if_label_shadows_lifetime( - tcx: TyCtxt<'_>, - mut scope: ScopeRef<'_>, - label: ast::Ident, - ) { - loop { - match *scope { - Scope::Body { s, .. } - | Scope::Elision { s, .. } - | Scope::ObjectLifetimeDefault { s, .. } => { - scope = s; - } - - Scope::Root => { - return; - } - - Scope::Binder { ref lifetimes, s, .. } => { - // FIXME (#24278): non-hygienic comparison - if let Some(def) = lifetimes.get(&hir::ParamName::Plain(label.modern())) { - let hir_id = tcx.hir().as_local_hir_id(def.id().unwrap()).unwrap(); - - signal_shadowing_problem( - tcx, - label.name, - original_lifetime(tcx.hir().span(hir_id)), - shadower_label(label.span), - ); - return; - } - scope = s; - } - } - } - } -} - -fn compute_object_lifetime_defaults(tcx: TyCtxt<'_>) -> HirIdMap> { - let mut map = HirIdMap::default(); - for item in tcx.hir().krate().items.values() { - match item.kind { - hir::ItemKind::Struct(_, ref generics) - | hir::ItemKind::Union(_, ref generics) - | hir::ItemKind::Enum(_, ref generics) - | hir::ItemKind::OpaqueTy(hir::OpaqueTy { - ref generics, impl_trait_fn: None, .. - }) - | hir::ItemKind::TyAlias(_, ref generics) - | hir::ItemKind::Trait(_, _, ref generics, ..) => { - let result = object_lifetime_defaults_for_item(tcx, generics); - - // Debugging aid. - if attr::contains_name(&item.attrs, sym::rustc_object_lifetime_default) { - let object_lifetime_default_reprs: String = result - .iter() - .map(|set| match *set { - Set1::Empty => "BaseDefault".into(), - Set1::One(Region::Static) => "'static".into(), - Set1::One(Region::EarlyBound(mut i, _, _)) => generics - .params - .iter() - .find_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - if i == 0 { - return Some(param.name.ident().to_string().into()); - } - i -= 1; - None - } - _ => None, - }) - .unwrap(), - Set1::One(_) => bug!(), - Set1::Many => "Ambiguous".into(), - }) - .collect::>>() - .join(","); - tcx.sess.span_err(item.span, &object_lifetime_default_reprs); - } - - map.insert(item.hir_id, result); - } - _ => {} - } - } - map -} - -/// Scan the bounds and where-clauses on parameters to extract bounds -/// of the form `T:'a` so as to determine the `ObjectLifetimeDefault` -/// for each type parameter. -fn object_lifetime_defaults_for_item( - tcx: TyCtxt<'_>, - generics: &hir::Generics<'_>, -) -> Vec { - fn add_bounds(set: &mut Set1, bounds: &[hir::GenericBound<'_>]) { - for bound in bounds { - if let hir::GenericBound::Outlives(ref lifetime) = *bound { - set.insert(lifetime.name.modern()); - } - } - } - - generics - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => None, - GenericParamKind::Type { .. } => { - let mut set = Set1::Empty; - - add_bounds(&mut set, ¶m.bounds); - - let param_def_id = tcx.hir().local_def_id(param.hir_id); - for predicate in generics.where_clause.predicates { - // Look for `type: ...` where clauses. - let data = match *predicate { - hir::WherePredicate::BoundPredicate(ref data) => data, - _ => continue, - }; - - // Ignore `for<'a> type: ...` as they can change what - // lifetimes mean (although we could "just" handle it). - if !data.bound_generic_params.is_empty() { - continue; - } - - let res = match data.bounded_ty.kind { - hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => path.res, - _ => continue, - }; - - if res == Res::Def(DefKind::TyParam, param_def_id) { - add_bounds(&mut set, &data.bounds); - } - } - - Some(match set { - Set1::Empty => Set1::Empty, - Set1::One(name) => { - if name == hir::LifetimeName::Static { - Set1::One(Region::Static) - } else { - generics - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => Some(( - param.hir_id, - hir::LifetimeName::Param(param.name), - LifetimeDefOrigin::from_param(param), - )), - _ => None, - }) - .enumerate() - .find(|&(_, (_, lt_name, _))| lt_name == name) - .map_or(Set1::Many, |(i, (id, _, origin))| { - let def_id = tcx.hir().local_def_id(id); - Set1::One(Region::EarlyBound(i as u32, def_id, origin)) - }) - } - } - Set1::Many => Set1::Many, - }) - } - GenericParamKind::Const { .. } => { - // Generic consts don't impose any constraints. - None - } - }) - .collect() -} - -impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { - // FIXME(#37666) this works around a limitation in the region inferencer - fn hack(&mut self, f: F) - where - F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>), - { - f(self) - } - - fn with(&mut self, wrap_scope: Scope<'_>, f: F) - where - F: for<'b> FnOnce(ScopeRef<'_>, &mut LifetimeContext<'b, 'tcx>), - { - let LifetimeContext { tcx, map, lifetime_uses, .. } = self; - let labels_in_fn = take(&mut self.labels_in_fn); - let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults); - let mut this = LifetimeContext { - tcx: *tcx, - map: map, - scope: &wrap_scope, - trait_ref_hack: self.trait_ref_hack, - is_in_fn_syntax: self.is_in_fn_syntax, - labels_in_fn, - xcrate_object_lifetime_defaults, - lifetime_uses: lifetime_uses, - }; - debug!("entering scope {:?}", this.scope); - f(self.scope, &mut this); - this.check_uses_for_lifetimes_defined_by_scope(); - debug!("exiting scope {:?}", this.scope); - self.labels_in_fn = this.labels_in_fn; - self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults; - } - - /// helper method to determine the span to remove when suggesting the - /// deletion of a lifetime - fn lifetime_deletion_span( - &self, - name: ast::Ident, - generics: &hir::Generics<'_>, - ) -> Option { - generics.params.iter().enumerate().find_map(|(i, param)| { - if param.name.ident() == name { - let mut in_band = false; - if let hir::GenericParamKind::Lifetime { kind } = param.kind { - if let hir::LifetimeParamKind::InBand = kind { - in_band = true; - } - } - if in_band { - Some(param.span) - } else { - if generics.params.len() == 1 { - // if sole lifetime, remove the entire `<>` brackets - Some(generics.span) - } else { - // if removing within `<>` brackets, we also want to - // delete a leading or trailing comma as appropriate - if i >= generics.params.len() - 1 { - Some(generics.params[i - 1].span.shrink_to_hi().to(param.span)) - } else { - Some(param.span.to(generics.params[i + 1].span.shrink_to_lo())) - } - } - } - } else { - None - } - }) - } - - // helper method to issue suggestions from `fn rah<'a>(&'a T)` to `fn rah(&T)` - // or from `fn rah<'a>(T<'a>)` to `fn rah(T<'_>)` - fn suggest_eliding_single_use_lifetime( - &self, - err: &mut DiagnosticBuilder<'_>, - def_id: DefId, - lifetime: &hir::Lifetime, - ) { - let name = lifetime.name.ident(); - let mut remove_decl = None; - if let Some(parent_def_id) = self.tcx.parent(def_id) { - if let Some(generics) = self.tcx.hir().get_generics(parent_def_id) { - remove_decl = self.lifetime_deletion_span(name, generics); - } - } - - let mut remove_use = None; - let mut elide_use = None; - let mut find_arg_use_span = |inputs: &[hir::Ty<'_>]| { - for input in inputs { - match input.kind { - hir::TyKind::Rptr(lt, _) => { - if lt.name.ident() == name { - // include the trailing whitespace between the lifetime and type names - let lt_through_ty_span = lifetime.span.to(input.span.shrink_to_hi()); - remove_use = Some( - self.tcx - .sess - .source_map() - .span_until_non_whitespace(lt_through_ty_span), - ); - break; - } - } - hir::TyKind::Path(ref qpath) => { - if let QPath::Resolved(_, path) = qpath { - let last_segment = &path.segments[path.segments.len() - 1]; - let generics = last_segment.generic_args(); - for arg in generics.args.iter() { - if let GenericArg::Lifetime(lt) = arg { - if lt.name.ident() == name { - elide_use = Some(lt.span); - break; - } - } - } - break; - } - } - _ => {} - } - } - }; - if let Node::Lifetime(hir_lifetime) = self.tcx.hir().get(lifetime.hir_id) { - if let Some(parent) = - self.tcx.hir().find(self.tcx.hir().get_parent_item(hir_lifetime.hir_id)) - { - match parent { - Node::Item(item) => { - if let hir::ItemKind::Fn(sig, _, _) = &item.kind { - find_arg_use_span(sig.decl.inputs); - } - } - Node::ImplItem(impl_item) => { - if let hir::ImplItemKind::Method(sig, _) = &impl_item.kind { - find_arg_use_span(sig.decl.inputs); - } - } - _ => {} - } - } - } - - let msg = "elide the single-use lifetime"; - match (remove_decl, remove_use, elide_use) { - (Some(decl_span), Some(use_span), None) => { - // if both declaration and use deletion spans start at the same - // place ("start at" because the latter includes trailing - // whitespace), then this is an in-band lifetime - if decl_span.shrink_to_lo() == use_span.shrink_to_lo() { - err.span_suggestion( - use_span, - msg, - String::new(), - Applicability::MachineApplicable, - ); - } else { - err.multipart_suggestion( - msg, - vec![(decl_span, String::new()), (use_span, String::new())], - Applicability::MachineApplicable, - ); - } - } - (Some(decl_span), None, Some(use_span)) => { - err.multipart_suggestion( - msg, - vec![(decl_span, String::new()), (use_span, "'_".to_owned())], - Applicability::MachineApplicable, - ); - } - _ => {} - } - } - - fn check_uses_for_lifetimes_defined_by_scope(&mut self) { - let defined_by = match self.scope { - Scope::Binder { lifetimes, .. } => lifetimes, - _ => { - debug!("check_uses_for_lifetimes_defined_by_scope: not in a binder scope"); - return; - } - }; - - let mut def_ids: Vec<_> = defined_by - .values() - .flat_map(|region| match region { - Region::EarlyBound(_, def_id, _) - | Region::LateBound(_, def_id, _) - | Region::Free(_, def_id) => Some(*def_id), - - Region::LateBoundAnon(..) | Region::Static => None, - }) - .collect(); - - // ensure that we issue lints in a repeatable order - def_ids.sort_by_cached_key(|&def_id| self.tcx.def_path_hash(def_id)); - - for def_id in def_ids { - debug!("check_uses_for_lifetimes_defined_by_scope: def_id = {:?}", def_id); - - let lifetimeuseset = self.lifetime_uses.remove(&def_id); - - debug!( - "check_uses_for_lifetimes_defined_by_scope: lifetimeuseset = {:?}", - lifetimeuseset - ); - - match lifetimeuseset { - Some(LifetimeUseSet::One(lifetime)) => { - let hir_id = self.tcx.hir().as_local_hir_id(def_id).unwrap(); - debug!("hir id first={:?}", hir_id); - if let Some((id, span, name)) = match self.tcx.hir().get(hir_id) { - Node::Lifetime(hir_lifetime) => Some(( - hir_lifetime.hir_id, - hir_lifetime.span, - hir_lifetime.name.ident(), - )), - Node::GenericParam(param) => { - Some((param.hir_id, param.span, param.name.ident())) - } - _ => None, - } { - debug!("id = {:?} span = {:?} name = {:?}", id, span, name); - if name.name == kw::UnderscoreLifetime { - continue; - } - - if let Some(parent_def_id) = self.tcx.parent(def_id) { - if let Some(parent_hir_id) = - self.tcx.hir().as_local_hir_id(parent_def_id) - { - // lifetimes in `derive` expansions don't count (Issue #53738) - if self - .tcx - .hir() - .attrs(parent_hir_id) - .iter() - .any(|attr| attr.check_name(sym::automatically_derived)) - { - continue; - } - } - } - - let mut err = self.tcx.struct_span_lint_hir( - lint::builtin::SINGLE_USE_LIFETIMES, - id, - span, - &format!("lifetime parameter `{}` only used once", name), - ); - - if span == lifetime.span { - // spans are the same for in-band lifetime declarations - err.span_label(span, "this lifetime is only used here"); - } else { - err.span_label(span, "this lifetime..."); - err.span_label(lifetime.span, "...is used only here"); - } - self.suggest_eliding_single_use_lifetime(&mut err, def_id, lifetime); - err.emit(); - } - } - Some(LifetimeUseSet::Many) => { - debug!("not one use lifetime"); - } - None => { - let hir_id = self.tcx.hir().as_local_hir_id(def_id).unwrap(); - if let Some((id, span, name)) = match self.tcx.hir().get(hir_id) { - Node::Lifetime(hir_lifetime) => Some(( - hir_lifetime.hir_id, - hir_lifetime.span, - hir_lifetime.name.ident(), - )), - Node::GenericParam(param) => { - Some((param.hir_id, param.span, param.name.ident())) - } - _ => None, - } { - debug!("id ={:?} span = {:?} name = {:?}", id, span, name); - let mut err = self.tcx.struct_span_lint_hir( - lint::builtin::UNUSED_LIFETIMES, - id, - span, - &format!("lifetime parameter `{}` never used", name), - ); - if let Some(parent_def_id) = self.tcx.parent(def_id) { - if let Some(generics) = self.tcx.hir().get_generics(parent_def_id) { - let unused_lt_span = self.lifetime_deletion_span(name, generics); - if let Some(span) = unused_lt_span { - err.span_suggestion( - span, - "elide the unused lifetime", - String::new(), - Applicability::MachineApplicable, - ); - } - } - } - err.emit(); - } - } - } - } - } - - /// Visits self by adding a scope and handling recursive walk over the contents with `walk`. - /// - /// Handles visiting fns and methods. These are a bit complicated because we must distinguish - /// early- vs late-bound lifetime parameters. We do this by checking which lifetimes appear - /// within type bounds; those are early bound lifetimes, and the rest are late bound. - /// - /// For example: - /// - /// fn foo<'a,'b,'c,T:Trait<'b>>(...) - /// - /// Here `'a` and `'c` are late bound but `'b` is early bound. Note that early- and late-bound - /// lifetimes may be interspersed together. - /// - /// If early bound lifetimes are present, we separate them into their own list (and likewise - /// for late bound). They will be numbered sequentially, starting from the lowest index that is - /// already in scope (for a fn item, that will be 0, but for a method it might not be). Late - /// bound lifetimes are resolved by name and associated with a binder ID (`binder_id`), so the - /// ordering is not important there. - fn visit_early_late( - &mut self, - parent_id: Option, - decl: &'tcx hir::FnDecl<'tcx>, - generics: &'tcx hir::Generics<'tcx>, - walk: F, - ) where - F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>), - { - insert_late_bound_lifetimes(self.map, decl, generics); - - // Find the start of nested early scopes, e.g., in methods. - let mut index = 0; - if let Some(parent_id) = parent_id { - let parent = self.tcx.hir().expect_item(parent_id); - if sub_items_have_self_param(&parent.kind) { - index += 1; // Self comes before lifetimes - } - match parent.kind { - hir::ItemKind::Trait(_, _, ref generics, ..) - | hir::ItemKind::Impl(_, _, _, ref generics, ..) => { - index += generics.params.len() as u32; - } - _ => {} - } - } - - let mut non_lifetime_count = 0; - let lifetimes = generics - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - if self.map.late_bound.contains(¶m.hir_id) { - Some(Region::late(&self.tcx.hir(), param)) - } else { - Some(Region::early(&self.tcx.hir(), &mut index, param)) - } - } - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - non_lifetime_count += 1; - None - } - }) - .collect(); - let next_early_index = index + non_lifetime_count; - - let scope = Scope::Binder { - lifetimes, - next_early_index, - s: self.scope, - opaque_type_parent: true, - track_lifetime_uses: false, - }; - self.with(scope, move |old_scope, this| { - this.check_lifetime_params(old_scope, &generics.params); - this.hack(walk); // FIXME(#37666) workaround in place of `walk(this)` - }); - } - - fn next_early_index_helper(&self, only_opaque_type_parent: bool) -> u32 { - let mut scope = self.scope; - loop { - match *scope { - Scope::Root => return 0, - - Scope::Binder { next_early_index, opaque_type_parent, .. } - if (!only_opaque_type_parent || opaque_type_parent) => - { - return next_early_index; - } - - 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 opaque type alias `impl Trait`. This will be the - /// next early index from the enclosing item, for the most - /// part. See the `opaque_type_parent` field for more info. - fn next_early_index_for_opaque_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); - - // If we've already reported an error, just ignore `lifetime_ref`. - if let LifetimeName::Error = lifetime_ref.name { - return; - } - - // Walk up the scope chain, tracking the number of fn scopes - // that we pass through, until we find a lifetime with the - // given name or we run out of scopes. - // search. - let mut late_depth = 0; - let mut scope = self.scope; - let mut outermost_body = None; - let result = loop { - match *scope { - Scope::Body { id, s } => { - outermost_body = Some(id); - scope = s; - } - - Scope::Root => { - break None; - } - - Scope::Binder { ref lifetimes, s, .. } => { - match lifetime_ref.name { - LifetimeName::Param(param_name) => { - if let Some(&def) = lifetimes.get(¶m_name.modern()) { - break Some(def.shifted(late_depth)); - } - } - _ => bug!("expected LifetimeName::Param"), - } - - late_depth += 1; - scope = s; - } - - Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } => { - scope = s; - } - } - }; - - if let Some(mut def) = result { - if let Region::EarlyBound(..) = def { - // Do not free early-bound regions, only late-bound ones. - } else if let Some(body_id) = outermost_body { - let fn_id = self.tcx.hir().body_owner(body_id); - match self.tcx.hir().get(fn_id) { - Node::Item(&hir::Item { kind: hir::ItemKind::Fn(..), .. }) - | Node::TraitItem(&hir::TraitItem { - kind: hir::TraitItemKind::Method(..), - .. - }) - | Node::ImplItem(&hir::ImplItem { - kind: hir::ImplItemKind::Method(..), .. - }) => { - let scope = self.tcx.hir().local_def_id(fn_id); - def = Region::Free(scope, def.id().unwrap()); - } - _ => {} - } - } - - // Check for fn-syntax conflicts with in-band lifetime definitions - if self.is_in_fn_syntax { - match def { - Region::EarlyBound(_, _, LifetimeDefOrigin::InBand) - | Region::LateBound(_, _, LifetimeDefOrigin::InBand) => { - struct_span_err!( - self.tcx.sess, - lifetime_ref.span, - E0687, - "lifetimes used in `fn` or `Fn` syntax must be \ - explicitly declared using `<...>` binders" - ) - .span_label(lifetime_ref.span, "in-band lifetime definition") - .emit(); - } - - Region::Static - | Region::EarlyBound(_, _, LifetimeDefOrigin::ExplicitOrElided) - | Region::LateBound(_, _, LifetimeDefOrigin::ExplicitOrElided) - | Region::EarlyBound(_, _, LifetimeDefOrigin::Error) - | Region::LateBound(_, _, LifetimeDefOrigin::Error) - | Region::LateBoundAnon(..) - | Region::Free(..) => {} - } - } - - self.insert_lifetime(lifetime_ref, def); - } else { - struct_span_err!( - self.tcx.sess, - lifetime_ref.span, - E0261, - "use of undeclared lifetime name `{}`", - lifetime_ref - ) - .span_label(lifetime_ref.span, "undeclared lifetime") - .emit(); - } - } - - fn visit_segment_args( - &mut self, - res: Res, - depth: usize, - generic_args: &'tcx hir::GenericArgs<'tcx>, - ) { - debug!( - "visit_segment_args(res={:?}, depth={:?}, generic_args={:?})", - res, depth, generic_args, - ); - - if generic_args.parenthesized { - let was_in_fn_syntax = self.is_in_fn_syntax; - self.is_in_fn_syntax = true; - self.visit_fn_like_elision(generic_args.inputs(), Some(generic_args.bindings[0].ty())); - self.is_in_fn_syntax = was_in_fn_syntax; - return; - } - - let mut elide_lifetimes = true; - let lifetimes = generic_args - .args - .iter() - .filter_map(|arg| match arg { - hir::GenericArg::Lifetime(lt) => { - if !lt.is_elided() { - elide_lifetimes = false; - } - Some(lt) - } - _ => None, - }) - .collect(); - if elide_lifetimes { - self.resolve_elided_lifetimes(lifetimes); - } else { - lifetimes.iter().for_each(|lt| self.visit_lifetime(lt)); - } - - // Figure out if this is a type/trait segment, - // which requires object lifetime defaults. - let parent_def_id = |this: &mut Self, def_id: DefId| { - let def_key = this.tcx.def_key(def_id); - DefId { krate: def_id.krate, index: def_key.parent.expect("missing parent") } - }; - let type_def_id = match res { - Res::Def(DefKind::AssocTy, def_id) if depth == 1 => Some(parent_def_id(self, def_id)), - Res::Def(DefKind::Variant, def_id) if depth == 0 => Some(parent_def_id(self, def_id)), - Res::Def(DefKind::Struct, def_id) - | Res::Def(DefKind::Union, def_id) - | Res::Def(DefKind::Enum, def_id) - | Res::Def(DefKind::TyAlias, def_id) - | Res::Def(DefKind::Trait, def_id) - if depth == 0 => - { - Some(def_id) - } - _ => None, - }; - - debug!("visit_segment_args: type_def_id={:?}", type_def_id); - - // Compute a vector of defaults, one for each type parameter, - // per the rules given in RFCs 599 and 1156. Example: - // - // ```rust - // struct Foo<'a, T: 'a, U> { } - // ``` - // - // If you have `Foo<'x, dyn Bar, dyn Baz>`, we want to default - // `dyn Bar` to `dyn Bar + 'x` (because of the `T: 'a` bound) - // and `dyn Baz` to `dyn Baz + 'static` (because there is no - // such bound). - // - // Therefore, we would compute `object_lifetime_defaults` to a - // vector like `['x, 'static]`. Note that the vector only - // includes type parameters. - let object_lifetime_defaults = type_def_id.map_or(vec![], |def_id| { - let in_body = { - let mut scope = self.scope; - loop { - match *scope { - Scope::Root => break false, - - Scope::Body { .. } => break true, - - Scope::Binder { s, .. } - | Scope::Elision { s, .. } - | Scope::ObjectLifetimeDefault { s, .. } => { - scope = s; - } - } - } - }; - - let map = &self.map; - let unsubst = if let Some(id) = self.tcx.hir().as_local_hir_id(def_id) { - &map.object_lifetime_defaults[&id] - } else { - let tcx = self.tcx; - self.xcrate_object_lifetime_defaults.entry(def_id).or_insert_with(|| { - tcx.generics_of(def_id) - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamDefKind::Type { object_lifetime_default, .. } => { - Some(object_lifetime_default) - } - GenericParamDefKind::Lifetime | GenericParamDefKind::Const => None, - }) - .collect() - }) - }; - debug!("visit_segment_args: unsubst={:?}", unsubst); - unsubst - .iter() - .map(|set| match *set { - Set1::Empty => { - if in_body { - None - } else { - Some(Region::Static) - } - } - Set1::One(r) => { - let lifetimes = generic_args.args.iter().filter_map(|arg| match arg { - GenericArg::Lifetime(lt) => Some(lt), - _ => None, - }); - r.subst(lifetimes, map) - } - Set1::Many => None, - }) - .collect() - }); - - debug!("visit_segment_args: object_lifetime_defaults={:?}", object_lifetime_defaults); - - let mut i = 0; - for arg in generic_args.args { - match arg { - GenericArg::Lifetime(_) => {} - GenericArg::Type(ty) => { - if let Some(<) = object_lifetime_defaults.get(i) { - let scope = Scope::ObjectLifetimeDefault { lifetime: lt, s: self.scope }; - self.with(scope, |_, this| this.visit_ty(ty)); - } else { - self.visit_ty(ty); - } - i += 1; - } - GenericArg::Const(ct) => { - self.visit_anon_const(&ct.value); - } - } - } - - // Hack: when resolving the type `XX` in binding like `dyn - // Foo<'b, Item = XX>`, the current object-lifetime default - // would be to examine the trait `Foo` to check whether it has - // a lifetime bound declared on `Item`. e.g., if `Foo` is - // declared like so, then the default object lifetime bound in - // `XX` should be `'b`: - // - // ```rust - // trait Foo<'a> { - // type Item: 'a; - // } - // ``` - // - // but if we just have `type Item;`, then it would be - // `'static`. However, we don't get all of this logic correct. - // - // Instead, we do something hacky: if there are no lifetime parameters - // to the trait, then we simply use a default object lifetime - // bound of `'static`, because there is no other possibility. On the other hand, - // if there ARE lifetime parameters, then we require the user to give an - // explicit bound for now. - // - // This is intended to leave room for us to implement the - // correct behavior in the future. - let has_lifetime_parameter = generic_args.args.iter().any(|arg| match arg { - GenericArg::Lifetime(_) => true, - _ => false, - }); - - // Resolve lifetimes found in the type `XX` from `Item = XX` bindings. - for b in generic_args.bindings { - let scope = Scope::ObjectLifetimeDefault { - lifetime: if has_lifetime_parameter { None } else { Some(Region::Static) }, - s: self.scope, - }; - self.with(scope, |_, this| this.visit_assoc_type_binding(b)); - } - } - - fn visit_fn_like_elision( - &mut self, - inputs: &'tcx [hir::Ty<'tcx>], - output: Option<&'tcx hir::Ty<'tcx>>, - ) { - debug!("visit_fn_like_elision: enter"); - let mut arg_elide = Elide::FreshLateAnon(Cell::new(0)); - let arg_scope = Scope::Elision { elide: arg_elide.clone(), s: self.scope }; - self.with(arg_scope, |_, this| { - for input in inputs { - this.visit_ty(input); - } - match *this.scope { - Scope::Elision { ref elide, .. } => { - arg_elide = elide.clone(); - } - _ => bug!(), - } - }); - - let output = match output { - Some(ty) => ty, - None => return, - }; - - debug!("visit_fn_like_elision: determine output"); - - // Figure out if there's a body we can get argument names from, - // and whether there's a `self` argument (treated specially). - let mut assoc_item_kind = None; - let mut impl_self = None; - let parent = self.tcx.hir().get_parent_node(output.hir_id); - let body = match self.tcx.hir().get(parent) { - // `fn` definitions and methods. - Node::Item(&hir::Item { kind: hir::ItemKind::Fn(.., body), .. }) => Some(body), - - Node::TraitItem(&hir::TraitItem { - kind: hir::TraitItemKind::Method(_, ref m), .. - }) => { - if let hir::ItemKind::Trait(.., ref trait_items) = - self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind - { - assoc_item_kind = - trait_items.iter().find(|ti| ti.id.hir_id == parent).map(|ti| ti.kind); - } - match *m { - hir::TraitMethod::Required(_) => None, - hir::TraitMethod::Provided(body) => Some(body), - } - } - - Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Method(_, body), .. }) => { - if let hir::ItemKind::Impl(.., ref self_ty, ref impl_items) = - self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind - { - impl_self = Some(self_ty); - assoc_item_kind = - impl_items.iter().find(|ii| ii.id.hir_id == parent).map(|ii| ii.kind); - } - Some(body) - } - - // Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds). - Node::ForeignItem(_) | Node::Ty(_) | Node::TraitRef(_) => None, - // Everything else (only closures?) doesn't - // actually enjoy elision in return types. - _ => { - self.visit_ty(output); - return; - } - }; - - let has_self = match assoc_item_kind { - Some(hir::AssocItemKind::Method { has_self }) => has_self, - _ => false, - }; - - // In accordance with the rules for lifetime elision, we can determine - // what region to use for elision in the output type in two ways. - // First (determined here), if `self` is by-reference, then the - // implied output region is the region of the self parameter. - if has_self { - struct SelfVisitor<'a> { - map: &'a NamedRegionMap, - impl_self: Option<&'a hir::TyKind<'a>>, - lifetime: Set1, - } - - impl SelfVisitor<'_> { - // Look for `self: &'a Self` - also desugared from `&'a self`, - // and if that matches, use it for elision and return early. - fn is_self_ty(&self, res: Res) -> bool { - if let Res::SelfTy(..) = res { - return true; - } - - // Can't always rely on literal (or implied) `Self` due - // to the way elision rules were originally specified. - if let Some(&hir::TyKind::Path(hir::QPath::Resolved(None, ref path))) = - self.impl_self - { - match path.res { - // Whitelist the types that unambiguously always - // result in the same type constructor being used - // (it can't differ between `Self` and `self`). - Res::Def(DefKind::Struct, _) - | Res::Def(DefKind::Union, _) - | Res::Def(DefKind::Enum, _) - | Res::PrimTy(_) => return res == path.res, - _ => {} - } - } - - false - } - } - - impl<'a> Visitor<'a> for SelfVisitor<'a> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'a> { - NestedVisitorMap::None - } - - fn visit_ty(&mut self, ty: &'a hir::Ty<'a>) { - if let hir::TyKind::Rptr(lifetime_ref, ref mt) = ty.kind { - if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = mt.ty.kind - { - if self.is_self_ty(path.res) { - if let Some(lifetime) = self.map.defs.get(&lifetime_ref.hir_id) { - self.lifetime.insert(*lifetime); - } - } - } - } - intravisit::walk_ty(self, ty) - } - } - - let mut visitor = SelfVisitor { - map: self.map, - impl_self: impl_self.map(|ty| &ty.kind), - lifetime: Set1::Empty, - }; - visitor.visit_ty(&inputs[0]); - if let Set1::One(lifetime) = visitor.lifetime { - let scope = Scope::Elision { elide: Elide::Exact(lifetime), s: self.scope }; - self.with(scope, |_, this| this.visit_ty(output)); - return; - } - } - - // Second, if there was exactly one lifetime (either a substitution or a - // reference) in the arguments, then any anonymous regions in the output - // have that lifetime. - let mut possible_implied_output_region = None; - let mut lifetime_count = 0; - let arg_lifetimes = inputs - .iter() - .enumerate() - .skip(has_self as usize) - .map(|(i, input)| { - let mut gather = GatherLifetimes { - map: self.map, - outer_index: ty::INNERMOST, - have_bound_regions: false, - lifetimes: Default::default(), - }; - gather.visit_ty(input); - - lifetime_count += gather.lifetimes.len(); - - if lifetime_count == 1 && gather.lifetimes.len() == 1 { - // there's a chance that the unique lifetime of this - // iteration will be the appropriate lifetime for output - // parameters, so lets store it. - possible_implied_output_region = gather.lifetimes.iter().cloned().next(); - } - - ElisionFailureInfo { - parent: body, - index: i, - lifetime_count: gather.lifetimes.len(), - have_bound_regions: gather.have_bound_regions, - } - }) - .collect(); - - let elide = if lifetime_count == 1 { - Elide::Exact(possible_implied_output_region.unwrap()) - } else { - Elide::Error(arg_lifetimes) - }; - - debug!("visit_fn_like_elision: elide={:?}", elide); - - let scope = Scope::Elision { elide, s: self.scope }; - self.with(scope, |_, this| this.visit_ty(output)); - debug!("visit_fn_like_elision: exit"); - - struct GatherLifetimes<'a> { - map: &'a NamedRegionMap, - outer_index: ty::DebruijnIndex, - have_bound_regions: bool, - lifetimes: FxHashSet, - } - - impl<'v, 'a> Visitor<'v> for GatherLifetimes<'a> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> { - NestedVisitorMap::None - } - - fn visit_ty(&mut self, ty: &hir::Ty<'_>) { - if let hir::TyKind::BareFn(_) = ty.kind { - self.outer_index.shift_in(1); - } - match ty.kind { - hir::TyKind::TraitObject(bounds, ref lifetime) => { - for bound in bounds { - self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); - } - - // Stay on the safe side and don't include the object - // lifetime default (which may not end up being used). - if !lifetime.is_elided() { - self.visit_lifetime(lifetime); - } - } - _ => { - intravisit::walk_ty(self, ty); - } - } - if let hir::TyKind::BareFn(_) = ty.kind { - self.outer_index.shift_out(1); - } - } - - fn visit_generic_param(&mut self, param: &hir::GenericParam<'_>) { - if let hir::GenericParamKind::Lifetime { .. } = param.kind { - // FIXME(eddyb) Do we want this? It only makes a difference - // if this `for<'a>` lifetime parameter is never used. - self.have_bound_regions = true; - } - - intravisit::walk_generic_param(self, param); - } - - fn visit_poly_trait_ref( - &mut self, - trait_ref: &hir::PolyTraitRef<'_>, - modifier: hir::TraitBoundModifier, - ) { - self.outer_index.shift_in(1); - intravisit::walk_poly_trait_ref(self, trait_ref, modifier); - self.outer_index.shift_out(1); - } - - fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) { - if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.hir_id) { - match lifetime { - Region::LateBound(debruijn, _, _) | Region::LateBoundAnon(debruijn, _) - if debruijn < self.outer_index => - { - self.have_bound_regions = true; - } - _ => { - self.lifetimes.insert(lifetime.shifted_out_to_binder(self.outer_index)); - } - } - } - } - } - } - - fn resolve_elided_lifetimes(&mut self, lifetime_refs: Vec<&'tcx hir::Lifetime>) { - debug!("resolve_elided_lifetimes(lifetime_refs={:?})", lifetime_refs); - - if lifetime_refs.is_empty() { - return; - } - - let span = lifetime_refs[0].span; - let mut late_depth = 0; - let mut scope = self.scope; - let mut lifetime_names = FxHashSet::default(); - let error = loop { - match *scope { - // Do not assign any resolution, it will be inferred. - Scope::Body { .. } => return, - - Scope::Root => break None, - - Scope::Binder { s, ref lifetimes, .. } => { - // collect named lifetimes for suggestions - for name in lifetimes.keys() { - if let hir::ParamName::Plain(name) = name { - lifetime_names.insert(*name); - } - } - late_depth += 1; - scope = s; - } - - Scope::Elision { ref elide, ref s, .. } => { - let lifetime = match *elide { - Elide::FreshLateAnon(ref counter) => { - for lifetime_ref in lifetime_refs { - let lifetime = Region::late_anon(counter).shifted(late_depth); - self.insert_lifetime(lifetime_ref, lifetime); - } - return; - } - Elide::Exact(l) => l.shifted(late_depth), - Elide::Error(ref e) => { - if let Scope::Binder { ref lifetimes, .. } = s { - // collect named lifetimes for suggestions - for name in lifetimes.keys() { - if let hir::ParamName::Plain(name) = name { - lifetime_names.insert(*name); - } - } - } - break Some(e); - } - }; - for lifetime_ref in lifetime_refs { - self.insert_lifetime(lifetime_ref, lifetime); - } - return; - } - - Scope::ObjectLifetimeDefault { s, .. } => { - scope = s; - } - } - }; - - let mut err = report_missing_lifetime_specifiers(self.tcx.sess, span, lifetime_refs.len()); - let mut add_label = true; - - if let Some(params) = error { - if lifetime_refs.len() == 1 { - add_label = add_label && self.report_elision_failure(&mut err, params, span); - } - } - if add_label { - add_missing_lifetime_specifiers_label( - &mut err, - span, - lifetime_refs.len(), - &lifetime_names, - self.tcx.sess.source_map().span_to_snippet(span).ok().as_ref().map(|s| s.as_str()), - ); - } - - err.emit(); - } - - fn suggest_lifetime(&self, db: &mut DiagnosticBuilder<'_>, span: Span, msg: &str) -> bool { - match self.tcx.sess.source_map().span_to_snippet(span) { - Ok(ref snippet) => { - let (sugg, applicability) = if snippet == "&" { - ("&'static ".to_owned(), Applicability::MachineApplicable) - } else if snippet == "'_" { - ("'static".to_owned(), Applicability::MachineApplicable) - } else { - (format!("{} + 'static", snippet), Applicability::MaybeIncorrect) - }; - db.span_suggestion(span, msg, sugg, applicability); - false - } - Err(_) => { - db.help(msg); - true - } - } - } - - fn report_elision_failure( - &mut self, - db: &mut DiagnosticBuilder<'_>, - params: &[ElisionFailureInfo], - span: Span, - ) -> bool { - let mut m = String::new(); - let len = params.len(); - - let elided_params: Vec<_> = - params.iter().cloned().filter(|info| info.lifetime_count > 0).collect(); - - let elided_len = elided_params.len(); - - for (i, info) in elided_params.into_iter().enumerate() { - let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions } = info; - - let help_name = if let Some(ident) = - parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident()) - { - format!("`{}`", ident) - } else { - format!("argument {}", index + 1) - }; - - m.push_str( - &(if n == 1 { - help_name - } else { - format!( - "one of {}'s {} {}lifetimes", - help_name, - n, - if have_bound_regions { "free " } else { "" } - ) - })[..], - ); - - if elided_len == 2 && i == 0 { - m.push_str(" or "); - } else if i + 2 == elided_len { - m.push_str(", or "); - } else if i != elided_len - 1 { - m.push_str(", "); - } - } - - if len == 0 { - help!( - db, - "this function's return type contains a borrowed value, but \ - there is no value for it to be borrowed from" - ); - self.suggest_lifetime(db, span, "consider giving it a 'static lifetime") - } else if elided_len == 0 { - help!( - db, - "this function's return type contains a borrowed value with \ - an elided lifetime, but the lifetime cannot be derived from \ - the arguments" - ); - let msg = "consider giving it an explicit bounded or 'static lifetime"; - self.suggest_lifetime(db, span, msg) - } else if elided_len == 1 { - help!( - db, - "this function's return type contains a borrowed value, but \ - the signature does not say which {} it is borrowed from", - m - ); - true - } else { - help!( - db, - "this function's return type contains a borrowed value, but \ - the signature does not say whether it is borrowed from {}", - m - ); - true - } - } - - fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) { - debug!("resolve_object_lifetime_default(lifetime_ref={:?})", lifetime_ref); - let mut late_depth = 0; - let mut scope = self.scope; - let lifetime = loop { - match *scope { - Scope::Binder { s, .. } => { - late_depth += 1; - scope = s; - } - - Scope::Root | Scope::Elision { .. } => break Region::Static, - - Scope::Body { .. } | Scope::ObjectLifetimeDefault { lifetime: None, .. } => return, - - Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l, - } - }; - self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth)); - } - - fn check_lifetime_params( - &mut self, - old_scope: ScopeRef<'_>, - params: &'tcx [hir::GenericParam<'tcx>], - ) { - let lifetimes: Vec<_> = params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => Some((param, param.name.modern())), - _ => None, - }) - .collect(); - for (i, (lifetime_i, lifetime_i_name)) in lifetimes.iter().enumerate() { - if let hir::ParamName::Plain(_) = lifetime_i_name { - let name = lifetime_i_name.ident().name; - if name == kw::UnderscoreLifetime || name == kw::StaticLifetime { - let mut err = struct_span_err!( - self.tcx.sess, - lifetime_i.span, - E0262, - "invalid lifetime parameter name: `{}`", - lifetime_i.name.ident(), - ); - err.span_label( - lifetime_i.span, - format!("{} is a reserved lifetime name", name), - ); - err.emit(); - } - } - - // It is a hard error to shadow a lifetime within the same scope. - for (lifetime_j, lifetime_j_name) in lifetimes.iter().skip(i + 1) { - if lifetime_i_name == lifetime_j_name { - struct_span_err!( - self.tcx.sess, - lifetime_j.span, - E0263, - "lifetime name `{}` declared twice in the same scope", - lifetime_j.name.ident() - ) - .span_label(lifetime_j.span, "declared twice") - .span_label(lifetime_i.span, "previous declaration here") - .emit(); - } - } - - // It is a soft error to shadow a lifetime within a parent scope. - self.check_lifetime_param_for_shadowing(old_scope, &lifetime_i); - - for bound in lifetime_i.bounds { - match bound { - hir::GenericBound::Outlives(ref lt) => match lt.name { - hir::LifetimeName::Underscore => self.tcx.sess.delay_span_bug( - lt.span, - "use of `'_` in illegal place, but not caught by lowering", - ), - hir::LifetimeName::Static => { - self.insert_lifetime(lt, Region::Static); - self.tcx - .sess - .struct_span_warn( - lifetime_i.span.to(lt.span), - &format!( - "unnecessary lifetime parameter `{}`", - lifetime_i.name.ident(), - ), - ) - .help(&format!( - "you can use the `'static` lifetime directly, in place of `{}`", - lifetime_i.name.ident(), - )) - .emit(); - } - hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit => { - self.resolve_lifetime_ref(lt); - } - hir::LifetimeName::ImplicitObjectLifetimeDefault => { - self.tcx.sess.delay_span_bug( - lt.span, - "lowering generated `ImplicitObjectLifetimeDefault` \ - outside of an object type", - ) - } - hir::LifetimeName::Error => { - // No need to do anything, error already reported. - } - }, - _ => bug!(), - } - } - } - } - - fn check_lifetime_param_for_shadowing( - &self, - mut old_scope: ScopeRef<'_>, - param: &'tcx hir::GenericParam<'tcx>, - ) { - for label in &self.labels_in_fn { - // FIXME (#24278): non-hygienic comparison - if param.name.ident().name == label.name { - signal_shadowing_problem( - self.tcx, - label.name, - original_label(label.span), - shadower_lifetime(¶m), - ); - return; - } - } - - loop { - match *old_scope { - Scope::Body { s, .. } - | Scope::Elision { s, .. } - | Scope::ObjectLifetimeDefault { s, .. } => { - old_scope = s; - } - - Scope::Root => { - return; - } - - Scope::Binder { ref lifetimes, s, .. } => { - if let Some(&def) = lifetimes.get(¶m.name.modern()) { - let hir_id = self.tcx.hir().as_local_hir_id(def.id().unwrap()).unwrap(); - - signal_shadowing_problem( - self.tcx, - param.name.ident().name, - original_lifetime(self.tcx.hir().span(hir_id)), - shadower_lifetime(¶m), - ); - return; - } - - old_scope = s; - } - } - } - } - - /// Returns `true` if, in the current scope, replacing `'_` would be - /// equivalent to a single-use lifetime. - fn track_lifetime_uses(&self) -> bool { - let mut scope = self.scope; - loop { - match *scope { - Scope::Root => break false, - - // Inside of items, it depends on the kind of item. - Scope::Binder { track_lifetime_uses, .. } => break track_lifetime_uses, - - // Inside a body, `'_` will use an inference variable, - // should be fine. - Scope::Body { .. } => break true, - - // A lifetime only used in a fn argument could as well - // be replaced with `'_`, as that would generate a - // fresh name, too. - Scope::Elision { elide: Elide::FreshLateAnon(_), .. } => break true, - - // In the return type or other such place, `'_` is not - // going to make a fresh name, so we cannot - // necessarily replace a single-use lifetime with - // `'_`. - Scope::Elision { elide: Elide::Exact(_), .. } => break false, - Scope::Elision { elide: Elide::Error(_), .. } => break false, - - Scope::ObjectLifetimeDefault { s, .. } => scope = s, - } - } - } - - fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) { - if lifetime_ref.hir_id == hir::DUMMY_HIR_ID { - span_bug!( - lifetime_ref.span, - "lifetime reference not renumbered, \ - probably a bug in syntax::fold" - ); - } - - debug!( - "insert_lifetime: {} resolved to {:?} span={:?}", - self.tcx.hir().node_to_string(lifetime_ref.hir_id), - def, - self.tcx.sess.source_map().span_to_string(lifetime_ref.span) - ); - self.map.defs.insert(lifetime_ref.hir_id, def); - - match def { - 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, _) => { - // A lifetime declared by the user. - let track_lifetime_uses = self.track_lifetime_uses(); - debug!("insert_lifetime: track_lifetime_uses={}", track_lifetime_uses); - if track_lifetime_uses && !self.lifetime_uses.contains_key(&def_id) { - debug!("insert_lifetime: first use of {:?}", def_id); - self.lifetime_uses.insert(def_id, LifetimeUseSet::One(lifetime_ref)); - } else { - debug!("insert_lifetime: many uses of {:?}", def_id); - self.lifetime_uses.insert(def_id, LifetimeUseSet::Many); - } - } - } - } - - /// Sometimes we resolve a lifetime, but later find that it is an - /// error (esp. around impl trait). In that case, we remove the - /// entry into `map.defs` so as not to confuse later code. - fn uninsert_lifetime_on_error(&mut self, lifetime_ref: &'tcx hir::Lifetime, bad_def: Region) { - let old_value = self.map.defs.remove(&lifetime_ref.hir_id); - assert_eq!(old_value, Some(bad_def)); - } -} - -/// Detects late-bound lifetimes and inserts them into -/// `map.late_bound`. -/// -/// A region declared on a fn is **late-bound** if: -/// - it is constrained by an argument type; -/// - it does not appear in a where-clause. -/// -/// "Constrained" basically means that it appears in any type but -/// not amongst the inputs to a projection. In other words, `<&'a -/// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`. -fn insert_late_bound_lifetimes( - map: &mut NamedRegionMap, - decl: &hir::FnDecl<'_>, - generics: &hir::Generics<'_>, -) { - debug!("insert_late_bound_lifetimes(decl={:?}, generics={:?})", decl, generics); - - let mut constrained_by_input = ConstrainedCollector::default(); - for arg_ty in decl.inputs { - constrained_by_input.visit_ty(arg_ty); - } - - let mut appears_in_output = AllCollector::default(); - intravisit::walk_fn_ret_ty(&mut appears_in_output, &decl.output); - - debug!("insert_late_bound_lifetimes: constrained_by_input={:?}", constrained_by_input.regions); - - // Walk the lifetimes that appear in where clauses. - // - // Subtle point: because we disallow nested bindings, we can just - // ignore binders here and scrape up all names we see. - let mut appears_in_where_clause = AllCollector::default(); - appears_in_where_clause.visit_generics(generics); - - for param in generics.params { - if let hir::GenericParamKind::Lifetime { .. } = param.kind { - if !param.bounds.is_empty() { - // `'a: 'b` means both `'a` and `'b` are referenced - appears_in_where_clause - .regions - .insert(hir::LifetimeName::Param(param.name.modern())); - } - } - } - - debug!( - "insert_late_bound_lifetimes: appears_in_where_clause={:?}", - appears_in_where_clause.regions - ); - - // Late bound regions are those that: - // - appear in the inputs - // - do not appear in the where-clauses - // - are not implicitly captured by `impl Trait` - for param in generics.params { - match param.kind { - hir::GenericParamKind::Lifetime { .. } => { /* fall through */ } - - // Neither types nor consts are late-bound. - hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => continue, - } - - let lt_name = hir::LifetimeName::Param(param.name.modern()); - // appears in the where clauses? early-bound. - if appears_in_where_clause.regions.contains(<_name) { - continue; - } - - // does not appear in the inputs, but appears in the return type? early-bound. - if !constrained_by_input.regions.contains(<_name) - && appears_in_output.regions.contains(<_name) - { - continue; - } - - debug!( - "insert_late_bound_lifetimes: lifetime {:?} with id {:?} is late-bound", - param.name.ident(), - param.hir_id - ); - - let inserted = map.late_bound.insert(param.hir_id); - assert!(inserted, "visited lifetime {:?} twice", param.hir_id); - } - - return; - - #[derive(Default)] - struct ConstrainedCollector { - regions: FxHashSet, - } - - impl<'v> Visitor<'v> for ConstrainedCollector { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> { - NestedVisitorMap::None - } - - fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { - match ty.kind { - hir::TyKind::Path(hir::QPath::Resolved(Some(_), _)) - | hir::TyKind::Path(hir::QPath::TypeRelative(..)) => { - // ignore lifetimes appearing in associated type - // projections, as they are not *constrained* - // (defined above) - } - - hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => { - // consider only the lifetimes on the final - // segment; I am not sure it's even currently - // valid to have them elsewhere, but even if it - // is, those would be potentially inputs to - // projections - if let Some(last_segment) = path.segments.last() { - self.visit_path_segment(path.span, last_segment); - } - } - - _ => { - intravisit::walk_ty(self, ty); - } - } - } - - fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { - self.regions.insert(lifetime_ref.name.modern()); - } - } - - #[derive(Default)] - struct AllCollector { - regions: FxHashSet, - } - - impl<'v> Visitor<'v> for AllCollector { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> { - NestedVisitorMap::None - } - - fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { - self.regions.insert(lifetime_ref.name.modern()); - } - } -} - -pub fn report_missing_lifetime_specifiers( - sess: &Session, - span: Span, - count: usize, -) -> DiagnosticBuilder<'_> { - struct_span_err!(sess, span, E0106, "missing lifetime specifier{}", pluralize!(count)) -} - -fn add_missing_lifetime_specifiers_label( - err: &mut DiagnosticBuilder<'_>, - span: Span, - count: usize, - lifetime_names: &FxHashSet, - snippet: Option<&str>, -) { - if count > 1 { - err.span_label(span, format!("expected {} lifetime parameters", count)); - } else if let (1, Some(name), Some("&")) = - (lifetime_names.len(), lifetime_names.iter().next(), snippet) - { - err.span_suggestion( - span, - "consider using the named lifetime", - format!("&{} ", name), - Applicability::MaybeIncorrect, - ); - } else { - err.span_label(span, "expected lifetime parameter"); - } -} diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index c30f3e68110..4c1d7f182dd 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -10,7 +10,7 @@ use rustc::hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc::hir::lowering::lower_crate; use rustc::lint; use rustc::middle::cstore::{CrateStore, MetadataLoader, MetadataLoaderDyn}; -use rustc::middle::{self, resolve_lifetime, stability}; +use rustc::middle::{self, stability}; use rustc::session::config::{self, CrateType, Input, OutputFilenames, OutputType}; use rustc::session::config::{PpMode, PpSourceMode}; use rustc::session::search_paths::PathKind; @@ -678,13 +678,13 @@ pub fn default_provide(providers: &mut ty::query::Providers<'_>) { plugin::build::provide(providers); hir::provide(providers); mir::provide(providers); - resolve_lifetime::provide(providers); rustc_privacy::provide(providers); typeck::provide(providers); ty::provide(providers); traits::provide(providers); stability::provide(providers); rustc_passes::provide(providers); + rustc_resolve::provide(providers); rustc_traits::provide(providers); rustc_metadata::provide(providers); lint::provide(providers); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 357176ae090..fa3e6291c30 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -30,6 +30,7 @@ use rustc::lint; use rustc::middle::cstore::{CrateStore, MetadataLoaderDyn}; use rustc::session::Session; use rustc::span_bug; +use rustc::ty::query::Providers; use rustc::ty::{self, DefIdTree, ResolverOutputs}; use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap, NodeSet}; @@ -74,6 +75,7 @@ mod def_collector; mod diagnostics; mod imports; mod late; +mod lifetimes; mod macros; enum Weak { @@ -3089,3 +3091,7 @@ impl CrateLint { } } } + +pub fn provide(providers: &mut Providers<'_>) { + lifetimes::provide(providers); +} diff --git a/src/librustc_resolve/lifetimes.rs b/src/librustc_resolve/lifetimes.rs new file mode 100644 index 00000000000..345974ae243 --- /dev/null +++ b/src/librustc_resolve/lifetimes.rs @@ -0,0 +1,2888 @@ +//! Name resolution for lifetimes. +//! +//! Name resolution for lifetimes follows *much* simpler rules than the +//! full resolve. For example, lifetime names are never exported or +//! used between functions, and they operate in a purely top-down +//! way. Therefore, we break lifetime name resolution into a separate pass. + +use rustc::hir::def::{DefKind, Res}; +use rustc::hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; +use rustc::hir::map::Map; +use rustc::hir::{GenericArg, GenericParam, LifetimeName, Node, ParamName, QPath}; +use rustc::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt}; + +use errors::{pluralize, Applicability, DiagnosticBuilder}; +use rustc::lint; +use rustc::session::Session; +use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet, HirIdMap, HirIdSet}; +use std::borrow::Cow; +use std::cell::Cell; +use std::mem::{replace, take}; +use syntax::ast; +use syntax::attr; +use syntax::symbol::{kw, sym}; +use syntax_pos::Span; + +use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc::hir::{self, GenericParamKind, LifetimeParamKind}; + +use log::debug; +use rustc::{bug, span_bug}; +use syntax::{help, span_err, struct_span_err, walk_list}; + +use rustc::middle::resolve_lifetime::*; +use rustc_error_codes::*; + +// This counts the no of times a lifetime is used +#[derive(Clone, Copy, Debug)] +pub enum LifetimeUseSet<'tcx> { + One(&'tcx hir::Lifetime), + Many, +} + +trait RegionExt { + fn early(hir_map: &Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region); + + fn late(hir_map: &Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region); + + fn late_anon(index: &Cell) -> Region; + + fn id(&self) -> Option; + + fn shifted(self, amount: u32) -> Region; + + fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region; + + fn subst<'a, L>(self, params: L, map: &NamedRegionMap) -> Option + where + L: Iterator; +} + +impl RegionExt for Region { + fn early(hir_map: &Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region) { + let i = *index; + *index += 1; + let def_id = hir_map.local_def_id(param.hir_id); + let origin = LifetimeDefOrigin::from_param(param); + debug!("Region::early: index={} def_id={:?}", i, def_id); + (param.name.modern(), Region::EarlyBound(i, def_id, origin)) + } + + fn late(hir_map: &Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region) { + let depth = ty::INNERMOST; + let def_id = hir_map.local_def_id(param.hir_id); + let origin = LifetimeDefOrigin::from_param(param); + debug!( + "Region::late: param={:?} depth={:?} def_id={:?} origin={:?}", + param, depth, def_id, origin, + ); + (param.name.modern(), Region::LateBound(depth, def_id, origin)) + } + + fn late_anon(index: &Cell) -> Region { + let i = index.get(); + index.set(i + 1); + let depth = ty::INNERMOST; + Region::LateBoundAnon(depth, i) + } + + fn id(&self) -> Option { + match *self { + Region::Static | Region::LateBoundAnon(..) => None, + + Region::EarlyBound(_, id, _) | Region::LateBound(_, id, _) | Region::Free(_, id) => { + Some(id) + } + } + } + + fn shifted(self, amount: u32) -> Region { + match self { + Region::LateBound(debruijn, id, origin) => { + Region::LateBound(debruijn.shifted_in(amount), id, origin) + } + Region::LateBoundAnon(debruijn, index) => { + Region::LateBoundAnon(debruijn.shifted_in(amount), index) + } + _ => self, + } + } + + fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region { + match self { + Region::LateBound(debruijn, id, origin) => { + Region::LateBound(debruijn.shifted_out_to_binder(binder), id, origin) + } + Region::LateBoundAnon(debruijn, index) => { + Region::LateBoundAnon(debruijn.shifted_out_to_binder(binder), index) + } + _ => self, + } + } + + fn subst<'a, L>(self, mut params: L, map: &NamedRegionMap) -> Option + where + L: Iterator, + { + if let Region::EarlyBound(index, _, _) = self { + params.nth(index as usize).and_then(|lifetime| map.defs.get(&lifetime.hir_id).cloned()) + } else { + Some(self) + } + } +} + +/// Maps the id of each lifetime reference to the lifetime decl +/// that it corresponds to. +/// +/// FIXME. This struct gets converted to a `ResolveLifetimes` for +/// actual use. It has the same data, but indexed by `DefIndex`. This +/// is silly. +#[derive(Default)] +struct NamedRegionMap { + // maps from every use of a named (not anonymous) lifetime to a + // `Region` describing how that region is bound + defs: HirIdMap, + + // the set of lifetime def ids that are late-bound; a region can + // be late-bound if (a) it does NOT appear in a where-clause and + // (b) it DOES appear in the arguments. + late_bound: HirIdSet, + + // For each type and trait definition, maps type parameters + // to the trait object lifetime defaults computed from them. + object_lifetime_defaults: HirIdMap>, +} + +struct LifetimeContext<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + map: &'a mut NamedRegionMap, + scope: ScopeRef<'a>, + + /// This is slightly complicated. Our representation for poly-trait-refs contains a single + /// binder and thus we only allow a single level of quantification. However, + /// the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>` + /// and `for <'a, 'b> &'b T: Foo<'a>`. In order to get the De Bruijn indices + /// correct when representing these constraints, we should only introduce one + /// scope. However, we want to support both locations for the quantifier and + /// during lifetime resolution we want precise information (so we can't + /// desugar in an earlier phase). + /// + /// So, if we encounter a quantifier at the outer scope, we set + /// `trait_ref_hack` to `true` (and introduce a scope), and then if we encounter + /// a quantifier at the inner scope, we error. If `trait_ref_hack` is `false`, + /// then we introduce the scope at the inner quantifier. + trait_ref_hack: bool, + + /// Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax. + is_in_fn_syntax: bool, + + /// List of labels in the function/method currently under analysis. + labels_in_fn: Vec, + + /// Cache for cross-crate per-definition object lifetime defaults. + xcrate_object_lifetime_defaults: DefIdMap>, + + lifetime_uses: &'a mut DefIdMap>, +} + +#[derive(Debug)] +enum Scope<'a> { + /// Declares lifetimes, and each can be early-bound or late-bound. + /// The `DebruijnIndex` of late-bound lifetimes starts at `1` and + /// it should be shifted by the number of `Binder`s in between the + /// declaration `Binder` and the location it's referenced from. + Binder { + lifetimes: FxHashMap, + + /// if we extend this scope with another scope, what is the next index + /// we should use for an early-bound region? + next_early_index: u32, + + /// Flag is set to true if, in this binder, `'_` would be + /// equivalent to a "single-use region". This is true on + /// impls, but not other kinds of items. + track_lifetime_uses: bool, + + /// Whether or not this binder would serve as the parent + /// binder for opaque types introduced within. For example: + /// + /// ```text + /// fn foo<'a>() -> impl for<'b> Trait> + /// ``` + /// + /// Here, the opaque 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 opaque type. + opaque_type_parent: bool, + + s: ScopeRef<'a>, + }, + + /// Lifetimes introduced by a fn are scoped to the call-site for that fn, + /// if this is a fn body, otherwise the original definitions are used. + /// Unspecified lifetimes are inferred, unless an elision scope is nested, + /// e.g., `(&T, fn(&T) -> &T);` becomes `(&'_ T, for<'a> fn(&'a T) -> &'a T)`. + Body { + id: hir::BodyId, + s: ScopeRef<'a>, + }, + + /// A scope which either determines unspecified lifetimes or errors + /// on them (e.g., due to ambiguity). For more details, see `Elide`. + Elision { + elide: Elide, + s: ScopeRef<'a>, + }, + + /// Use a specific lifetime (if `Some`) or leave it unset (to be + /// inferred in a function body or potentially error outside one), + /// for the default choice of lifetime in a trait object type. + ObjectLifetimeDefault { + lifetime: Option, + s: ScopeRef<'a>, + }, + + Root, +} + +#[derive(Clone, Debug)] +enum Elide { + /// Use a fresh anonymous late-bound lifetime each time, by + /// incrementing the counter to generate sequential indices. + FreshLateAnon(Cell), + /// Always use this one lifetime. + Exact(Region), + /// Less or more than one lifetime were found, error on unspecified. + Error(Vec), +} + +#[derive(Clone, Debug)] +struct ElisionFailureInfo { + /// Where we can find the argument pattern. + parent: Option, + /// The index of the argument in the original definition. + index: usize, + lifetime_count: usize, + have_bound_regions: bool, +} + +type ScopeRef<'a> = &'a Scope<'a>; + +const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root; + +pub fn provide(providers: &mut ty::query::Providers<'_>) { + *providers = ty::query::Providers { + resolve_lifetimes, + + named_region_map: |tcx, id| { + let id = LocalDefId::from_def_id(DefId::local(id)); // (*) + tcx.resolve_lifetimes(LOCAL_CRATE).defs.get(&id) + }, + + is_late_bound_map: |tcx, id| { + let id = LocalDefId::from_def_id(DefId::local(id)); // (*) + tcx.resolve_lifetimes(LOCAL_CRATE).late_bound.get(&id) + }, + + object_lifetime_defaults_map: |tcx, id| { + let id = LocalDefId::from_def_id(DefId::local(id)); // (*) + tcx.resolve_lifetimes(LOCAL_CRATE).object_lifetime_defaults.get(&id) + }, + + ..*providers + }; + + // (*) FIXME the query should be defined to take a LocalDefId +} + +/// Computes the `ResolveLifetimes` map that contains data for the +/// entire crate. You should not read the result of this query +/// directly, but rather use `named_region_map`, `is_late_bound_map`, +/// etc. +fn resolve_lifetimes(tcx: TyCtxt<'_>, for_krate: CrateNum) -> &ResolveLifetimes { + assert_eq!(for_krate, LOCAL_CRATE); + + let named_region_map = krate(tcx); + + let mut rl = ResolveLifetimes::default(); + + for (hir_id, v) in named_region_map.defs { + let map = rl.defs.entry(hir_id.owner_local_def_id()).or_default(); + map.insert(hir_id.local_id, v); + } + for hir_id in named_region_map.late_bound { + let map = rl.late_bound.entry(hir_id.owner_local_def_id()).or_default(); + map.insert(hir_id.local_id); + } + for (hir_id, v) in named_region_map.object_lifetime_defaults { + let map = rl.object_lifetime_defaults.entry(hir_id.owner_local_def_id()).or_default(); + map.insert(hir_id.local_id, v); + } + + tcx.arena.alloc(rl) +} + +fn krate(tcx: TyCtxt<'_>) -> NamedRegionMap { + let krate = tcx.hir().krate(); + let mut map = NamedRegionMap { + defs: Default::default(), + late_bound: Default::default(), + object_lifetime_defaults: compute_object_lifetime_defaults(tcx), + }; + { + let mut visitor = LifetimeContext { + tcx, + map: &mut map, + scope: ROOT_SCOPE, + trait_ref_hack: false, + is_in_fn_syntax: false, + labels_in_fn: vec![], + xcrate_object_lifetime_defaults: Default::default(), + lifetime_uses: &mut Default::default(), + }; + for (_, item) in &krate.items { + visitor.visit_item(item); + } + } + map +} + +/// In traits, there is an implicit `Self` type parameter which comes before the generics. +/// We have to account for this when computing the index of the other generic parameters. +/// This function returns whether there is such an implicit parameter defined on the given item. +fn sub_items_have_self_param(node: &hir::ItemKind<'_>) -> bool { + match *node { + hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => true, + _ => false, + } +} + +impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::All(&self.tcx.hir()) + } + + // We want to nest trait/impl items in their parent, but nothing else. + fn visit_nested_item(&mut self, _: hir::ItemId) {} + + fn visit_nested_body(&mut self, body: hir::BodyId) { + // Each body has their own set of labels, save labels. + let saved = take(&mut self.labels_in_fn); + let body = self.tcx.hir().body(body); + extract_labels(self, body); + self.with(Scope::Body { id: body.id(), s: self.scope }, |_, this| { + this.visit_body(body); + }); + replace(&mut self.labels_in_fn, saved); + } + + fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { + match item.kind { + hir::ItemKind::Fn(ref sig, ref generics, _) => { + self.visit_early_late(None, &sig.decl, generics, |this| { + intravisit::walk_item(this, item); + }); + } + + hir::ItemKind::ExternCrate(_) + | hir::ItemKind::Use(..) + | hir::ItemKind::Mod(..) + | hir::ItemKind::ForeignMod(..) + | hir::ItemKind::GlobalAsm(..) => { + // These sorts of items have no lifetime parameters at all. + intravisit::walk_item(self, item); + } + hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => { + // No lifetime parameters, but implied 'static. + let scope = Scope::Elision { elide: Elide::Exact(Region::Static), s: ROOT_SCOPE }; + self.with(scope, |_, this| intravisit::walk_item(this, item)); + } + hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(_), .. }) => { + // Currently opaque type declarations are just generated from `impl Trait` + // items. Doing anything on this node is irrelevant, as we currently don't need + // it. + } + hir::ItemKind::TyAlias(_, ref generics) + | hir::ItemKind::OpaqueTy(hir::OpaqueTy { + impl_trait_fn: None, ref generics, .. + }) + | hir::ItemKind::Enum(_, ref generics) + | hir::ItemKind::Struct(_, ref generics) + | hir::ItemKind::Union(_, ref generics) + | hir::ItemKind::Trait(_, _, ref generics, ..) + | hir::ItemKind::TraitAlias(ref generics, ..) + | hir::ItemKind::Impl(_, _, _, ref generics, ..) => { + // Impls permit `'_` to be used and it is equivalent to "some fresh lifetime name". + // This is not true for other kinds of items.x + let track_lifetime_uses = match item.kind { + hir::ItemKind::Impl(..) => true, + _ => false, + }; + // These kinds of items have only early-bound lifetime parameters. + let mut index = if sub_items_have_self_param(&item.kind) { + 1 // Self comes before lifetimes + } else { + 0 + }; + let mut non_lifetime_count = 0; + let lifetimes = generics + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::early(&self.tcx.hir(), &mut index, param)) + } + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { + non_lifetime_count += 1; + None + } + }) + .collect(); + let scope = Scope::Binder { + lifetimes, + next_early_index: index + non_lifetime_count, + opaque_type_parent: true, + track_lifetime_uses, + s: ROOT_SCOPE, + }; + self.with(scope, |old_scope, this| { + this.check_lifetime_params(old_scope, &generics.params); + intravisit::walk_item(this, item); + }); + } + } + } + + fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { + match item.kind { + hir::ForeignItemKind::Fn(ref decl, _, ref generics) => { + self.visit_early_late(None, decl, generics, |this| { + intravisit::walk_foreign_item(this, item); + }) + } + hir::ForeignItemKind::Static(..) => { + intravisit::walk_foreign_item(self, item); + } + hir::ForeignItemKind::Type => { + intravisit::walk_foreign_item(self, item); + } + } + } + + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { + debug!("visit_ty: id={:?} ty={:?}", ty.hir_id, ty); + debug!("visit_ty: ty.kind={:?}", ty.kind); + match ty.kind { + hir::TyKind::BareFn(ref c) => { + let next_early_index = self.next_early_index(); + let was_in_fn_syntax = self.is_in_fn_syntax; + self.is_in_fn_syntax = true; + let scope = Scope::Binder { + lifetimes: c + .generic_params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::late(&self.tcx.hir(), param)) + } + _ => None, + }) + .collect(), + s: self.scope, + next_early_index, + track_lifetime_uses: true, + opaque_type_parent: false, + }; + self.with(scope, |old_scope, this| { + // a bare fn has no bounds, so everything + // contained within is scoped within its binder. + this.check_lifetime_params(old_scope, &c.generic_params); + intravisit::walk_ty(this, ty); + }); + self.is_in_fn_syntax = was_in_fn_syntax; + } + hir::TyKind::TraitObject(bounds, ref lifetime) => { + debug!("visit_ty: TraitObject(bounds={:?}, lifetime={:?})", bounds, lifetime); + for bound in bounds { + self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); + } + match lifetime.name { + LifetimeName::Implicit => { + // For types like `dyn Foo`, we should + // generate a special form of elided. + span_bug!(ty.span, "object-lifetime-default expected, not implict",); + } + LifetimeName::ImplicitObjectLifetimeDefault => { + // If the user does not write *anything*, we + // use the object lifetime defaulting + // rules. So e.g., `Box` becomes + // `Box`. + self.resolve_object_lifetime_default(lifetime) + } + LifetimeName::Underscore => { + // If the user writes `'_`, we use the *ordinary* elision + // rules. So the `'_` in e.g., `Box` will be + // resolved the same as the `'_` in `&'_ Foo`. + // + // cc #48468 + self.resolve_elided_lifetimes(vec![lifetime]) + } + LifetimeName::Param(_) | LifetimeName::Static => { + // If the user wrote an explicit name, use that. + self.visit_lifetime(lifetime); + } + LifetimeName::Error => {} + } + } + hir::TyKind::Rptr(ref lifetime_ref, ref mt) => { + self.visit_lifetime(lifetime_ref); + let scope = Scope::ObjectLifetimeDefault { + lifetime: self.map.defs.get(&lifetime_ref.hir_id).cloned(), + s: self.scope, + }; + self.with(scope, |_, this| this.visit_ty(&mt.ty)); + } + hir::TyKind::Def(item_id, lifetimes) => { + // Resolve the lifetimes in the bounds to the lifetime defs in the generics. + // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to + // `type MyAnonTy<'b> = impl MyTrait<'b>;` + // ^ ^ this gets resolved in the scope of + // the opaque_ty generics + let (generics, bounds) = match self.tcx.hir().expect_item(item_id.id).kind { + // Named opaque `impl Trait` types are reached via `TyKind::Path`. + // This arm is for `impl Trait` in the types of statics, constants and locals. + hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: None, .. }) => { + intravisit::walk_ty(self, ty); + return; + } + // RPIT (return position impl trait) + hir::ItemKind::OpaqueTy(hir::OpaqueTy { ref generics, bounds, .. }) => { + (generics, bounds) + } + ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), + }; + + // Resolve the lifetimes that are applied to the opaque type. + // These are resolved in the current scope. + // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to + // `fn foo<'a>() -> MyAnonTy<'a> { ... }` + // ^ ^this gets resolved in the current scope + for lifetime in lifetimes { + if let hir::GenericArg::Lifetime(lifetime) = lifetime { + self.visit_lifetime(lifetime); + + // Check for predicates like `impl for<'a> Trait>` + // and ban them. Type variables instantiated inside binders aren't + // well-supported at the moment, so this doesn't work. + // In the future, this should be fixed and this error should be removed. + let def = self.map.defs.get(&lifetime.hir_id).cloned(); + if let Some(Region::LateBound(_, def_id, _)) = def { + if let Some(hir_id) = self.tcx.hir().as_local_hir_id(def_id) { + // Ensure that the parent of the def is an item, not HRTB + let parent_id = self.tcx.hir().get_parent_node(hir_id); + let parent_impl_id = hir::ImplItemId { hir_id: parent_id }; + let parent_trait_id = hir::TraitItemId { hir_id: parent_id }; + let krate = self.tcx.hir().forest.krate(); + + if !(krate.items.contains_key(&parent_id) + || krate.impl_items.contains_key(&parent_impl_id) + || krate.trait_items.contains_key(&parent_trait_id)) + { + span_err!( + self.tcx.sess, + lifetime.span, + E0657, + "`impl Trait` can only capture lifetimes \ + bound at the fn or impl level" + ); + self.uninsert_lifetime_on_error(lifetime, def.unwrap()); + } + } + } + } + } + + // 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_opaque_type(); + debug!("visit_ty: index = {}", index); + + let mut elision = None; + let mut lifetimes = FxHashMap::default(); + let mut non_lifetime_count = 0; + for param in generics.params { + match param.kind { + GenericParamKind::Lifetime { .. } => { + let (name, reg) = Region::early(&self.tcx.hir(), &mut index, ¶m); + let def_id = if let Region::EarlyBound(_, def_id, _) = reg { + def_id + } else { + bug!(); + }; + if let hir::ParamName::Plain(param_name) = name { + if param_name.name == kw::UnderscoreLifetime { + // Pick the elided lifetime "definition" if one exists + // and use it to make an elision scope. + self.lifetime_uses.insert(def_id.clone(), LifetimeUseSet::Many); + elision = Some(reg); + } else { + lifetimes.insert(name, reg); + } + } else { + self.lifetime_uses.insert(def_id.clone(), LifetimeUseSet::Many); + lifetimes.insert(name, reg); + } + } + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { + non_lifetime_count += 1; + } + } + } + let next_early_index = index + non_lifetime_count; + + if let Some(elision_region) = elision { + let scope = + Scope::Elision { elide: Elide::Exact(elision_region), s: self.scope }; + self.with(scope, |_old_scope, this| { + let scope = Scope::Binder { + lifetimes, + next_early_index, + s: this.scope, + track_lifetime_uses: true, + opaque_type_parent: false, + }; + this.with(scope, |_old_scope, this| { + this.visit_generics(generics); + for bound in bounds { + this.visit_param_bound(bound); + } + }); + }); + } else { + let scope = Scope::Binder { + lifetimes, + next_early_index, + s: self.scope, + track_lifetime_uses: true, + opaque_type_parent: false, + }; + self.with(scope, |_old_scope, this| { + this.visit_generics(generics); + for bound in bounds { + this.visit_param_bound(bound); + } + }); + } + } + _ => intravisit::walk_ty(self, ty), + } + } + + fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { + use self::hir::TraitItemKind::*; + match trait_item.kind { + Method(ref sig, _) => { + let tcx = self.tcx; + self.visit_early_late( + Some(tcx.hir().get_parent_item(trait_item.hir_id)), + &sig.decl, + &trait_item.generics, + |this| intravisit::walk_trait_item(this, trait_item), + ); + } + Type(bounds, ref ty) => { + let generics = &trait_item.generics; + let mut index = self.next_early_index(); + debug!("visit_ty: index = {}", index); + let mut non_lifetime_count = 0; + let lifetimes = generics + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::early(&self.tcx.hir(), &mut index, param)) + } + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { + non_lifetime_count += 1; + None + } + }) + .collect(); + let scope = Scope::Binder { + lifetimes, + next_early_index: index + non_lifetime_count, + s: self.scope, + track_lifetime_uses: true, + opaque_type_parent: true, + }; + self.with(scope, |_old_scope, this| { + this.visit_generics(generics); + for bound in bounds { + this.visit_param_bound(bound); + } + if let Some(ty) = ty { + 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); + } + } + } + + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { + use self::hir::ImplItemKind::*; + match impl_item.kind { + Method(ref sig, _) => { + let tcx = self.tcx; + self.visit_early_late( + Some(tcx.hir().get_parent_item(impl_item.hir_id)), + &sig.decl, + &impl_item.generics, + |this| intravisit::walk_impl_item(this, impl_item), + ) + } + TyAlias(ref ty) => { + let generics = &impl_item.generics; + let mut index = self.next_early_index(); + let mut non_lifetime_count = 0; + debug!("visit_ty: index = {}", index); + let lifetimes = generics + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::early(&self.tcx.hir(), &mut index, param)) + } + GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => { + non_lifetime_count += 1; + None + } + }) + .collect(); + let scope = Scope::Binder { + lifetimes, + next_early_index: index + non_lifetime_count, + s: self.scope, + track_lifetime_uses: true, + opaque_type_parent: true, + }; + self.with(scope, |_old_scope, this| { + this.visit_generics(generics); + this.visit_ty(ty); + }); + } + OpaqueTy(bounds) => { + let generics = &impl_item.generics; + let mut index = self.next_early_index(); + let mut next_early_index = index; + debug!("visit_ty: index = {}", index); + let lifetimes = generics + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::early(&self.tcx.hir(), &mut index, param)) + } + GenericParamKind::Type { .. } => { + next_early_index += 1; + None + } + GenericParamKind::Const { .. } => { + next_early_index += 1; + None + } + }) + .collect(); + + let scope = Scope::Binder { + lifetimes, + next_early_index, + s: self.scope, + track_lifetime_uses: true, + opaque_type_parent: true, + }; + self.with(scope, |_old_scope, this| { + this.visit_generics(generics); + for bound in bounds { + this.visit_param_bound(bound); + } + }); + } + Const(_, _) => { + // Only methods and types support generics. + assert!(impl_item.generics.params.is_empty()); + intravisit::walk_impl_item(self, impl_item); + } + } + } + + fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { + debug!("visit_lifetime(lifetime_ref={:?})", lifetime_ref); + if lifetime_ref.is_elided() { + self.resolve_elided_lifetimes(vec![lifetime_ref]); + return; + } + if lifetime_ref.is_static() { + self.insert_lifetime(lifetime_ref, Region::Static); + return; + } + self.resolve_lifetime_ref(lifetime_ref); + } + + fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) { + for (i, segment) in path.segments.iter().enumerate() { + let depth = path.segments.len() - i - 1; + if let Some(ref args) = segment.args { + self.visit_segment_args(path.res, depth, args); + } + } + } + + fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) { + let output = match fd.output { + hir::DefaultReturn(_) => None, + hir::Return(ref ty) => Some(&**ty), + }; + self.visit_fn_like_elision(&fd.inputs, output); + } + + fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) { + check_mixed_explicit_and_in_band_defs(self.tcx, &generics.params); + for param in generics.params { + match param.kind { + GenericParamKind::Lifetime { .. } => {} + GenericParamKind::Type { ref default, .. } => { + walk_list!(self, visit_param_bound, param.bounds); + if let Some(ref ty) = default { + self.visit_ty(&ty); + } + } + GenericParamKind::Const { ref ty, .. } => { + walk_list!(self, visit_param_bound, param.bounds); + self.visit_ty(&ty); + } + } + } + for predicate in generics.where_clause.predicates { + match predicate { + &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { + ref bounded_ty, + bounds, + ref bound_generic_params, + .. + }) => { + let lifetimes: FxHashMap<_, _> = bound_generic_params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::late(&self.tcx.hir(), param)) + } + _ => None, + }) + .collect(); + if !lifetimes.is_empty() { + self.trait_ref_hack = true; + let next_early_index = self.next_early_index(); + let scope = Scope::Binder { + lifetimes, + s: self.scope, + next_early_index, + track_lifetime_uses: true, + opaque_type_parent: false, + }; + let result = self.with(scope, |old_scope, this| { + this.check_lifetime_params(old_scope, &bound_generic_params); + this.visit_ty(&bounded_ty); + walk_list!(this, visit_param_bound, bounds); + }); + self.trait_ref_hack = false; + result + } else { + self.visit_ty(&bounded_ty); + walk_list!(self, visit_param_bound, bounds); + } + } + &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { + ref lifetime, + bounds, + .. + }) => { + self.visit_lifetime(lifetime); + walk_list!(self, visit_param_bound, bounds); + } + &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { + ref lhs_ty, + ref rhs_ty, + .. + }) => { + self.visit_ty(lhs_ty); + self.visit_ty(rhs_ty); + } + } + } + } + + fn visit_poly_trait_ref( + &mut self, + trait_ref: &'tcx hir::PolyTraitRef<'tcx>, + _modifier: hir::TraitBoundModifier, + ) { + debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref); + + if !self.trait_ref_hack + || trait_ref.bound_generic_params.iter().any(|param| match param.kind { + GenericParamKind::Lifetime { .. } => true, + _ => false, + }) + { + if self.trait_ref_hack { + span_err!( + self.tcx.sess, + trait_ref.span, + E0316, + "nested quantification of lifetimes" + ); + } + let next_early_index = self.next_early_index(); + let scope = Scope::Binder { + lifetimes: trait_ref + .bound_generic_params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::late(&self.tcx.hir(), param)) + } + _ => None, + }) + .collect(), + s: self.scope, + next_early_index, + track_lifetime_uses: true, + opaque_type_parent: false, + }; + self.with(scope, |old_scope, this| { + this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params); + walk_list!(this, visit_generic_param, trait_ref.bound_generic_params); + this.visit_trait_ref(&trait_ref.trait_ref) + }) + } else { + self.visit_trait_ref(&trait_ref.trait_ref) + } + } +} + +#[derive(Copy, Clone, PartialEq)] +enum ShadowKind { + Label, + Lifetime, +} +struct Original { + kind: ShadowKind, + span: Span, +} +struct Shadower { + kind: ShadowKind, + span: Span, +} + +fn original_label(span: Span) -> Original { + Original { kind: ShadowKind::Label, span: span } +} +fn shadower_label(span: Span) -> Shadower { + Shadower { kind: ShadowKind::Label, span: span } +} +fn original_lifetime(span: Span) -> Original { + Original { kind: ShadowKind::Lifetime, span: span } +} +fn shadower_lifetime(param: &hir::GenericParam<'_>) -> Shadower { + Shadower { kind: ShadowKind::Lifetime, span: param.span } +} + +impl ShadowKind { + fn desc(&self) -> &'static str { + match *self { + ShadowKind::Label => "label", + ShadowKind::Lifetime => "lifetime", + } + } +} + +fn check_mixed_explicit_and_in_band_defs(tcx: TyCtxt<'_>, params: &[hir::GenericParam<'_>]) { + let lifetime_params: Vec<_> = params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { kind, .. } => Some((kind, param.span)), + _ => None, + }) + .collect(); + let explicit = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::Explicit); + let in_band = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::InBand); + + if let (Some((_, explicit_span)), Some((_, in_band_span))) = (explicit, in_band) { + struct_span_err!( + tcx.sess, + *in_band_span, + E0688, + "cannot mix in-band and explicit lifetime definitions" + ) + .span_label(*in_band_span, "in-band lifetime definition here") + .span_label(*explicit_span, "explicit lifetime definition here") + .emit(); + } +} + +fn signal_shadowing_problem(tcx: TyCtxt<'_>, name: ast::Name, orig: Original, shadower: Shadower) { + let mut err = if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) { + // lifetime/lifetime shadowing is an error + struct_span_err!( + tcx.sess, + shadower.span, + E0496, + "{} name `{}` shadows a \ + {} name that is already in scope", + shadower.kind.desc(), + name, + orig.kind.desc() + ) + } else { + // shadowing involving a label is only a warning, due to issues with + // labels and lifetimes not being macro-hygienic. + tcx.sess.struct_span_warn( + shadower.span, + &format!( + "{} name `{}` shadows a \ + {} name that is already in scope", + shadower.kind.desc(), + name, + orig.kind.desc() + ), + ) + }; + err.span_label(orig.span, "first declared here"); + err.span_label(shadower.span, format!("lifetime {} already in scope", name)); + err.emit(); +} + +// Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning +// if one of the label shadows a lifetime or another label. +fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body<'_>) { + struct GatherLabels<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + scope: ScopeRef<'a>, + labels_in_fn: &'a mut Vec, + } + + let mut gather = + GatherLabels { tcx: ctxt.tcx, scope: ctxt.scope, labels_in_fn: &mut ctxt.labels_in_fn }; + gather.visit_body(body); + + impl<'v, 'a, 'tcx> Visitor<'v> for GatherLabels<'a, 'tcx> { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> { + NestedVisitorMap::None + } + + fn visit_expr(&mut self, ex: &hir::Expr<'_>) { + if let Some(label) = expression_label(ex) { + for prior_label in &self.labels_in_fn[..] { + // FIXME (#24278): non-hygienic comparison + if label.name == prior_label.name { + signal_shadowing_problem( + self.tcx, + label.name, + original_label(prior_label.span), + shadower_label(label.span), + ); + } + } + + check_if_label_shadows_lifetime(self.tcx, self.scope, label); + + self.labels_in_fn.push(label); + } + intravisit::walk_expr(self, ex) + } + } + + fn expression_label(ex: &hir::Expr<'_>) -> Option { + if let hir::ExprKind::Loop(_, Some(label), _) = ex.kind { Some(label.ident) } else { None } + } + + fn check_if_label_shadows_lifetime( + tcx: TyCtxt<'_>, + mut scope: ScopeRef<'_>, + label: ast::Ident, + ) { + loop { + match *scope { + Scope::Body { s, .. } + | Scope::Elision { s, .. } + | Scope::ObjectLifetimeDefault { s, .. } => { + scope = s; + } + + Scope::Root => { + return; + } + + Scope::Binder { ref lifetimes, s, .. } => { + // FIXME (#24278): non-hygienic comparison + if let Some(def) = lifetimes.get(&hir::ParamName::Plain(label.modern())) { + let hir_id = tcx.hir().as_local_hir_id(def.id().unwrap()).unwrap(); + + signal_shadowing_problem( + tcx, + label.name, + original_lifetime(tcx.hir().span(hir_id)), + shadower_label(label.span), + ); + return; + } + scope = s; + } + } + } + } +} + +fn compute_object_lifetime_defaults(tcx: TyCtxt<'_>) -> HirIdMap> { + let mut map = HirIdMap::default(); + for item in tcx.hir().krate().items.values() { + match item.kind { + hir::ItemKind::Struct(_, ref generics) + | hir::ItemKind::Union(_, ref generics) + | hir::ItemKind::Enum(_, ref generics) + | hir::ItemKind::OpaqueTy(hir::OpaqueTy { + ref generics, impl_trait_fn: None, .. + }) + | hir::ItemKind::TyAlias(_, ref generics) + | hir::ItemKind::Trait(_, _, ref generics, ..) => { + let result = object_lifetime_defaults_for_item(tcx, generics); + + // Debugging aid. + if attr::contains_name(&item.attrs, sym::rustc_object_lifetime_default) { + let object_lifetime_default_reprs: String = result + .iter() + .map(|set| match *set { + Set1::Empty => "BaseDefault".into(), + Set1::One(Region::Static) => "'static".into(), + Set1::One(Region::EarlyBound(mut i, _, _)) => generics + .params + .iter() + .find_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + if i == 0 { + return Some(param.name.ident().to_string().into()); + } + i -= 1; + None + } + _ => None, + }) + .unwrap(), + Set1::One(_) => bug!(), + Set1::Many => "Ambiguous".into(), + }) + .collect::>>() + .join(","); + tcx.sess.span_err(item.span, &object_lifetime_default_reprs); + } + + map.insert(item.hir_id, result); + } + _ => {} + } + } + map +} + +/// Scan the bounds and where-clauses on parameters to extract bounds +/// of the form `T:'a` so as to determine the `ObjectLifetimeDefault` +/// for each type parameter. +fn object_lifetime_defaults_for_item( + tcx: TyCtxt<'_>, + generics: &hir::Generics<'_>, +) -> Vec { + fn add_bounds(set: &mut Set1, bounds: &[hir::GenericBound<'_>]) { + for bound in bounds { + if let hir::GenericBound::Outlives(ref lifetime) = *bound { + set.insert(lifetime.name.modern()); + } + } + } + + generics + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => None, + GenericParamKind::Type { .. } => { + let mut set = Set1::Empty; + + add_bounds(&mut set, ¶m.bounds); + + let param_def_id = tcx.hir().local_def_id(param.hir_id); + for predicate in generics.where_clause.predicates { + // Look for `type: ...` where clauses. + let data = match *predicate { + hir::WherePredicate::BoundPredicate(ref data) => data, + _ => continue, + }; + + // Ignore `for<'a> type: ...` as they can change what + // lifetimes mean (although we could "just" handle it). + if !data.bound_generic_params.is_empty() { + continue; + } + + let res = match data.bounded_ty.kind { + hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => path.res, + _ => continue, + }; + + if res == Res::Def(DefKind::TyParam, param_def_id) { + add_bounds(&mut set, &data.bounds); + } + } + + Some(match set { + Set1::Empty => Set1::Empty, + Set1::One(name) => { + if name == hir::LifetimeName::Static { + Set1::One(Region::Static) + } else { + generics + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => Some(( + param.hir_id, + hir::LifetimeName::Param(param.name), + LifetimeDefOrigin::from_param(param), + )), + _ => None, + }) + .enumerate() + .find(|&(_, (_, lt_name, _))| lt_name == name) + .map_or(Set1::Many, |(i, (id, _, origin))| { + let def_id = tcx.hir().local_def_id(id); + Set1::One(Region::EarlyBound(i as u32, def_id, origin)) + }) + } + } + Set1::Many => Set1::Many, + }) + } + GenericParamKind::Const { .. } => { + // Generic consts don't impose any constraints. + None + } + }) + .collect() +} + +impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { + // FIXME(#37666) this works around a limitation in the region inferencer + fn hack(&mut self, f: F) + where + F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>), + { + f(self) + } + + fn with(&mut self, wrap_scope: Scope<'_>, f: F) + where + F: for<'b> FnOnce(ScopeRef<'_>, &mut LifetimeContext<'b, 'tcx>), + { + let LifetimeContext { tcx, map, lifetime_uses, .. } = self; + let labels_in_fn = take(&mut self.labels_in_fn); + let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults); + let mut this = LifetimeContext { + tcx: *tcx, + map: map, + scope: &wrap_scope, + trait_ref_hack: self.trait_ref_hack, + is_in_fn_syntax: self.is_in_fn_syntax, + labels_in_fn, + xcrate_object_lifetime_defaults, + lifetime_uses: lifetime_uses, + }; + debug!("entering scope {:?}", this.scope); + f(self.scope, &mut this); + this.check_uses_for_lifetimes_defined_by_scope(); + debug!("exiting scope {:?}", this.scope); + self.labels_in_fn = this.labels_in_fn; + self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults; + } + + /// helper method to determine the span to remove when suggesting the + /// deletion of a lifetime + fn lifetime_deletion_span( + &self, + name: ast::Ident, + generics: &hir::Generics<'_>, + ) -> Option { + generics.params.iter().enumerate().find_map(|(i, param)| { + if param.name.ident() == name { + let mut in_band = false; + if let hir::GenericParamKind::Lifetime { kind } = param.kind { + if let hir::LifetimeParamKind::InBand = kind { + in_band = true; + } + } + if in_band { + Some(param.span) + } else { + if generics.params.len() == 1 { + // if sole lifetime, remove the entire `<>` brackets + Some(generics.span) + } else { + // if removing within `<>` brackets, we also want to + // delete a leading or trailing comma as appropriate + if i >= generics.params.len() - 1 { + Some(generics.params[i - 1].span.shrink_to_hi().to(param.span)) + } else { + Some(param.span.to(generics.params[i + 1].span.shrink_to_lo())) + } + } + } + } else { + None + } + }) + } + + // helper method to issue suggestions from `fn rah<'a>(&'a T)` to `fn rah(&T)` + // or from `fn rah<'a>(T<'a>)` to `fn rah(T<'_>)` + fn suggest_eliding_single_use_lifetime( + &self, + err: &mut DiagnosticBuilder<'_>, + def_id: DefId, + lifetime: &hir::Lifetime, + ) { + let name = lifetime.name.ident(); + let mut remove_decl = None; + if let Some(parent_def_id) = self.tcx.parent(def_id) { + if let Some(generics) = self.tcx.hir().get_generics(parent_def_id) { + remove_decl = self.lifetime_deletion_span(name, generics); + } + } + + let mut remove_use = None; + let mut elide_use = None; + let mut find_arg_use_span = |inputs: &[hir::Ty<'_>]| { + for input in inputs { + match input.kind { + hir::TyKind::Rptr(lt, _) => { + if lt.name.ident() == name { + // include the trailing whitespace between the lifetime and type names + let lt_through_ty_span = lifetime.span.to(input.span.shrink_to_hi()); + remove_use = Some( + self.tcx + .sess + .source_map() + .span_until_non_whitespace(lt_through_ty_span), + ); + break; + } + } + hir::TyKind::Path(ref qpath) => { + if let QPath::Resolved(_, path) = qpath { + let last_segment = &path.segments[path.segments.len() - 1]; + let generics = last_segment.generic_args(); + for arg in generics.args.iter() { + if let GenericArg::Lifetime(lt) = arg { + if lt.name.ident() == name { + elide_use = Some(lt.span); + break; + } + } + } + break; + } + } + _ => {} + } + } + }; + if let Node::Lifetime(hir_lifetime) = self.tcx.hir().get(lifetime.hir_id) { + if let Some(parent) = + self.tcx.hir().find(self.tcx.hir().get_parent_item(hir_lifetime.hir_id)) + { + match parent { + Node::Item(item) => { + if let hir::ItemKind::Fn(sig, _, _) = &item.kind { + find_arg_use_span(sig.decl.inputs); + } + } + Node::ImplItem(impl_item) => { + if let hir::ImplItemKind::Method(sig, _) = &impl_item.kind { + find_arg_use_span(sig.decl.inputs); + } + } + _ => {} + } + } + } + + let msg = "elide the single-use lifetime"; + match (remove_decl, remove_use, elide_use) { + (Some(decl_span), Some(use_span), None) => { + // if both declaration and use deletion spans start at the same + // place ("start at" because the latter includes trailing + // whitespace), then this is an in-band lifetime + if decl_span.shrink_to_lo() == use_span.shrink_to_lo() { + err.span_suggestion( + use_span, + msg, + String::new(), + Applicability::MachineApplicable, + ); + } else { + err.multipart_suggestion( + msg, + vec![(decl_span, String::new()), (use_span, String::new())], + Applicability::MachineApplicable, + ); + } + } + (Some(decl_span), None, Some(use_span)) => { + err.multipart_suggestion( + msg, + vec![(decl_span, String::new()), (use_span, "'_".to_owned())], + Applicability::MachineApplicable, + ); + } + _ => {} + } + } + + fn check_uses_for_lifetimes_defined_by_scope(&mut self) { + let defined_by = match self.scope { + Scope::Binder { lifetimes, .. } => lifetimes, + _ => { + debug!("check_uses_for_lifetimes_defined_by_scope: not in a binder scope"); + return; + } + }; + + let mut def_ids: Vec<_> = defined_by + .values() + .flat_map(|region| match region { + Region::EarlyBound(_, def_id, _) + | Region::LateBound(_, def_id, _) + | Region::Free(_, def_id) => Some(*def_id), + + Region::LateBoundAnon(..) | Region::Static => None, + }) + .collect(); + + // ensure that we issue lints in a repeatable order + def_ids.sort_by_cached_key(|&def_id| self.tcx.def_path_hash(def_id)); + + for def_id in def_ids { + debug!("check_uses_for_lifetimes_defined_by_scope: def_id = {:?}", def_id); + + let lifetimeuseset = self.lifetime_uses.remove(&def_id); + + debug!( + "check_uses_for_lifetimes_defined_by_scope: lifetimeuseset = {:?}", + lifetimeuseset + ); + + match lifetimeuseset { + Some(LifetimeUseSet::One(lifetime)) => { + let hir_id = self.tcx.hir().as_local_hir_id(def_id).unwrap(); + debug!("hir id first={:?}", hir_id); + if let Some((id, span, name)) = match self.tcx.hir().get(hir_id) { + Node::Lifetime(hir_lifetime) => Some(( + hir_lifetime.hir_id, + hir_lifetime.span, + hir_lifetime.name.ident(), + )), + Node::GenericParam(param) => { + Some((param.hir_id, param.span, param.name.ident())) + } + _ => None, + } { + debug!("id = {:?} span = {:?} name = {:?}", id, span, name); + if name.name == kw::UnderscoreLifetime { + continue; + } + + if let Some(parent_def_id) = self.tcx.parent(def_id) { + if let Some(parent_hir_id) = + self.tcx.hir().as_local_hir_id(parent_def_id) + { + // lifetimes in `derive` expansions don't count (Issue #53738) + if self + .tcx + .hir() + .attrs(parent_hir_id) + .iter() + .any(|attr| attr.check_name(sym::automatically_derived)) + { + continue; + } + } + } + + let mut err = self.tcx.struct_span_lint_hir( + lint::builtin::SINGLE_USE_LIFETIMES, + id, + span, + &format!("lifetime parameter `{}` only used once", name), + ); + + if span == lifetime.span { + // spans are the same for in-band lifetime declarations + err.span_label(span, "this lifetime is only used here"); + } else { + err.span_label(span, "this lifetime..."); + err.span_label(lifetime.span, "...is used only here"); + } + self.suggest_eliding_single_use_lifetime(&mut err, def_id, lifetime); + err.emit(); + } + } + Some(LifetimeUseSet::Many) => { + debug!("not one use lifetime"); + } + None => { + let hir_id = self.tcx.hir().as_local_hir_id(def_id).unwrap(); + if let Some((id, span, name)) = match self.tcx.hir().get(hir_id) { + Node::Lifetime(hir_lifetime) => Some(( + hir_lifetime.hir_id, + hir_lifetime.span, + hir_lifetime.name.ident(), + )), + Node::GenericParam(param) => { + Some((param.hir_id, param.span, param.name.ident())) + } + _ => None, + } { + debug!("id ={:?} span = {:?} name = {:?}", id, span, name); + let mut err = self.tcx.struct_span_lint_hir( + lint::builtin::UNUSED_LIFETIMES, + id, + span, + &format!("lifetime parameter `{}` never used", name), + ); + if let Some(parent_def_id) = self.tcx.parent(def_id) { + if let Some(generics) = self.tcx.hir().get_generics(parent_def_id) { + let unused_lt_span = self.lifetime_deletion_span(name, generics); + if let Some(span) = unused_lt_span { + err.span_suggestion( + span, + "elide the unused lifetime", + String::new(), + Applicability::MachineApplicable, + ); + } + } + } + err.emit(); + } + } + } + } + } + + /// Visits self by adding a scope and handling recursive walk over the contents with `walk`. + /// + /// Handles visiting fns and methods. These are a bit complicated because we must distinguish + /// early- vs late-bound lifetime parameters. We do this by checking which lifetimes appear + /// within type bounds; those are early bound lifetimes, and the rest are late bound. + /// + /// For example: + /// + /// fn foo<'a,'b,'c,T:Trait<'b>>(...) + /// + /// Here `'a` and `'c` are late bound but `'b` is early bound. Note that early- and late-bound + /// lifetimes may be interspersed together. + /// + /// If early bound lifetimes are present, we separate them into their own list (and likewise + /// for late bound). They will be numbered sequentially, starting from the lowest index that is + /// already in scope (for a fn item, that will be 0, but for a method it might not be). Late + /// bound lifetimes are resolved by name and associated with a binder ID (`binder_id`), so the + /// ordering is not important there. + fn visit_early_late( + &mut self, + parent_id: Option, + decl: &'tcx hir::FnDecl<'tcx>, + generics: &'tcx hir::Generics<'tcx>, + walk: F, + ) where + F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>), + { + insert_late_bound_lifetimes(self.map, decl, generics); + + // Find the start of nested early scopes, e.g., in methods. + let mut index = 0; + if let Some(parent_id) = parent_id { + let parent = self.tcx.hir().expect_item(parent_id); + if sub_items_have_self_param(&parent.kind) { + index += 1; // Self comes before lifetimes + } + match parent.kind { + hir::ItemKind::Trait(_, _, ref generics, ..) + | hir::ItemKind::Impl(_, _, _, ref generics, ..) => { + index += generics.params.len() as u32; + } + _ => {} + } + } + + let mut non_lifetime_count = 0; + let lifetimes = generics + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + if self.map.late_bound.contains(¶m.hir_id) { + Some(Region::late(&self.tcx.hir(), param)) + } else { + Some(Region::early(&self.tcx.hir(), &mut index, param)) + } + } + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { + non_lifetime_count += 1; + None + } + }) + .collect(); + let next_early_index = index + non_lifetime_count; + + let scope = Scope::Binder { + lifetimes, + next_early_index, + s: self.scope, + opaque_type_parent: true, + track_lifetime_uses: false, + }; + self.with(scope, move |old_scope, this| { + this.check_lifetime_params(old_scope, &generics.params); + this.hack(walk); // FIXME(#37666) workaround in place of `walk(this)` + }); + } + + fn next_early_index_helper(&self, only_opaque_type_parent: bool) -> u32 { + let mut scope = self.scope; + loop { + match *scope { + Scope::Root => return 0, + + Scope::Binder { next_early_index, opaque_type_parent, .. } + if (!only_opaque_type_parent || opaque_type_parent) => + { + return next_early_index; + } + + 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 opaque type alias `impl Trait`. This will be the + /// next early index from the enclosing item, for the most + /// part. See the `opaque_type_parent` field for more info. + fn next_early_index_for_opaque_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); + + // If we've already reported an error, just ignore `lifetime_ref`. + if let LifetimeName::Error = lifetime_ref.name { + return; + } + + // Walk up the scope chain, tracking the number of fn scopes + // that we pass through, until we find a lifetime with the + // given name or we run out of scopes. + // search. + let mut late_depth = 0; + let mut scope = self.scope; + let mut outermost_body = None; + let result = loop { + match *scope { + Scope::Body { id, s } => { + outermost_body = Some(id); + scope = s; + } + + Scope::Root => { + break None; + } + + Scope::Binder { ref lifetimes, s, .. } => { + match lifetime_ref.name { + LifetimeName::Param(param_name) => { + if let Some(&def) = lifetimes.get(¶m_name.modern()) { + break Some(def.shifted(late_depth)); + } + } + _ => bug!("expected LifetimeName::Param"), + } + + late_depth += 1; + scope = s; + } + + Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } => { + scope = s; + } + } + }; + + if let Some(mut def) = result { + if let Region::EarlyBound(..) = def { + // Do not free early-bound regions, only late-bound ones. + } else if let Some(body_id) = outermost_body { + let fn_id = self.tcx.hir().body_owner(body_id); + match self.tcx.hir().get(fn_id) { + Node::Item(&hir::Item { kind: hir::ItemKind::Fn(..), .. }) + | Node::TraitItem(&hir::TraitItem { + kind: hir::TraitItemKind::Method(..), + .. + }) + | Node::ImplItem(&hir::ImplItem { + kind: hir::ImplItemKind::Method(..), .. + }) => { + let scope = self.tcx.hir().local_def_id(fn_id); + def = Region::Free(scope, def.id().unwrap()); + } + _ => {} + } + } + + // Check for fn-syntax conflicts with in-band lifetime definitions + if self.is_in_fn_syntax { + match def { + Region::EarlyBound(_, _, LifetimeDefOrigin::InBand) + | Region::LateBound(_, _, LifetimeDefOrigin::InBand) => { + struct_span_err!( + self.tcx.sess, + lifetime_ref.span, + E0687, + "lifetimes used in `fn` or `Fn` syntax must be \ + explicitly declared using `<...>` binders" + ) + .span_label(lifetime_ref.span, "in-band lifetime definition") + .emit(); + } + + Region::Static + | Region::EarlyBound(_, _, LifetimeDefOrigin::ExplicitOrElided) + | Region::LateBound(_, _, LifetimeDefOrigin::ExplicitOrElided) + | Region::EarlyBound(_, _, LifetimeDefOrigin::Error) + | Region::LateBound(_, _, LifetimeDefOrigin::Error) + | Region::LateBoundAnon(..) + | Region::Free(..) => {} + } + } + + self.insert_lifetime(lifetime_ref, def); + } else { + struct_span_err!( + self.tcx.sess, + lifetime_ref.span, + E0261, + "use of undeclared lifetime name `{}`", + lifetime_ref + ) + .span_label(lifetime_ref.span, "undeclared lifetime") + .emit(); + } + } + + fn visit_segment_args( + &mut self, + res: Res, + depth: usize, + generic_args: &'tcx hir::GenericArgs<'tcx>, + ) { + debug!( + "visit_segment_args(res={:?}, depth={:?}, generic_args={:?})", + res, depth, generic_args, + ); + + if generic_args.parenthesized { + let was_in_fn_syntax = self.is_in_fn_syntax; + self.is_in_fn_syntax = true; + self.visit_fn_like_elision(generic_args.inputs(), Some(generic_args.bindings[0].ty())); + self.is_in_fn_syntax = was_in_fn_syntax; + return; + } + + let mut elide_lifetimes = true; + let lifetimes = generic_args + .args + .iter() + .filter_map(|arg| match arg { + hir::GenericArg::Lifetime(lt) => { + if !lt.is_elided() { + elide_lifetimes = false; + } + Some(lt) + } + _ => None, + }) + .collect(); + if elide_lifetimes { + self.resolve_elided_lifetimes(lifetimes); + } else { + lifetimes.iter().for_each(|lt| self.visit_lifetime(lt)); + } + + // Figure out if this is a type/trait segment, + // which requires object lifetime defaults. + let parent_def_id = |this: &mut Self, def_id: DefId| { + let def_key = this.tcx.def_key(def_id); + DefId { krate: def_id.krate, index: def_key.parent.expect("missing parent") } + }; + let type_def_id = match res { + Res::Def(DefKind::AssocTy, def_id) if depth == 1 => Some(parent_def_id(self, def_id)), + Res::Def(DefKind::Variant, def_id) if depth == 0 => Some(parent_def_id(self, def_id)), + Res::Def(DefKind::Struct, def_id) + | Res::Def(DefKind::Union, def_id) + | Res::Def(DefKind::Enum, def_id) + | Res::Def(DefKind::TyAlias, def_id) + | Res::Def(DefKind::Trait, def_id) + if depth == 0 => + { + Some(def_id) + } + _ => None, + }; + + debug!("visit_segment_args: type_def_id={:?}", type_def_id); + + // Compute a vector of defaults, one for each type parameter, + // per the rules given in RFCs 599 and 1156. Example: + // + // ```rust + // struct Foo<'a, T: 'a, U> { } + // ``` + // + // If you have `Foo<'x, dyn Bar, dyn Baz>`, we want to default + // `dyn Bar` to `dyn Bar + 'x` (because of the `T: 'a` bound) + // and `dyn Baz` to `dyn Baz + 'static` (because there is no + // such bound). + // + // Therefore, we would compute `object_lifetime_defaults` to a + // vector like `['x, 'static]`. Note that the vector only + // includes type parameters. + let object_lifetime_defaults = type_def_id.map_or(vec![], |def_id| { + let in_body = { + let mut scope = self.scope; + loop { + match *scope { + Scope::Root => break false, + + Scope::Body { .. } => break true, + + Scope::Binder { s, .. } + | Scope::Elision { s, .. } + | Scope::ObjectLifetimeDefault { s, .. } => { + scope = s; + } + } + } + }; + + let map = &self.map; + let unsubst = if let Some(id) = self.tcx.hir().as_local_hir_id(def_id) { + &map.object_lifetime_defaults[&id] + } else { + let tcx = self.tcx; + self.xcrate_object_lifetime_defaults.entry(def_id).or_insert_with(|| { + tcx.generics_of(def_id) + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamDefKind::Type { object_lifetime_default, .. } => { + Some(object_lifetime_default) + } + GenericParamDefKind::Lifetime | GenericParamDefKind::Const => None, + }) + .collect() + }) + }; + debug!("visit_segment_args: unsubst={:?}", unsubst); + unsubst + .iter() + .map(|set| match *set { + Set1::Empty => { + if in_body { + None + } else { + Some(Region::Static) + } + } + Set1::One(r) => { + let lifetimes = generic_args.args.iter().filter_map(|arg| match arg { + GenericArg::Lifetime(lt) => Some(lt), + _ => None, + }); + r.subst(lifetimes, map) + } + Set1::Many => None, + }) + .collect() + }); + + debug!("visit_segment_args: object_lifetime_defaults={:?}", object_lifetime_defaults); + + let mut i = 0; + for arg in generic_args.args { + match arg { + GenericArg::Lifetime(_) => {} + GenericArg::Type(ty) => { + if let Some(<) = object_lifetime_defaults.get(i) { + let scope = Scope::ObjectLifetimeDefault { lifetime: lt, s: self.scope }; + self.with(scope, |_, this| this.visit_ty(ty)); + } else { + self.visit_ty(ty); + } + i += 1; + } + GenericArg::Const(ct) => { + self.visit_anon_const(&ct.value); + } + } + } + + // Hack: when resolving the type `XX` in binding like `dyn + // Foo<'b, Item = XX>`, the current object-lifetime default + // would be to examine the trait `Foo` to check whether it has + // a lifetime bound declared on `Item`. e.g., if `Foo` is + // declared like so, then the default object lifetime bound in + // `XX` should be `'b`: + // + // ```rust + // trait Foo<'a> { + // type Item: 'a; + // } + // ``` + // + // but if we just have `type Item;`, then it would be + // `'static`. However, we don't get all of this logic correct. + // + // Instead, we do something hacky: if there are no lifetime parameters + // to the trait, then we simply use a default object lifetime + // bound of `'static`, because there is no other possibility. On the other hand, + // if there ARE lifetime parameters, then we require the user to give an + // explicit bound for now. + // + // This is intended to leave room for us to implement the + // correct behavior in the future. + let has_lifetime_parameter = generic_args.args.iter().any(|arg| match arg { + GenericArg::Lifetime(_) => true, + _ => false, + }); + + // Resolve lifetimes found in the type `XX` from `Item = XX` bindings. + for b in generic_args.bindings { + let scope = Scope::ObjectLifetimeDefault { + lifetime: if has_lifetime_parameter { None } else { Some(Region::Static) }, + s: self.scope, + }; + self.with(scope, |_, this| this.visit_assoc_type_binding(b)); + } + } + + fn visit_fn_like_elision( + &mut self, + inputs: &'tcx [hir::Ty<'tcx>], + output: Option<&'tcx hir::Ty<'tcx>>, + ) { + debug!("visit_fn_like_elision: enter"); + let mut arg_elide = Elide::FreshLateAnon(Cell::new(0)); + let arg_scope = Scope::Elision { elide: arg_elide.clone(), s: self.scope }; + self.with(arg_scope, |_, this| { + for input in inputs { + this.visit_ty(input); + } + match *this.scope { + Scope::Elision { ref elide, .. } => { + arg_elide = elide.clone(); + } + _ => bug!(), + } + }); + + let output = match output { + Some(ty) => ty, + None => return, + }; + + debug!("visit_fn_like_elision: determine output"); + + // Figure out if there's a body we can get argument names from, + // and whether there's a `self` argument (treated specially). + let mut assoc_item_kind = None; + let mut impl_self = None; + let parent = self.tcx.hir().get_parent_node(output.hir_id); + let body = match self.tcx.hir().get(parent) { + // `fn` definitions and methods. + Node::Item(&hir::Item { kind: hir::ItemKind::Fn(.., body), .. }) => Some(body), + + Node::TraitItem(&hir::TraitItem { + kind: hir::TraitItemKind::Method(_, ref m), .. + }) => { + if let hir::ItemKind::Trait(.., ref trait_items) = + self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind + { + assoc_item_kind = + trait_items.iter().find(|ti| ti.id.hir_id == parent).map(|ti| ti.kind); + } + match *m { + hir::TraitMethod::Required(_) => None, + hir::TraitMethod::Provided(body) => Some(body), + } + } + + Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Method(_, body), .. }) => { + if let hir::ItemKind::Impl(.., ref self_ty, ref impl_items) = + self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind + { + impl_self = Some(self_ty); + assoc_item_kind = + impl_items.iter().find(|ii| ii.id.hir_id == parent).map(|ii| ii.kind); + } + Some(body) + } + + // Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds). + Node::ForeignItem(_) | Node::Ty(_) | Node::TraitRef(_) => None, + // Everything else (only closures?) doesn't + // actually enjoy elision in return types. + _ => { + self.visit_ty(output); + return; + } + }; + + let has_self = match assoc_item_kind { + Some(hir::AssocItemKind::Method { has_self }) => has_self, + _ => false, + }; + + // In accordance with the rules for lifetime elision, we can determine + // what region to use for elision in the output type in two ways. + // First (determined here), if `self` is by-reference, then the + // implied output region is the region of the self parameter. + if has_self { + struct SelfVisitor<'a> { + map: &'a NamedRegionMap, + impl_self: Option<&'a hir::TyKind<'a>>, + lifetime: Set1, + } + + impl SelfVisitor<'_> { + // Look for `self: &'a Self` - also desugared from `&'a self`, + // and if that matches, use it for elision and return early. + fn is_self_ty(&self, res: Res) -> bool { + if let Res::SelfTy(..) = res { + return true; + } + + // Can't always rely on literal (or implied) `Self` due + // to the way elision rules were originally specified. + if let Some(&hir::TyKind::Path(hir::QPath::Resolved(None, ref path))) = + self.impl_self + { + match path.res { + // Whitelist the types that unambiguously always + // result in the same type constructor being used + // (it can't differ between `Self` and `self`). + Res::Def(DefKind::Struct, _) + | Res::Def(DefKind::Union, _) + | Res::Def(DefKind::Enum, _) + | Res::PrimTy(_) => return res == path.res, + _ => {} + } + } + + false + } + } + + impl<'a> Visitor<'a> for SelfVisitor<'a> { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'a> { + NestedVisitorMap::None + } + + fn visit_ty(&mut self, ty: &'a hir::Ty<'a>) { + if let hir::TyKind::Rptr(lifetime_ref, ref mt) = ty.kind { + if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = mt.ty.kind + { + if self.is_self_ty(path.res) { + if let Some(lifetime) = self.map.defs.get(&lifetime_ref.hir_id) { + self.lifetime.insert(*lifetime); + } + } + } + } + intravisit::walk_ty(self, ty) + } + } + + let mut visitor = SelfVisitor { + map: self.map, + impl_self: impl_self.map(|ty| &ty.kind), + lifetime: Set1::Empty, + }; + visitor.visit_ty(&inputs[0]); + if let Set1::One(lifetime) = visitor.lifetime { + let scope = Scope::Elision { elide: Elide::Exact(lifetime), s: self.scope }; + self.with(scope, |_, this| this.visit_ty(output)); + return; + } + } + + // Second, if there was exactly one lifetime (either a substitution or a + // reference) in the arguments, then any anonymous regions in the output + // have that lifetime. + let mut possible_implied_output_region = None; + let mut lifetime_count = 0; + let arg_lifetimes = inputs + .iter() + .enumerate() + .skip(has_self as usize) + .map(|(i, input)| { + let mut gather = GatherLifetimes { + map: self.map, + outer_index: ty::INNERMOST, + have_bound_regions: false, + lifetimes: Default::default(), + }; + gather.visit_ty(input); + + lifetime_count += gather.lifetimes.len(); + + if lifetime_count == 1 && gather.lifetimes.len() == 1 { + // there's a chance that the unique lifetime of this + // iteration will be the appropriate lifetime for output + // parameters, so lets store it. + possible_implied_output_region = gather.lifetimes.iter().cloned().next(); + } + + ElisionFailureInfo { + parent: body, + index: i, + lifetime_count: gather.lifetimes.len(), + have_bound_regions: gather.have_bound_regions, + } + }) + .collect(); + + let elide = if lifetime_count == 1 { + Elide::Exact(possible_implied_output_region.unwrap()) + } else { + Elide::Error(arg_lifetimes) + }; + + debug!("visit_fn_like_elision: elide={:?}", elide); + + let scope = Scope::Elision { elide, s: self.scope }; + self.with(scope, |_, this| this.visit_ty(output)); + debug!("visit_fn_like_elision: exit"); + + struct GatherLifetimes<'a> { + map: &'a NamedRegionMap, + outer_index: ty::DebruijnIndex, + have_bound_regions: bool, + lifetimes: FxHashSet, + } + + impl<'v, 'a> Visitor<'v> for GatherLifetimes<'a> { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> { + NestedVisitorMap::None + } + + fn visit_ty(&mut self, ty: &hir::Ty<'_>) { + if let hir::TyKind::BareFn(_) = ty.kind { + self.outer_index.shift_in(1); + } + match ty.kind { + hir::TyKind::TraitObject(bounds, ref lifetime) => { + for bound in bounds { + self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); + } + + // Stay on the safe side and don't include the object + // lifetime default (which may not end up being used). + if !lifetime.is_elided() { + self.visit_lifetime(lifetime); + } + } + _ => { + intravisit::walk_ty(self, ty); + } + } + if let hir::TyKind::BareFn(_) = ty.kind { + self.outer_index.shift_out(1); + } + } + + fn visit_generic_param(&mut self, param: &hir::GenericParam<'_>) { + if let hir::GenericParamKind::Lifetime { .. } = param.kind { + // FIXME(eddyb) Do we want this? It only makes a difference + // if this `for<'a>` lifetime parameter is never used. + self.have_bound_regions = true; + } + + intravisit::walk_generic_param(self, param); + } + + fn visit_poly_trait_ref( + &mut self, + trait_ref: &hir::PolyTraitRef<'_>, + modifier: hir::TraitBoundModifier, + ) { + self.outer_index.shift_in(1); + intravisit::walk_poly_trait_ref(self, trait_ref, modifier); + self.outer_index.shift_out(1); + } + + fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) { + if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.hir_id) { + match lifetime { + Region::LateBound(debruijn, _, _) | Region::LateBoundAnon(debruijn, _) + if debruijn < self.outer_index => + { + self.have_bound_regions = true; + } + _ => { + self.lifetimes.insert(lifetime.shifted_out_to_binder(self.outer_index)); + } + } + } + } + } + } + + fn resolve_elided_lifetimes(&mut self, lifetime_refs: Vec<&'tcx hir::Lifetime>) { + debug!("resolve_elided_lifetimes(lifetime_refs={:?})", lifetime_refs); + + if lifetime_refs.is_empty() { + return; + } + + let span = lifetime_refs[0].span; + let mut late_depth = 0; + let mut scope = self.scope; + let mut lifetime_names = FxHashSet::default(); + let error = loop { + match *scope { + // Do not assign any resolution, it will be inferred. + Scope::Body { .. } => return, + + Scope::Root => break None, + + Scope::Binder { s, ref lifetimes, .. } => { + // collect named lifetimes for suggestions + for name in lifetimes.keys() { + if let hir::ParamName::Plain(name) = name { + lifetime_names.insert(*name); + } + } + late_depth += 1; + scope = s; + } + + Scope::Elision { ref elide, ref s, .. } => { + let lifetime = match *elide { + Elide::FreshLateAnon(ref counter) => { + for lifetime_ref in lifetime_refs { + let lifetime = Region::late_anon(counter).shifted(late_depth); + self.insert_lifetime(lifetime_ref, lifetime); + } + return; + } + Elide::Exact(l) => l.shifted(late_depth), + Elide::Error(ref e) => { + if let Scope::Binder { ref lifetimes, .. } = s { + // collect named lifetimes for suggestions + for name in lifetimes.keys() { + if let hir::ParamName::Plain(name) = name { + lifetime_names.insert(*name); + } + } + } + break Some(e); + } + }; + for lifetime_ref in lifetime_refs { + self.insert_lifetime(lifetime_ref, lifetime); + } + return; + } + + Scope::ObjectLifetimeDefault { s, .. } => { + scope = s; + } + } + }; + + let mut err = report_missing_lifetime_specifiers(self.tcx.sess, span, lifetime_refs.len()); + let mut add_label = true; + + if let Some(params) = error { + if lifetime_refs.len() == 1 { + add_label = add_label && self.report_elision_failure(&mut err, params, span); + } + } + if add_label { + add_missing_lifetime_specifiers_label( + &mut err, + span, + lifetime_refs.len(), + &lifetime_names, + self.tcx.sess.source_map().span_to_snippet(span).ok().as_ref().map(|s| s.as_str()), + ); + } + + err.emit(); + } + + fn suggest_lifetime(&self, db: &mut DiagnosticBuilder<'_>, span: Span, msg: &str) -> bool { + match self.tcx.sess.source_map().span_to_snippet(span) { + Ok(ref snippet) => { + let (sugg, applicability) = if snippet == "&" { + ("&'static ".to_owned(), Applicability::MachineApplicable) + } else if snippet == "'_" { + ("'static".to_owned(), Applicability::MachineApplicable) + } else { + (format!("{} + 'static", snippet), Applicability::MaybeIncorrect) + }; + db.span_suggestion(span, msg, sugg, applicability); + false + } + Err(_) => { + db.help(msg); + true + } + } + } + + fn report_elision_failure( + &mut self, + db: &mut DiagnosticBuilder<'_>, + params: &[ElisionFailureInfo], + span: Span, + ) -> bool { + let mut m = String::new(); + let len = params.len(); + + let elided_params: Vec<_> = + params.iter().cloned().filter(|info| info.lifetime_count > 0).collect(); + + let elided_len = elided_params.len(); + + for (i, info) in elided_params.into_iter().enumerate() { + let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions } = info; + + let help_name = if let Some(ident) = + parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident()) + { + format!("`{}`", ident) + } else { + format!("argument {}", index + 1) + }; + + m.push_str( + &(if n == 1 { + help_name + } else { + format!( + "one of {}'s {} {}lifetimes", + help_name, + n, + if have_bound_regions { "free " } else { "" } + ) + })[..], + ); + + if elided_len == 2 && i == 0 { + m.push_str(" or "); + } else if i + 2 == elided_len { + m.push_str(", or "); + } else if i != elided_len - 1 { + m.push_str(", "); + } + } + + if len == 0 { + help!( + db, + "this function's return type contains a borrowed value, but \ + there is no value for it to be borrowed from" + ); + self.suggest_lifetime(db, span, "consider giving it a 'static lifetime") + } else if elided_len == 0 { + help!( + db, + "this function's return type contains a borrowed value with \ + an elided lifetime, but the lifetime cannot be derived from \ + the arguments" + ); + let msg = "consider giving it an explicit bounded or 'static lifetime"; + self.suggest_lifetime(db, span, msg) + } else if elided_len == 1 { + help!( + db, + "this function's return type contains a borrowed value, but \ + the signature does not say which {} it is borrowed from", + m + ); + true + } else { + help!( + db, + "this function's return type contains a borrowed value, but \ + the signature does not say whether it is borrowed from {}", + m + ); + true + } + } + + fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) { + debug!("resolve_object_lifetime_default(lifetime_ref={:?})", lifetime_ref); + let mut late_depth = 0; + let mut scope = self.scope; + let lifetime = loop { + match *scope { + Scope::Binder { s, .. } => { + late_depth += 1; + scope = s; + } + + Scope::Root | Scope::Elision { .. } => break Region::Static, + + Scope::Body { .. } | Scope::ObjectLifetimeDefault { lifetime: None, .. } => return, + + Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l, + } + }; + self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth)); + } + + fn check_lifetime_params( + &mut self, + old_scope: ScopeRef<'_>, + params: &'tcx [hir::GenericParam<'tcx>], + ) { + let lifetimes: Vec<_> = params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => Some((param, param.name.modern())), + _ => None, + }) + .collect(); + for (i, (lifetime_i, lifetime_i_name)) in lifetimes.iter().enumerate() { + if let hir::ParamName::Plain(_) = lifetime_i_name { + let name = lifetime_i_name.ident().name; + if name == kw::UnderscoreLifetime || name == kw::StaticLifetime { + let mut err = struct_span_err!( + self.tcx.sess, + lifetime_i.span, + E0262, + "invalid lifetime parameter name: `{}`", + lifetime_i.name.ident(), + ); + err.span_label( + lifetime_i.span, + format!("{} is a reserved lifetime name", name), + ); + err.emit(); + } + } + + // It is a hard error to shadow a lifetime within the same scope. + for (lifetime_j, lifetime_j_name) in lifetimes.iter().skip(i + 1) { + if lifetime_i_name == lifetime_j_name { + struct_span_err!( + self.tcx.sess, + lifetime_j.span, + E0263, + "lifetime name `{}` declared twice in the same scope", + lifetime_j.name.ident() + ) + .span_label(lifetime_j.span, "declared twice") + .span_label(lifetime_i.span, "previous declaration here") + .emit(); + } + } + + // It is a soft error to shadow a lifetime within a parent scope. + self.check_lifetime_param_for_shadowing(old_scope, &lifetime_i); + + for bound in lifetime_i.bounds { + match bound { + hir::GenericBound::Outlives(ref lt) => match lt.name { + hir::LifetimeName::Underscore => self.tcx.sess.delay_span_bug( + lt.span, + "use of `'_` in illegal place, but not caught by lowering", + ), + hir::LifetimeName::Static => { + self.insert_lifetime(lt, Region::Static); + self.tcx + .sess + .struct_span_warn( + lifetime_i.span.to(lt.span), + &format!( + "unnecessary lifetime parameter `{}`", + lifetime_i.name.ident(), + ), + ) + .help(&format!( + "you can use the `'static` lifetime directly, in place of `{}`", + lifetime_i.name.ident(), + )) + .emit(); + } + hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit => { + self.resolve_lifetime_ref(lt); + } + hir::LifetimeName::ImplicitObjectLifetimeDefault => { + self.tcx.sess.delay_span_bug( + lt.span, + "lowering generated `ImplicitObjectLifetimeDefault` \ + outside of an object type", + ) + } + hir::LifetimeName::Error => { + // No need to do anything, error already reported. + } + }, + _ => bug!(), + } + } + } + } + + fn check_lifetime_param_for_shadowing( + &self, + mut old_scope: ScopeRef<'_>, + param: &'tcx hir::GenericParam<'tcx>, + ) { + for label in &self.labels_in_fn { + // FIXME (#24278): non-hygienic comparison + if param.name.ident().name == label.name { + signal_shadowing_problem( + self.tcx, + label.name, + original_label(label.span), + shadower_lifetime(¶m), + ); + return; + } + } + + loop { + match *old_scope { + Scope::Body { s, .. } + | Scope::Elision { s, .. } + | Scope::ObjectLifetimeDefault { s, .. } => { + old_scope = s; + } + + Scope::Root => { + return; + } + + Scope::Binder { ref lifetimes, s, .. } => { + if let Some(&def) = lifetimes.get(¶m.name.modern()) { + let hir_id = self.tcx.hir().as_local_hir_id(def.id().unwrap()).unwrap(); + + signal_shadowing_problem( + self.tcx, + param.name.ident().name, + original_lifetime(self.tcx.hir().span(hir_id)), + shadower_lifetime(¶m), + ); + return; + } + + old_scope = s; + } + } + } + } + + /// Returns `true` if, in the current scope, replacing `'_` would be + /// equivalent to a single-use lifetime. + fn track_lifetime_uses(&self) -> bool { + let mut scope = self.scope; + loop { + match *scope { + Scope::Root => break false, + + // Inside of items, it depends on the kind of item. + Scope::Binder { track_lifetime_uses, .. } => break track_lifetime_uses, + + // Inside a body, `'_` will use an inference variable, + // should be fine. + Scope::Body { .. } => break true, + + // A lifetime only used in a fn argument could as well + // be replaced with `'_`, as that would generate a + // fresh name, too. + Scope::Elision { elide: Elide::FreshLateAnon(_), .. } => break true, + + // In the return type or other such place, `'_` is not + // going to make a fresh name, so we cannot + // necessarily replace a single-use lifetime with + // `'_`. + Scope::Elision { elide: Elide::Exact(_), .. } => break false, + Scope::Elision { elide: Elide::Error(_), .. } => break false, + + Scope::ObjectLifetimeDefault { s, .. } => scope = s, + } + } + } + + fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) { + if lifetime_ref.hir_id == hir::DUMMY_HIR_ID { + span_bug!( + lifetime_ref.span, + "lifetime reference not renumbered, \ + probably a bug in syntax::fold" + ); + } + + debug!( + "insert_lifetime: {} resolved to {:?} span={:?}", + self.tcx.hir().node_to_string(lifetime_ref.hir_id), + def, + self.tcx.sess.source_map().span_to_string(lifetime_ref.span) + ); + self.map.defs.insert(lifetime_ref.hir_id, def); + + match def { + 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, _) => { + // A lifetime declared by the user. + let track_lifetime_uses = self.track_lifetime_uses(); + debug!("insert_lifetime: track_lifetime_uses={}", track_lifetime_uses); + if track_lifetime_uses && !self.lifetime_uses.contains_key(&def_id) { + debug!("insert_lifetime: first use of {:?}", def_id); + self.lifetime_uses.insert(def_id, LifetimeUseSet::One(lifetime_ref)); + } else { + debug!("insert_lifetime: many uses of {:?}", def_id); + self.lifetime_uses.insert(def_id, LifetimeUseSet::Many); + } + } + } + } + + /// Sometimes we resolve a lifetime, but later find that it is an + /// error (esp. around impl trait). In that case, we remove the + /// entry into `map.defs` so as not to confuse later code. + fn uninsert_lifetime_on_error(&mut self, lifetime_ref: &'tcx hir::Lifetime, bad_def: Region) { + let old_value = self.map.defs.remove(&lifetime_ref.hir_id); + assert_eq!(old_value, Some(bad_def)); + } +} + +/// Detects late-bound lifetimes and inserts them into +/// `map.late_bound`. +/// +/// A region declared on a fn is **late-bound** if: +/// - it is constrained by an argument type; +/// - it does not appear in a where-clause. +/// +/// "Constrained" basically means that it appears in any type but +/// not amongst the inputs to a projection. In other words, `<&'a +/// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`. +fn insert_late_bound_lifetimes( + map: &mut NamedRegionMap, + decl: &hir::FnDecl<'_>, + generics: &hir::Generics<'_>, +) { + debug!("insert_late_bound_lifetimes(decl={:?}, generics={:?})", decl, generics); + + let mut constrained_by_input = ConstrainedCollector::default(); + for arg_ty in decl.inputs { + constrained_by_input.visit_ty(arg_ty); + } + + let mut appears_in_output = AllCollector::default(); + intravisit::walk_fn_ret_ty(&mut appears_in_output, &decl.output); + + debug!("insert_late_bound_lifetimes: constrained_by_input={:?}", constrained_by_input.regions); + + // Walk the lifetimes that appear in where clauses. + // + // Subtle point: because we disallow nested bindings, we can just + // ignore binders here and scrape up all names we see. + let mut appears_in_where_clause = AllCollector::default(); + appears_in_where_clause.visit_generics(generics); + + for param in generics.params { + if let hir::GenericParamKind::Lifetime { .. } = param.kind { + if !param.bounds.is_empty() { + // `'a: 'b` means both `'a` and `'b` are referenced + appears_in_where_clause + .regions + .insert(hir::LifetimeName::Param(param.name.modern())); + } + } + } + + debug!( + "insert_late_bound_lifetimes: appears_in_where_clause={:?}", + appears_in_where_clause.regions + ); + + // Late bound regions are those that: + // - appear in the inputs + // - do not appear in the where-clauses + // - are not implicitly captured by `impl Trait` + for param in generics.params { + match param.kind { + hir::GenericParamKind::Lifetime { .. } => { /* fall through */ } + + // Neither types nor consts are late-bound. + hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => continue, + } + + let lt_name = hir::LifetimeName::Param(param.name.modern()); + // appears in the where clauses? early-bound. + if appears_in_where_clause.regions.contains(<_name) { + continue; + } + + // does not appear in the inputs, but appears in the return type? early-bound. + if !constrained_by_input.regions.contains(<_name) + && appears_in_output.regions.contains(<_name) + { + continue; + } + + debug!( + "insert_late_bound_lifetimes: lifetime {:?} with id {:?} is late-bound", + param.name.ident(), + param.hir_id + ); + + let inserted = map.late_bound.insert(param.hir_id); + assert!(inserted, "visited lifetime {:?} twice", param.hir_id); + } + + return; + + #[derive(Default)] + struct ConstrainedCollector { + regions: FxHashSet, + } + + impl<'v> Visitor<'v> for ConstrainedCollector { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> { + NestedVisitorMap::None + } + + fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { + match ty.kind { + hir::TyKind::Path(hir::QPath::Resolved(Some(_), _)) + | hir::TyKind::Path(hir::QPath::TypeRelative(..)) => { + // ignore lifetimes appearing in associated type + // projections, as they are not *constrained* + // (defined above) + } + + hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => { + // consider only the lifetimes on the final + // segment; I am not sure it's even currently + // valid to have them elsewhere, but even if it + // is, those would be potentially inputs to + // projections + if let Some(last_segment) = path.segments.last() { + self.visit_path_segment(path.span, last_segment); + } + } + + _ => { + intravisit::walk_ty(self, ty); + } + } + } + + fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { + self.regions.insert(lifetime_ref.name.modern()); + } + } + + #[derive(Default)] + struct AllCollector { + regions: FxHashSet, + } + + impl<'v> Visitor<'v> for AllCollector { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> { + NestedVisitorMap::None + } + + fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { + self.regions.insert(lifetime_ref.name.modern()); + } + } +} + +fn report_missing_lifetime_specifiers( + sess: &Session, + span: Span, + count: usize, +) -> DiagnosticBuilder<'_> { + struct_span_err!(sess, span, E0106, "missing lifetime specifier{}", pluralize!(count)) +} + +fn add_missing_lifetime_specifiers_label( + err: &mut DiagnosticBuilder<'_>, + span: Span, + count: usize, + lifetime_names: &FxHashSet, + snippet: Option<&str>, +) { + if count > 1 { + err.span_label(span, format!("expected {} lifetime parameters", count)); + } else if let (1, Some(name), Some("&")) = + (lifetime_names.len(), lifetime_names.iter().next(), snippet) + { + err.span_suggestion( + span, + "consider using the named lifetime", + format!("&{} ", name), + Applicability::MaybeIncorrect, + ); + } else { + err.span_label(span, "expected lifetime parameter"); + } +}