diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 96db40cb95b97..d1ea76b392223 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -672,9 +672,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { LifetimeRes::Param { .. } => { (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit) } - LifetimeRes::Fresh { param, .. } => { - (hir::ParamName::Fresh(param), hir::LifetimeParamKind::Elided) - } + LifetimeRes::Fresh { .. } => (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided), LifetimeRes::Static | LifetimeRes::Error => return None, res => panic!( "Unexpected lifetime resolution {:?} for {:?} at {:?}", @@ -1576,10 +1574,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { (hir::ParamName::Plain(ident), LifetimeRes::Param { param, binder: fn_node_id }) } // Input lifetime like `'1`: - LifetimeRes::Fresh { param, .. } => ( - hir::ParamName::Fresh(outer_def_id), - LifetimeRes::Fresh { param, binder: fn_node_id }, - ), + LifetimeRes::Fresh { param, .. } => { + (hir::ParamName::Fresh, LifetimeRes::Fresh { param, binder: fn_node_id }) + } LifetimeRes::Static | LifetimeRes::Error => continue, res => { panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span) @@ -1749,7 +1746,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> hir::Lifetime { debug!(?self.captured_lifetimes); let name = match res { - LifetimeRes::Param { param, binder } => { + LifetimeRes::Param { mut param, binder } => { debug_assert_ne!(ident.name, kw::UnderscoreLifetime); let p_name = ParamName::Plain(ident); if let Some(LifetimeCaptureContext { parent_def_id, captures, binders_to_ignore }) = @@ -1757,10 +1754,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { && !binders_to_ignore.contains(&binder) { match captures.entry(param) { - Entry::Occupied(_) => {} + Entry::Occupied(o) => param = self.resolver.local_def_id(o.get().1), Entry::Vacant(v) => { let p_id = self.resolver.next_node_id(); - self.resolver.create_def( + let p_def_id = self.resolver.create_def( *parent_def_id, p_id, DefPathData::LifetimeNs(p_name.ident().name), @@ -1769,10 +1766,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ); v.insert((span, p_id, p_name, res)); + param = p_def_id; } } } - hir::LifetimeName::Param(p_name) + hir::LifetimeName::Param(param, p_name) } LifetimeRes::Fresh { mut param, binder } => { debug_assert_eq!(ident.name, kw::UnderscoreLifetime); @@ -1792,21 +1790,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span.with_parent(None), ); - let p_name = ParamName::Fresh(param); - v.insert((span, p_id, p_name, res)); + v.insert((span, p_id, ParamName::Fresh, res)); param = p_def_id; } } } - let p_name = ParamName::Fresh(param); - hir::LifetimeName::Param(p_name) + hir::LifetimeName::Param(param, ParamName::Fresh) } LifetimeRes::Anonymous { binder, elided } => { - let l_name = if elided { - hir::LifetimeName::Implicit - } else { - hir::LifetimeName::Underscore - }; if let Some(LifetimeCaptureContext { parent_def_id, captures, binders_to_ignore }) = &mut self.captured_lifetimes && !binders_to_ignore.contains(&binder) @@ -1819,11 +1810,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ExpnId::root(), span.with_parent(None), ); - let p_name = ParamName::Fresh(p_def_id); - captures.insert(p_def_id, (span, p_id, p_name, res)); - hir::LifetimeName::Param(p_name) + captures.insert(p_def_id, (span, p_id, ParamName::Fresh, res)); + hir::LifetimeName::Param(p_def_id, ParamName::Fresh) + } else if elided { + hir::LifetimeName::Implicit } else { - l_name + hir::LifetimeName::Underscore } } LifetimeRes::Static => hir::LifetimeName::Static, @@ -1831,6 +1823,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { res => panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span), }; debug!(?self.captured_lifetimes); + debug!(?name); hir::Lifetime { hir_id: self.lower_node_id(id), span: self.lower_span(span), name } } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index cb4b154d271a5..fcb6ae438fed9 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -567,14 +567,14 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let lifetime = self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?; match lifetime.name { - hir::LifetimeName::Param(hir::ParamName::Plain(_) | hir::ParamName::Error) + hir::LifetimeName::Param(_, hir::ParamName::Plain(_) | hir::ParamName::Error) | hir::LifetimeName::Error | hir::LifetimeName::Static => { let lifetime_span = lifetime.span; Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span)) } - hir::LifetimeName::Param(hir::ParamName::Fresh(_)) + hir::LifetimeName::Param(_, hir::ParamName::Fresh) | hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index dbe6fe6ea8402..b98d434111862 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -26,7 +26,7 @@ use rustc_target::spec::abi::Abi; use smallvec::SmallVec; use std::fmt; -#[derive(Copy, Clone, Encodable, HashStable_Generic)] +#[derive(Debug, Copy, Clone, Encodable, HashStable_Generic)] pub struct Lifetime { pub hir_id: HirId, pub span: Span, @@ -60,7 +60,7 @@ pub enum ParamName { /// ``` /// where `'f` is something like `Fresh(0)`. The indices are /// unique per impl, but not necessarily continuous. - Fresh(LocalDefId), + Fresh, /// Indicates an illegal name was given and an error has been /// reported (so we should squelch other derived errors). Occurs @@ -72,9 +72,7 @@ impl ParamName { pub fn ident(&self) -> Ident { match *self { ParamName::Plain(ident) => ident, - ParamName::Fresh(_) | ParamName::Error => { - Ident::with_dummy_span(kw::UnderscoreLifetime) - } + ParamName::Fresh | ParamName::Error => Ident::with_dummy_span(kw::UnderscoreLifetime), } } @@ -90,7 +88,7 @@ impl ParamName { #[derive(HashStable_Generic)] pub enum LifetimeName { /// User-given names or fresh (synthetic) names. - Param(ParamName), + Param(LocalDefId, ParamName), /// User wrote nothing (e.g., the lifetime in `&u32`). Implicit, @@ -127,7 +125,7 @@ impl LifetimeName { | LifetimeName::Error => Ident::empty(), LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime), LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime), - LifetimeName::Param(param_name) => param_name.ident(), + LifetimeName::Param(_, param_name) => param_name.ident(), } } @@ -136,9 +134,9 @@ impl LifetimeName { LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Implicit | LifetimeName::Underscore - | LifetimeName::Param(ParamName::Fresh(_)) + | LifetimeName::Param(_, ParamName::Fresh) | LifetimeName::Error => true, - LifetimeName::Static | LifetimeName::Param(_) => false, + LifetimeName::Static | LifetimeName::Param(..) => false, } } @@ -148,12 +146,12 @@ impl LifetimeName { | LifetimeName::Implicit | LifetimeName::Underscore => true, - // It might seem surprising that `Fresh(_)` counts as + // It might seem surprising that `Fresh` counts as // *not* elided -- but this is because, as far as the code - // in the compiler is concerned -- `Fresh(_)` variants act + // in the compiler is concerned -- `Fresh` variants act // equivalently to "some fresh name". They correspond to // early-bound regions on an impl, in other words. - LifetimeName::Error | LifetimeName::Param(_) | LifetimeName::Static => false, + LifetimeName::Error | LifetimeName::Param(..) | LifetimeName::Static => false, } } @@ -163,8 +161,8 @@ impl LifetimeName { pub fn normalize_to_macros_2_0(&self) -> LifetimeName { match *self { - LifetimeName::Param(param_name) => { - LifetimeName::Param(param_name.normalize_to_macros_2_0()) + LifetimeName::Param(def_id, param_name) => { + LifetimeName::Param(def_id, param_name.normalize_to_macros_2_0()) } lifetime_name => lifetime_name, } @@ -177,12 +175,6 @@ impl fmt::Display for Lifetime { } } -impl fmt::Debug for Lifetime { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "lifetime({}: {})", self.hir_id, self.name.ident()) - } -} - impl Lifetime { pub fn is_elided(&self) -> bool { self.name.is_elided() @@ -628,6 +620,16 @@ impl<'hir> Generics<'hir> { }) } + pub fn outlives_for_param( + &self, + param_def_id: LocalDefId, + ) -> impl Iterator> { + self.predicates.iter().filter_map(move |pred| match pred { + WherePredicate::RegionPredicate(rp) if rp.is_param_bound(param_def_id) => Some(rp), + _ => None, + }) + } + pub fn bounds_span_for_suggestions(&self, param_def_id: LocalDefId) -> Option { self.bounds_for_param(param_def_id).flat_map(|bp| bp.bounds.iter().rev()).find_map( |bound| { @@ -769,6 +771,16 @@ pub struct WhereRegionPredicate<'hir> { pub bounds: GenericBounds<'hir>, } +impl<'hir> WhereRegionPredicate<'hir> { + /// Returns `true` if `param_def_id` matches the `lifetime` of this predicate. + pub fn is_param_bound(&self, param_def_id: LocalDefId) -> bool { + match self.lifetime.name { + LifetimeName::Param(id, _) => id == param_def_id, + _ => false, + } + } +} + /// An equality predicate (e.g., `T = int`); currently unsupported. #[derive(Debug, HashStable_Generic)] pub struct WhereEqPredicate<'hir> { diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 5b83a29bb33c3..bd8587f1106e9 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -510,11 +510,11 @@ pub fn walk_label<'v, V: Visitor<'v>>(visitor: &mut V, label: &'v Label) { pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) { visitor.visit_id(lifetime.hir_id); match lifetime.name { - LifetimeName::Param(ParamName::Plain(ident)) => { + LifetimeName::Param(_, ParamName::Plain(ident)) => { visitor.visit_ident(ident); } - LifetimeName::Param(ParamName::Fresh(_)) - | LifetimeName::Param(ParamName::Error) + LifetimeName::Param(_, ParamName::Fresh) + | LifetimeName::Param(_, ParamName::Error) | LifetimeName::Static | LifetimeName::Error | LifetimeName::Implicit @@ -879,7 +879,7 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Generi visitor.visit_id(param.hir_id); match param.name { ParamName::Plain(ident) => visitor.visit_ident(ident), - ParamName::Error | ParamName::Fresh(_) => {} + ParamName::Error | ParamName::Fresh => {} } match param.kind { GenericParamKind::Lifetime { .. } => {} diff --git a/compiler/rustc_middle/src/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs index 70586cefaeee1..cdc0d07680193 100644 --- a/compiler/rustc_middle/src/middle/resolve_lifetime.rs +++ b/compiler/rustc_middle/src/middle/resolve_lifetime.rs @@ -6,7 +6,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::ItemLocalId; use rustc_macros::HashStable; -use rustc_span::symbol::Symbol; #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)] pub enum Region { @@ -22,12 +21,12 @@ pub enum Region { /// so that we can e.g. suggest elided-lifetimes-in-paths of the form <'_, '_> e.g. #[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)] pub enum LifetimeScopeForPath { - // Contains all lifetime names that are in scope and could possibly be used in generics - // arguments of path. - NonElided(Vec), + /// Contains all lifetime names that are in scope and could possibly be used in generics + /// arguments of path. + NonElided(Vec), - // Information that allows us to suggest args of the form `<'_>` in case - // no generic arguments were provided for a path. + /// Information that allows us to suggest args of the form `<'_>` in case + /// no generic arguments were provided for a path. Elided, } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 9213652e35f8e..cb39eb5416ba2 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -13,7 +13,7 @@ use rustc_ast::{ }; use rustc_ast_lowering::ResolverAstLowering; use rustc_ast_pretty::pprust::path_segment_to_string; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_errors::{ pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, @@ -21,7 +21,7 @@ use rustc_errors::{ use rustc_hir as hir; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind}; -use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::PrimTy; use rustc_session::lint; use rustc_session::parse::feature_err; @@ -2082,7 +2082,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { /// Returns whether to add `'static` lifetime to the suggested lifetime list. pub(crate) fn report_elision_failure( - &mut self, + &self, diag: &mut Diagnostic, params: &[ElisionFailureInfo], ) -> bool { @@ -2187,10 +2187,27 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { &self, err: &mut Diagnostic, mut spans_with_counts: Vec<(Span, usize)>, - lifetime_names: &FxHashSet, - lifetime_spans: Vec, - params: &[ElisionFailureInfo], + in_scope_lifetimes: FxIndexSet, + params: Option<&[ElisionFailureInfo]>, ) { + let (mut lifetime_names, lifetime_spans): (FxHashSet<_>, Vec<_>) = in_scope_lifetimes + .iter() + .filter_map(|def_id| { + let name = self.tcx.item_name(def_id.to_def_id()); + let span = self.tcx.def_ident_span(def_id.to_def_id())?; + Some((name, span)) + }) + .filter(|&(n, _)| n != kw::UnderscoreLifetime) + .unzip(); + + if let Some(params) = params { + // If there's no lifetime available, suggest `'static`. + if self.report_elision_failure(err, params) && lifetime_names.is_empty() { + lifetime_names.insert(kw::StaticLifetime); + } + } + let params = params.unwrap_or(&[]); + let snippets: Vec> = spans_with_counts .iter() .map(|(span, _)| self.tcx.sess.source_map().span_to_snippet(*span).ok()) diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 59c2db25b8e05..6cd81aa7dac13 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -8,14 +8,14 @@ use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot}; use rustc_ast::walk_list; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefIdMap, LocalDefId}; use rustc_hir::hir_id::ItemLocalId; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node, ParamName}; +use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node}; use rustc_hir::{GenericParamKind, HirIdMap, HirIdSet}; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; @@ -33,9 +33,9 @@ use std::mem::take; use tracing::{debug, span, Level}; trait RegionExt { - fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region); + fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region); - fn late(index: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region); + fn late(index: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region); fn late_anon(named_late_bound_vars: u32, index: &Cell) -> Region; @@ -51,22 +51,22 @@ trait RegionExt { } impl RegionExt for Region { - fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region) { + fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region) { let i = *index; *index += 1; let def_id = hir_map.local_def_id(param.hir_id); debug!("Region::early: index={} def_id={:?}", i, def_id); - (param.name.normalize_to_macros_2_0(), Region::EarlyBound(i, def_id.to_def_id())) + (def_id, Region::EarlyBound(i, def_id.to_def_id())) } - fn late(idx: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region) { + fn late(idx: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region) { let depth = ty::INNERMOST; let def_id = hir_map.local_def_id(param.hir_id); debug!( "Region::late: idx={:?}, param={:?} depth={:?} def_id={:?}", idx, param, depth, def_id, ); - (param.name.normalize_to_macros_2_0(), Region::LateBound(depth, idx, def_id.to_def_id())) + (def_id, Region::LateBound(depth, idx, def_id.to_def_id())) } fn late_anon(named_late_bound_vars: u32, index: &Cell) -> Region { @@ -178,7 +178,7 @@ enum Scope<'a> { Binder { /// We use an IndexMap here because we want these lifetimes in order /// for diagnostics. - lifetimes: FxIndexMap, + lifetimes: FxIndexMap, /// if we extend this scope with another scope, what is the next index /// we should use for an early-bound region? @@ -554,10 +554,7 @@ fn get_lifetime_scopes_for_path(mut scope: &Scope<'_>) -> LifetimeScopeForPath { loop { match scope { Scope::Binder { lifetimes, s, .. } => { - available_lifetimes.extend(lifetimes.keys().filter_map(|p| match p { - hir::ParamName::Plain(ident) => Some(ident.name), - _ => None, - })); + available_lifetimes.extend(lifetimes.keys()); scope = s; } Scope::Body { s, .. } => { @@ -841,7 +838,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }; self.missing_named_lifetime_spots .push(MissingLifetimeSpot::HigherRanked { span, span_type }); - let (lifetimes, binders): (FxIndexMap, Vec<_>) = c + let (lifetimes, binders): (FxIndexMap, Vec<_>) = c .generic_params .iter() .filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. })) @@ -898,7 +895,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // cc #48468 self.resolve_elided_lifetimes(&[lifetime]) } - LifetimeName::Param(_) | LifetimeName::Static => { + LifetimeName::Param(..) | LifetimeName::Static => { // If the user wrote an explicit name, use that. self.visit_lifetime(lifetime); } @@ -1016,17 +1013,17 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { for param in generics.params { match param.kind { GenericParamKind::Lifetime { .. } => { - let (name, reg) = Region::early(self.tcx.hir(), &mut index, ¶m); + let (def_id, reg) = Region::early(self.tcx.hir(), &mut index, ¶m); if let hir::ParamName::Plain(Ident { name: kw::UnderscoreLifetime, .. - }) = name + }) = param.name { // Pick the elided lifetime "definition" if one exists // and use it to make an elision scope. elision = Some(reg); } else { - lifetimes.insert(name, reg); + lifetimes.insert(def_id, reg); } } GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { @@ -1174,7 +1171,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let mut index = self.next_early_index(); let mut non_lifetime_count = 0; debug!("visit_ty: index = {}", index); - let lifetimes: FxIndexMap = generics + let lifetimes: FxIndexMap = generics .params .iter() .filter_map(|param| match param.kind { @@ -1218,15 +1215,17 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { #[tracing::instrument(level = "debug", skip(self))] fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { - if lifetime_ref.is_elided() { - self.resolve_elided_lifetimes(&[lifetime_ref]); - return; - } - if lifetime_ref.is_static() { - self.insert_lifetime(lifetime_ref, Region::Static); - return; + match lifetime_ref.name { + hir::LifetimeName::ImplicitObjectLifetimeDefault + | hir::LifetimeName::Implicit + | hir::LifetimeName::Underscore => self.resolve_elided_lifetimes(&[lifetime_ref]), + hir::LifetimeName::Static => self.insert_lifetime(lifetime_ref, Region::Static), + hir::LifetimeName::Param(param_def_id, _) => { + self.resolve_lifetime_ref(param_def_id, lifetime_ref) + } + // If we've already reported an error, just ignore `lifetime_ref`. + hir::LifetimeName::Error => {} } - self.resolve_lifetime_ref(lifetime_ref); } fn visit_assoc_type_binding(&mut self, type_binding: &'tcx hir::TypeBinding<'_>) { @@ -1311,7 +1310,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { ref bound_generic_params, .. }) => { - let (lifetimes, binders): (FxIndexMap, Vec<_>) = + let (lifetimes, binders): (FxIndexMap, Vec<_>) = bound_generic_params .iter() .filter(|param| { @@ -1433,7 +1432,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let (mut binders, scope_type) = self.poly_trait_ref_binder_info(); let initial_bound_vars = binders.len() as u32; - let mut lifetimes: FxIndexMap = FxIndexMap::default(); + let mut lifetimes: FxIndexMap = FxIndexMap::default(); let binders_iter = trait_ref .bound_generic_params .iter() @@ -1580,14 +1579,17 @@ fn object_lifetime_defaults_for_item<'tcx>( .iter() .filter_map(|param| match param.kind { GenericParamKind::Lifetime { .. } => { - Some((param.hir_id, hir::LifetimeName::Param(param.name))) + let param_def_id = tcx.hir().local_def_id(param.hir_id); + Some(( + param_def_id, + hir::LifetimeName::Param(param_def_id, param.name), + )) } _ => None, }) .enumerate() .find(|&(_, (_, lt_name))| lt_name == name) - .map_or(Set1::Many, |(i, (id, _))| { - let def_id = tcx.hir().local_def_id(id); + .map_or(Set1::Many, |(i, (def_id, _))| { Set1::One(Region::EarlyBound(i as u32, def_id.to_def_id())) }) } @@ -1660,7 +1662,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { ) where F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>), { - insert_late_bound_lifetimes(self.map, decl, generics); + insert_late_bound_lifetimes(self.tcx, self.map, decl, generics); // Find the start of nested early scopes, e.g., in methods. let mut next_early_index = 0; @@ -1680,7 +1682,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let mut non_lifetime_count = 0; let mut named_late_bound_vars = 0; - let lifetimes: FxIndexMap = generics + let lifetimes: FxIndexMap = generics .params .iter() .filter_map(|param| match param.kind { @@ -1763,14 +1765,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { 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; - } - + #[tracing::instrument(level = "debug", skip(self))] + fn resolve_lifetime_ref( + &mut self, + region_def_id: LocalDefId, + lifetime_ref: &'tcx hir::Lifetime, + ) { // 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. @@ -1790,14 +1790,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } Scope::Binder { ref lifetimes, scope_type, s, .. } => { - match lifetime_ref.name { - LifetimeName::Param(param_name) => { - if let Some(&def) = lifetimes.get(¶m_name.normalize_to_macros_2_0()) - { - break Some(def.shifted(late_depth)); - } - } - _ => bug!("expected LifetimeName::Param"), + if let Some(&def) = lifetimes.get(®ion_def_id) { + break Some(def.shifted(late_depth)); } match scope_type { BinderScopeType::Normal => late_depth += 1, @@ -2473,8 +2467,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let mut late_depth = 0; let mut scope = self.scope; - let mut lifetime_names = FxHashSet::default(); - let mut lifetime_spans = vec![]; + let mut in_scope_lifetimes = FxIndexSet::default(); let error = loop { match *scope { // Do not assign any resolution, it will be inferred. @@ -2484,12 +2477,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { Scope::Binder { s, ref lifetimes, scope_type, .. } => { // collect named lifetimes for suggestions - for name in lifetimes.keys() { - if let hir::ParamName::Plain(name) = name { - lifetime_names.insert(name.name); - lifetime_spans.push(name.span); - } - } + in_scope_lifetimes.extend(lifetimes.keys().copied()); match scope_type { BinderScopeType::Normal => late_depth += 1, BinderScopeType::Concatenating => {} @@ -2524,12 +2512,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { match scope { 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.name); - lifetime_spans.push(name.span); - } - } + in_scope_lifetimes.extend(lifetimes.keys().copied()); scope = s; } Scope::ObjectLifetimeDefault { ref s, .. } @@ -2574,19 +2557,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let mut err = self.report_missing_lifetime_specifiers(spans.clone(), lifetime_refs.len()); - if let Some(params) = error { - // If there's no lifetime available, suggest `'static`. - if self.report_elision_failure(&mut err, params) && lifetime_names.is_empty() { - lifetime_names.insert(kw::StaticLifetime); - } - } - self.add_missing_lifetime_specifiers_label( &mut err, spans_with_counts, - &lifetime_names, - lifetime_spans, - error.unwrap_or(&[]), + in_scope_lifetimes, + error, ); err.emit(); } @@ -2647,8 +2622,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { /// "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`. -#[tracing::instrument(level = "debug", skip(map))] +#[tracing::instrument(level = "debug", skip(tcx, map))] fn insert_late_bound_lifetimes( + tcx: TyCtxt<'_>, map: &mut NamedRegionMap, decl: &hir::FnDecl<'_>, generics: &hir::Generics<'_>, @@ -2683,15 +2659,16 @@ fn insert_late_bound_lifetimes( hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => continue, } - let lt_name = hir::LifetimeName::Param(param.name.normalize_to_macros_2_0()); + let param_def_id = tcx.hir().local_def_id(param.hir_id); + // appears in the where clauses? early-bound. - if appears_in_where_clause.regions.contains(<_name) { + if appears_in_where_clause.regions.contains(¶m_def_id) { 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) + if !constrained_by_input.regions.contains(¶m_def_id) + && appears_in_output.regions.contains(¶m_def_id) { continue; } @@ -2706,7 +2683,7 @@ fn insert_late_bound_lifetimes( #[derive(Default)] struct ConstrainedCollector { - regions: FxHashSet, + regions: FxHashSet, } impl<'v> Visitor<'v> for ConstrainedCollector { @@ -2738,18 +2715,22 @@ fn insert_late_bound_lifetimes( } fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { - self.regions.insert(lifetime_ref.name.normalize_to_macros_2_0()); + if let hir::LifetimeName::Param(def_id, _) = lifetime_ref.name { + self.regions.insert(def_id); + } } } #[derive(Default)] struct AllCollector { - regions: FxHashSet, + regions: FxHashSet, } impl<'v> Visitor<'v> for AllCollector { fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { - self.regions.insert(lifetime_ref.name.normalize_to_macros_2_0()); + if let hir::LifetimeName::Param(def_id, _) = lifetime_ref.name { + self.regions.insert(def_id); + } } } } diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs index f1dc3cbbac459..bc3a3db9fdadb 100644 --- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs @@ -514,7 +514,9 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { param_names .iter() .take(num_params_to_take) - .map(|p| p.as_str()) + .map(|def_id| { + self.tcx.item_name(def_id.to_def_id()).to_ident_string() + }) .collect::>() .join(", ") } else { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c725cf93be2f4..f3070fb35f1d0 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -475,24 +475,14 @@ fn clean_generic_param<'tcx>( generics: Option<&hir::Generics<'tcx>>, param: &hir::GenericParam<'tcx>, ) -> GenericParamDef { + let did = cx.tcx.hir().local_def_id(param.hir_id); let (name, kind) = match param.kind { hir::GenericParamKind::Lifetime { .. } => { let outlives = if let Some(generics) = generics { generics - .predicates - .iter() - .flat_map(|pred| { - match pred { - hir::WherePredicate::RegionPredicate(rp) - if rp.lifetime.name == hir::LifetimeName::Param(param.name) - && !rp.in_where_clause => - { - rp.bounds - } - _ => &[], - } - .iter() - }) + .outlives_for_param(did) + .filter(|bp| !bp.in_where_clause) + .flat_map(|bp| bp.bounds) .map(|bound| match bound { hir::GenericBound::Outlives(lt) => lt.clean(cx), _ => panic!(), @@ -504,7 +494,6 @@ fn clean_generic_param<'tcx>( (param.name.ident().name, GenericParamDefKind::Lifetime { outlives }) } hir::GenericParamKind::Type { ref default, synthetic } => { - let did = cx.tcx.hir().local_def_id(param.hir_id); let bounds = if let Some(generics) = generics { generics .bounds_for_param(did) @@ -528,7 +517,7 @@ fn clean_generic_param<'tcx>( hir::GenericParamKind::Const { ty, default } => ( param.name.ident().name, GenericParamDefKind::Const { - did: cx.tcx.hir().local_def_id(param.hir_id).to_def_id(), + did: did.to_def_id(), ty: Box::new(ty.clean(cx)), default: default.map(|ct| { let def_id = cx.tcx.hir().local_def_id(ct.hir_id); @@ -1459,7 +1448,7 @@ impl<'tcx> Clean<'tcx, Type> for hir::Ty<'tcx> { // Turning `fn f(&'_ self)` into `fn f(&self)` isn't the worst thing in the world, though; // there's no case where it could cause the function to fail to compile. let elided = - l.is_elided() || matches!(l.name, LifetimeName::Param(ParamName::Fresh(_))); + l.is_elided() || matches!(l.name, LifetimeName::Param(_, ParamName::Fresh)); let lifetime = if elided { None } else { Some(l.clean(cx)) }; BorrowedRef { lifetime, mutability: m.mutbl, type_: box m.ty.clean(cx) } } diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 51d5b510ab930..070c7e591420d 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -371,7 +371,7 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> { if let Some(ref lt) = *lifetime { if lt.name == LifetimeName::Static { self.lts.push(RefLt::Static); - } else if let LifetimeName::Param(ParamName::Fresh(_)) = lt.name { + } else if let LifetimeName::Param(_, ParamName::Fresh) = lt.name { // Fresh lifetimes generated should be ignored. } else if lt.is_elided() { self.lts.push(RefLt::Unnamed); diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 548f7b2528b11..0b96f6ff68358 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -343,7 +343,7 @@ impl fmt::Display for RefPrefix { use fmt::Write; f.write_char('&')?; match self.lt { - LifetimeName::Param(ParamName::Plain(name)) => { + LifetimeName::Param(_, ParamName::Plain(name)) => { name.fmt(f)?; f.write_char(' ')?; }, diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index c440793b90e0e..fc1a4e1f60255 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -902,16 +902,14 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { pub fn hash_lifetime(&mut self, lifetime: Lifetime) { std::mem::discriminant(&lifetime.name).hash(&mut self.s); - if let LifetimeName::Param(ref name) = lifetime.name { + if let LifetimeName::Param(param_id, ref name) = lifetime.name { std::mem::discriminant(name).hash(&mut self.s); + param_id.hash(&mut self.s); match name { ParamName::Plain(ref ident) => { ident.name.hash(&mut self.s); }, - ParamName::Fresh(ref size) => { - size.hash(&mut self.s); - }, - ParamName::Error => {}, + ParamName::Fresh | ParamName::Error => {}, } } }