1
Fork 0

Rollup merge of #97415 - cjgillot:is-late-bound-solo, r=estebank

Compute `is_late_bound_map` query separately from lifetime resolution

This query is actually very simple, and is only useful for functions and method.  It can be computed directly by fetching the HIR, with no need to embed it within the lifetime resolution visitor.

Based on https://github.com/rust-lang/rust/pull/96296
This commit is contained in:
Dylan DPC 2022-06-03 17:10:51 +02:00 committed by GitHub
commit 53ab3b2e6e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 205 additions and 266 deletions

View file

@ -672,9 +672,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
LifetimeRes::Param { .. } => { LifetimeRes::Param { .. } => {
(hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit) (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit)
} }
LifetimeRes::Fresh { param, .. } => { LifetimeRes::Fresh { .. } => (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided),
(hir::ParamName::Fresh(param), hir::LifetimeParamKind::Elided)
}
LifetimeRes::Static | LifetimeRes::Error => return None, LifetimeRes::Static | LifetimeRes::Error => return None,
res => panic!( res => panic!(
"Unexpected lifetime resolution {:?} for {:?} at {:?}", "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 }) (hir::ParamName::Plain(ident), LifetimeRes::Param { param, binder: fn_node_id })
} }
// Input lifetime like `'1`: // Input lifetime like `'1`:
LifetimeRes::Fresh { param, .. } => ( LifetimeRes::Fresh { param, .. } => {
hir::ParamName::Fresh(outer_def_id), (hir::ParamName::Fresh, LifetimeRes::Fresh { param, binder: fn_node_id })
LifetimeRes::Fresh { param, binder: fn_node_id }, }
),
LifetimeRes::Static | LifetimeRes::Error => continue, LifetimeRes::Static | LifetimeRes::Error => continue,
res => { res => {
panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span) panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span)
@ -1749,7 +1746,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
) -> hir::Lifetime { ) -> hir::Lifetime {
debug!(?self.captured_lifetimes); debug!(?self.captured_lifetimes);
let name = match res { let name = match res {
LifetimeRes::Param { param, binder } => { LifetimeRes::Param { mut param, binder } => {
debug_assert_ne!(ident.name, kw::UnderscoreLifetime); debug_assert_ne!(ident.name, kw::UnderscoreLifetime);
let p_name = ParamName::Plain(ident); let p_name = ParamName::Plain(ident);
if let Some(LifetimeCaptureContext { parent_def_id, captures, binders_to_ignore }) = 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) && !binders_to_ignore.contains(&binder)
{ {
match captures.entry(param) { match captures.entry(param) {
Entry::Occupied(_) => {} Entry::Occupied(o) => param = self.resolver.local_def_id(o.get().1),
Entry::Vacant(v) => { Entry::Vacant(v) => {
let p_id = self.resolver.next_node_id(); let p_id = self.resolver.next_node_id();
self.resolver.create_def( let p_def_id = self.resolver.create_def(
*parent_def_id, *parent_def_id,
p_id, p_id,
DefPathData::LifetimeNs(p_name.ident().name), DefPathData::LifetimeNs(p_name.ident().name),
@ -1769,10 +1766,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
); );
v.insert((span, p_id, p_name, res)); 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 } => { LifetimeRes::Fresh { mut param, binder } => {
debug_assert_eq!(ident.name, kw::UnderscoreLifetime); debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
@ -1792,21 +1790,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span.with_parent(None), span.with_parent(None),
); );
let p_name = ParamName::Fresh(param); v.insert((span, p_id, ParamName::Fresh, res));
v.insert((span, p_id, p_name, res));
param = p_def_id; param = p_def_id;
} }
} }
} }
let p_name = ParamName::Fresh(param); hir::LifetimeName::Param(param, ParamName::Fresh)
hir::LifetimeName::Param(p_name)
} }
LifetimeRes::Anonymous { binder, elided } => { 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 }) = if let Some(LifetimeCaptureContext { parent_def_id, captures, binders_to_ignore }) =
&mut self.captured_lifetimes &mut self.captured_lifetimes
&& !binders_to_ignore.contains(&binder) && !binders_to_ignore.contains(&binder)
@ -1819,11 +1810,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ExpnId::root(), ExpnId::root(),
span.with_parent(None), span.with_parent(None),
); );
let p_name = ParamName::Fresh(p_def_id); captures.insert(p_def_id, (span, p_id, ParamName::Fresh, res));
captures.insert(p_def_id, (span, p_id, p_name, res)); hir::LifetimeName::Param(p_def_id, ParamName::Fresh)
hir::LifetimeName::Param(p_name) } else if elided {
hir::LifetimeName::Implicit
} else { } else {
l_name hir::LifetimeName::Underscore
} }
} }
LifetimeRes::Static => hir::LifetimeName::Static, 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), res => panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span),
}; };
debug!(?self.captured_lifetimes); debug!(?self.captured_lifetimes);
debug!(?name);
hir::Lifetime { hir_id: self.lower_node_id(id), span: self.lower_span(span), name } hir::Lifetime { hir_id: self.lower_node_id(id), span: self.lower_span(span), name }
} }

View file

@ -567,14 +567,14 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
let lifetime = let lifetime =
self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?; self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?;
match lifetime.name { 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::Error
| hir::LifetimeName::Static => { | hir::LifetimeName::Static => {
let lifetime_span = lifetime.span; let lifetime_span = lifetime.span;
Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span)) Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span))
} }
hir::LifetimeName::Param(hir::ParamName::Fresh(_)) hir::LifetimeName::Param(_, hir::ParamName::Fresh)
| hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::ImplicitObjectLifetimeDefault
| hir::LifetimeName::Implicit | hir::LifetimeName::Implicit
| hir::LifetimeName::Underscore => { | hir::LifetimeName::Underscore => {

View file

@ -830,11 +830,11 @@ fn for_each_late_bound_region_defined_on<'tcx>(
fn_def_id: DefId, fn_def_id: DefId,
mut f: impl FnMut(ty::Region<'tcx>), mut f: impl FnMut(ty::Region<'tcx>),
) { ) {
if let Some((owner, late_bounds)) = tcx.is_late_bound_map(fn_def_id.expect_local()) { if let Some(late_bounds) = tcx.is_late_bound_map(fn_def_id.expect_local()) {
for &region_def_id in late_bounds.iter() { for &region_def_id in late_bounds.iter() {
let name = tcx.item_name(region_def_id.to_def_id()); let name = tcx.item_name(region_def_id.to_def_id());
let liberated_region = tcx.mk_region(ty::ReFree(ty::FreeRegion { let liberated_region = tcx.mk_region(ty::ReFree(ty::FreeRegion {
scope: owner.to_def_id(), scope: fn_def_id,
bound_region: ty::BoundRegionKind::BrNamed(region_def_id.to_def_id(), name), bound_region: ty::BoundRegionKind::BrNamed(region_def_id.to_def_id(), name),
})); }));
f(liberated_region); f(liberated_region);

View file

@ -26,7 +26,7 @@ use rustc_target::spec::abi::Abi;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::fmt; use std::fmt;
#[derive(Copy, Clone, Encodable, HashStable_Generic)] #[derive(Debug, Copy, Clone, Encodable, HashStable_Generic)]
pub struct Lifetime { pub struct Lifetime {
pub hir_id: HirId, pub hir_id: HirId,
pub span: Span, pub span: Span,
@ -60,7 +60,7 @@ pub enum ParamName {
/// ``` /// ```
/// where `'f` is something like `Fresh(0)`. The indices are /// where `'f` is something like `Fresh(0)`. The indices are
/// unique per impl, but not necessarily continuous. /// unique per impl, but not necessarily continuous.
Fresh(LocalDefId), Fresh,
/// Indicates an illegal name was given and an error has been /// Indicates an illegal name was given and an error has been
/// reported (so we should squelch other derived errors). Occurs /// reported (so we should squelch other derived errors). Occurs
@ -72,9 +72,7 @@ impl ParamName {
pub fn ident(&self) -> Ident { pub fn ident(&self) -> Ident {
match *self { match *self {
ParamName::Plain(ident) => ident, ParamName::Plain(ident) => ident,
ParamName::Fresh(_) | ParamName::Error => { ParamName::Fresh | ParamName::Error => Ident::with_dummy_span(kw::UnderscoreLifetime),
Ident::with_dummy_span(kw::UnderscoreLifetime)
}
} }
} }
@ -90,7 +88,7 @@ impl ParamName {
#[derive(HashStable_Generic)] #[derive(HashStable_Generic)]
pub enum LifetimeName { pub enum LifetimeName {
/// User-given names or fresh (synthetic) names. /// User-given names or fresh (synthetic) names.
Param(ParamName), Param(LocalDefId, ParamName),
/// User wrote nothing (e.g., the lifetime in `&u32`). /// User wrote nothing (e.g., the lifetime in `&u32`).
Implicit, Implicit,
@ -127,7 +125,7 @@ impl LifetimeName {
| LifetimeName::Error => Ident::empty(), | LifetimeName::Error => Ident::empty(),
LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime), LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime),
LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime), 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::ImplicitObjectLifetimeDefault
| LifetimeName::Implicit | LifetimeName::Implicit
| LifetimeName::Underscore | LifetimeName::Underscore
| LifetimeName::Param(ParamName::Fresh(_)) | LifetimeName::Param(_, ParamName::Fresh)
| LifetimeName::Error => true, | LifetimeName::Error => true,
LifetimeName::Static | LifetimeName::Param(_) => false, LifetimeName::Static | LifetimeName::Param(..) => false,
} }
} }
@ -148,12 +146,12 @@ impl LifetimeName {
| LifetimeName::Implicit | LifetimeName::Implicit
| LifetimeName::Underscore => true, | 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 // *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 // equivalently to "some fresh name". They correspond to
// early-bound regions on an impl, in other words. // 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 { pub fn normalize_to_macros_2_0(&self) -> LifetimeName {
match *self { match *self {
LifetimeName::Param(param_name) => { LifetimeName::Param(def_id, param_name) => {
LifetimeName::Param(param_name.normalize_to_macros_2_0()) LifetimeName::Param(def_id, param_name.normalize_to_macros_2_0())
} }
lifetime_name => lifetime_name, 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 { impl Lifetime {
pub fn is_elided(&self) -> bool { pub fn is_elided(&self) -> bool {
self.name.is_elided() self.name.is_elided()
@ -628,6 +620,16 @@ impl<'hir> Generics<'hir> {
}) })
} }
pub fn outlives_for_param(
&self,
param_def_id: LocalDefId,
) -> impl Iterator<Item = &WhereRegionPredicate<'_>> {
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<Span> { pub fn bounds_span_for_suggestions(&self, param_def_id: LocalDefId) -> Option<Span> {
self.bounds_for_param(param_def_id).flat_map(|bp| bp.bounds.iter().rev()).find_map( self.bounds_for_param(param_def_id).flat_map(|bp| bp.bounds.iter().rev()).find_map(
|bound| { |bound| {
@ -769,6 +771,16 @@ pub struct WhereRegionPredicate<'hir> {
pub bounds: GenericBounds<'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. /// An equality predicate (e.g., `T = int`); currently unsupported.
#[derive(Debug, HashStable_Generic)] #[derive(Debug, HashStable_Generic)]
pub struct WhereEqPredicate<'hir> { pub struct WhereEqPredicate<'hir> {

View file

@ -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) { pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
visitor.visit_id(lifetime.hir_id); visitor.visit_id(lifetime.hir_id);
match lifetime.name { match lifetime.name {
LifetimeName::Param(ParamName::Plain(ident)) => { LifetimeName::Param(_, ParamName::Plain(ident)) => {
visitor.visit_ident(ident); visitor.visit_ident(ident);
} }
LifetimeName::Param(ParamName::Fresh(_)) LifetimeName::Param(_, ParamName::Fresh)
| LifetimeName::Param(ParamName::Error) | LifetimeName::Param(_, ParamName::Error)
| LifetimeName::Static | LifetimeName::Static
| LifetimeName::Error | LifetimeName::Error
| LifetimeName::Implicit | 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); visitor.visit_id(param.hir_id);
match param.name { match param.name {
ParamName::Plain(ident) => visitor.visit_ident(ident), ParamName::Plain(ident) => visitor.visit_ident(ident),
ParamName::Error | ParamName::Fresh(_) => {} ParamName::Error | ParamName::Fresh => {}
} }
match param.kind { match param.kind {
GenericParamKind::Lifetime { .. } => {} GenericParamKind::Lifetime { .. } => {}

View file

@ -364,7 +364,11 @@ impl<'hir> Map<'hir> {
match node.node { match node.node {
OwnerNode::ImplItem(impl_item) => Some(&impl_item.generics), OwnerNode::ImplItem(impl_item) => Some(&impl_item.generics),
OwnerNode::TraitItem(trait_item) => Some(&trait_item.generics), OwnerNode::TraitItem(trait_item) => Some(&trait_item.generics),
OwnerNode::Item(Item { OwnerNode::ForeignItem(ForeignItem {
kind: ForeignItemKind::Fn(_, _, generics),
..
})
| OwnerNode::Item(Item {
kind: kind:
ItemKind::Fn(_, generics, _) ItemKind::Fn(_, generics, _)
| ItemKind::TyAlias(_, generics) | ItemKind::TyAlias(_, generics)

View file

@ -6,7 +6,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::ItemLocalId; use rustc_hir::ItemLocalId;
use rustc_macros::HashStable; use rustc_macros::HashStable;
use rustc_span::symbol::Symbol;
#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)] #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
pub enum Region { 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. /// 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)] #[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
pub enum LifetimeScopeForPath { pub enum LifetimeScopeForPath {
// Contains all lifetime names that are in scope and could possibly be used in generics /// Contains all lifetime names that are in scope and could possibly be used in generics
// arguments of path. /// arguments of path.
NonElided(Vec<Symbol>), NonElided(Vec<LocalDefId>),
// Information that allows us to suggest args of the form `<'_>` in case /// Information that allows us to suggest args of the form `<'_>` in case
// no generic arguments were provided for a path. /// no generic arguments were provided for a path.
Elided, Elided,
} }

View file

@ -1584,7 +1584,7 @@ rustc_queries! {
Option<&'tcx FxHashMap<ItemLocalId, Region>> { Option<&'tcx FxHashMap<ItemLocalId, Region>> {
desc { "looking up a named region" } desc { "looking up a named region" }
} }
query is_late_bound_map(_: LocalDefId) -> Option<(LocalDefId, &'tcx FxHashSet<LocalDefId>)> { query is_late_bound_map(_: LocalDefId) -> Option<&'tcx FxHashSet<LocalDefId>> {
desc { "testing if a region is late bound" } desc { "testing if a region is late bound" }
} }
/// For a given item (like a struct), gets the default lifetimes to be used /// For a given item (like a struct), gets the default lifetimes to be used

View file

@ -2803,6 +2803,13 @@ impl<'tcx> TyCtxt<'tcx> {
self.named_region_map(id.owner).and_then(|map| map.get(&id.local_id).cloned()) self.named_region_map(id.owner).and_then(|map| map.get(&id.local_id).cloned())
} }
pub fn is_late_bound(self, id: HirId) -> bool {
self.is_late_bound_map(id.owner).map_or(false, |set| {
let def_id = self.hir().local_def_id(id);
set.contains(&def_id)
})
}
pub fn late_bound_vars(self, id: HirId) -> &'tcx List<ty::BoundVariableKind> { pub fn late_bound_vars(self, id: HirId) -> &'tcx List<ty::BoundVariableKind> {
self.mk_bound_variable_kinds( self.mk_bound_variable_kinds(
self.late_bound_vars_map(id.owner) self.late_bound_vars_map(id.owner)

View file

@ -13,7 +13,7 @@ use rustc_ast::{
}; };
use rustc_ast_lowering::ResolverAstLowering; use rustc_ast_lowering::ResolverAstLowering;
use rustc_ast_pretty::pprust::path_segment_to_string; 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::{ use rustc_errors::{
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
MultiSpan, MultiSpan,
@ -21,7 +21,7 @@ use rustc_errors::{
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind}; 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_hir::PrimTy;
use rustc_session::lint; use rustc_session::lint;
use rustc_session::parse::feature_err; 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. /// Returns whether to add `'static` lifetime to the suggested lifetime list.
pub(crate) fn report_elision_failure( pub(crate) fn report_elision_failure(
&mut self, &self,
diag: &mut Diagnostic, diag: &mut Diagnostic,
params: &[ElisionFailureInfo], params: &[ElisionFailureInfo],
) -> bool { ) -> bool {
@ -2187,10 +2187,27 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
&self, &self,
err: &mut Diagnostic, err: &mut Diagnostic,
mut spans_with_counts: Vec<(Span, usize)>, mut spans_with_counts: Vec<(Span, usize)>,
lifetime_names: &FxHashSet<Symbol>, in_scope_lifetimes: FxIndexSet<LocalDefId>,
lifetime_spans: Vec<Span>, params: Option<&[ElisionFailureInfo]>,
params: &[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<Option<String>> = spans_with_counts let snippets: Vec<Option<String>> = spans_with_counts
.iter() .iter()
.map(|(span, _)| self.tcx.sess.source_map().span_to_snippet(*span).ok()) .map(|(span, _)| self.tcx.sess.source_map().span_to_snippet(*span).ok())

View file

@ -8,19 +8,19 @@
use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot}; use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot};
use rustc_ast::walk_list; 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_errors::struct_span_err;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefIdMap, LocalDefId}; use rustc_hir::def_id::{DefIdMap, LocalDefId};
use rustc_hir::hir_id::ItemLocalId; use rustc_hir::hir_id::ItemLocalId;
use rustc_hir::intravisit::{self, Visitor}; 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_hir::{GenericParamKind, HirIdMap};
use rustc_middle::hir::map::Map; use rustc_middle::hir::map::Map;
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
use rustc_middle::middle::resolve_lifetime::*; use rustc_middle::middle::resolve_lifetime::*;
use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt}; use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
use rustc_middle::{bug, span_bug}; use rustc_middle::{bug, span_bug};
use rustc_span::def_id::DefId; use rustc_span::def_id::DefId;
use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::symbol::{kw, sym, Ident};
@ -33,9 +33,9 @@ use std::mem::take;
use tracing::{debug, span, Level}; use tracing::{debug, span, Level};
trait RegionExt { 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<u32>) -> Region; fn late_anon(named_late_bound_vars: u32, index: &Cell<u32>) -> Region;
@ -51,22 +51,22 @@ trait RegionExt {
} }
impl RegionExt for Region { 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; let i = *index;
*index += 1; *index += 1;
let def_id = hir_map.local_def_id(param.hir_id); let def_id = hir_map.local_def_id(param.hir_id);
debug!("Region::early: index={} def_id={:?}", i, def_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 depth = ty::INNERMOST;
let def_id = hir_map.local_def_id(param.hir_id); let def_id = hir_map.local_def_id(param.hir_id);
debug!( debug!(
"Region::late: idx={:?}, param={:?} depth={:?} def_id={:?}", "Region::late: idx={:?}, param={:?} depth={:?} def_id={:?}",
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<u32>) -> Region { fn late_anon(named_late_bound_vars: u32, index: &Cell<u32>) -> Region {
@ -134,11 +134,6 @@ struct NamedRegionMap {
// `Region` describing how that region is bound // `Region` describing how that region is bound
defs: HirIdMap<Region>, defs: HirIdMap<Region>,
// 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,
// Maps relevant hir items to the bound vars on them. These include: // Maps relevant hir items to the bound vars on them. These include:
// - function defs // - function defs
// - function pointers // - function pointers
@ -178,7 +173,7 @@ enum Scope<'a> {
Binder { Binder {
/// We use an IndexMap here because we want these lifetimes in order /// We use an IndexMap here because we want these lifetimes in order
/// for diagnostics. /// for diagnostics.
lifetimes: FxIndexMap<hir::ParamName, Region>, lifetimes: FxIndexMap<LocalDefId, Region>,
/// if we extend this scope with another scope, what is the next index /// if we extend this scope with another scope, what is the next index
/// we should use for an early-bound region? /// we should use for an early-bound region?
@ -402,7 +397,7 @@ fn resolve_lifetimes_trait_definition(
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
local_def_id: LocalDefId, local_def_id: LocalDefId,
) -> ResolveLifetimes { ) -> ResolveLifetimes {
convert_named_region_map(tcx, do_resolve(tcx, local_def_id, true, false)) convert_named_region_map(do_resolve(tcx, local_def_id, true, false))
} }
/// Computes the `ResolveLifetimes` map that contains data for an entire `Item`. /// Computes the `ResolveLifetimes` map that contains data for an entire `Item`.
@ -410,7 +405,7 @@ fn resolve_lifetimes_trait_definition(
/// `named_region_map`, `is_late_bound_map`, etc. /// `named_region_map`, `is_late_bound_map`, etc.
#[tracing::instrument(level = "debug", skip(tcx))] #[tracing::instrument(level = "debug", skip(tcx))]
fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifetimes { fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifetimes {
convert_named_region_map(tcx, do_resolve(tcx, local_def_id, false, false)) convert_named_region_map(do_resolve(tcx, local_def_id, false, false))
} }
fn do_resolve( fn do_resolve(
@ -422,7 +417,6 @@ fn do_resolve(
let item = tcx.hir().expect_item(local_def_id); let item = tcx.hir().expect_item(local_def_id);
let mut named_region_map = NamedRegionMap { let mut named_region_map = NamedRegionMap {
defs: Default::default(), defs: Default::default(),
late_bound: Default::default(),
late_bound_vars: Default::default(), late_bound_vars: Default::default(),
scope_for_path: with_scope_for_path.then(|| Default::default()), scope_for_path: with_scope_for_path.then(|| Default::default()),
}; };
@ -439,18 +433,13 @@ fn do_resolve(
named_region_map named_region_map
} }
fn convert_named_region_map(tcx: TyCtxt<'_>, named_region_map: NamedRegionMap) -> ResolveLifetimes { fn convert_named_region_map(named_region_map: NamedRegionMap) -> ResolveLifetimes {
let mut rl = ResolveLifetimes::default(); let mut rl = ResolveLifetimes::default();
for (hir_id, v) in named_region_map.defs { for (hir_id, v) in named_region_map.defs {
let map = rl.defs.entry(hir_id.owner).or_default(); let map = rl.defs.entry(hir_id.owner).or_default();
map.insert(hir_id.local_id, v); 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).or_default();
let def_id = tcx.hir().local_def_id(hir_id);
map.insert(def_id);
}
for (hir_id, v) in named_region_map.late_bound_vars { for (hir_id, v) in named_region_map.late_bound_vars {
let map = rl.late_bound_vars.entry(hir_id.owner).or_default(); let map = rl.late_bound_vars.entry(hir_id.owner).or_default();
map.insert(hir_id.local_id, v); map.insert(hir_id.local_id, v);
@ -506,28 +495,6 @@ fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> LocalDefId {
item item
} }
fn is_late_bound_map<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
) -> Option<(LocalDefId, &'tcx FxHashSet<LocalDefId>)> {
match tcx.def_kind(def_id) {
DefKind::AnonConst | DefKind::InlineConst => {
let mut def_id = tcx.local_parent(def_id);
// We search for the next outer anon const or fn here
// while skipping closures.
//
// Note that for `AnonConst` we still just recurse until we
// find a function body, but who cares :shrug:
while tcx.is_closure(def_id.to_def_id()) {
def_id = tcx.local_parent(def_id);
}
tcx.is_late_bound_map(def_id)
}
_ => resolve_lifetimes_for(tcx, def_id).late_bound.get(&def_id).map(|lt| (def_id, lt)),
}
}
/// In traits, there is an implicit `Self` type parameter which comes before the generics. /// 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. /// 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. /// This function returns whether there is such an implicit parameter defined on the given item.
@ -554,10 +521,7 @@ fn get_lifetime_scopes_for_path(mut scope: &Scope<'_>) -> LifetimeScopeForPath {
loop { loop {
match scope { match scope {
Scope::Binder { lifetimes, s, .. } => { Scope::Binder { lifetimes, s, .. } => {
available_lifetimes.extend(lifetimes.keys().filter_map(|p| match p { available_lifetimes.extend(lifetimes.keys());
hir::ParamName::Plain(ident) => Some(ident.name),
_ => None,
}));
scope = s; scope = s;
} }
Scope::Body { s, .. } => { Scope::Body { s, .. } => {
@ -690,9 +654,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
_ => {} _ => {}
} }
match item.kind { match item.kind {
hir::ItemKind::Fn(ref sig, ref generics, _) => { hir::ItemKind::Fn(_, ref generics, _) => {
self.missing_named_lifetime_spots.push(generics.into()); self.missing_named_lifetime_spots.push(generics.into());
self.visit_early_late(None, item.hir_id(), &sig.decl, generics, |this| { self.visit_early_late(None, item.hir_id(), generics, |this| {
intravisit::walk_item(this, item); intravisit::walk_item(this, item);
}); });
self.missing_named_lifetime_spots.pop(); self.missing_named_lifetime_spots.pop();
@ -734,13 +698,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
self.map.defs.insert(hir::HirId { owner, local_id }, *region); self.map.defs.insert(hir::HirId { owner, local_id }, *region);
}); });
} }
for (&owner, late_bound) in resolved_lifetimes.late_bound.iter() {
late_bound.iter().for_each(|&id| {
let hir_id = self.tcx.local_def_id_to_hir_id(id);
debug_assert_eq!(owner, hir_id.owner);
self.map.late_bound.insert(hir_id);
});
}
for (&owner, late_bound_vars) in for (&owner, late_bound_vars) in
resolved_lifetimes.late_bound_vars.iter() resolved_lifetimes.late_bound_vars.iter()
{ {
@ -810,8 +767,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
match item.kind { match item.kind {
hir::ForeignItemKind::Fn(ref decl, _, ref generics) => { hir::ForeignItemKind::Fn(_, _, ref generics) => {
self.visit_early_late(None, item.hir_id(), decl, generics, |this| { self.visit_early_late(None, item.hir_id(), generics, |this| {
intravisit::walk_foreign_item(this, item); intravisit::walk_foreign_item(this, item);
}) })
} }
@ -841,7 +798,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}; };
self.missing_named_lifetime_spots self.missing_named_lifetime_spots
.push(MissingLifetimeSpot::HigherRanked { span, span_type }); .push(MissingLifetimeSpot::HigherRanked { span, span_type });
let (lifetimes, binders): (FxIndexMap<hir::ParamName, Region>, Vec<_>) = c let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) = c
.generic_params .generic_params
.iter() .iter()
.filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. })) .filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
@ -898,7 +855,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// cc #48468 // cc #48468
self.resolve_elided_lifetimes(&[lifetime]) self.resolve_elided_lifetimes(&[lifetime])
} }
LifetimeName::Param(_) | LifetimeName::Static => { LifetimeName::Param(..) | LifetimeName::Static => {
// If the user wrote an explicit name, use that. // If the user wrote an explicit name, use that.
self.visit_lifetime(lifetime); self.visit_lifetime(lifetime);
} }
@ -1016,17 +973,17 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
for param in generics.params { for param in generics.params {
match param.kind { match param.kind {
GenericParamKind::Lifetime { .. } => { GenericParamKind::Lifetime { .. } => {
let (name, reg) = Region::early(self.tcx.hir(), &mut index, &param); let (def_id, reg) = Region::early(self.tcx.hir(), &mut index, &param);
if let hir::ParamName::Plain(Ident { if let hir::ParamName::Plain(Ident {
name: kw::UnderscoreLifetime, name: kw::UnderscoreLifetime,
.. ..
}) = name }) = param.name
{ {
// Pick the elided lifetime "definition" if one exists // Pick the elided lifetime "definition" if one exists
// and use it to make an elision scope. // and use it to make an elision scope.
elision = Some(reg); elision = Some(reg);
} else { } else {
lifetimes.insert(name, reg); lifetimes.insert(def_id, reg);
} }
} }
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
@ -1088,13 +1045,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
use self::hir::TraitItemKind::*; use self::hir::TraitItemKind::*;
match trait_item.kind { match trait_item.kind {
Fn(ref sig, _) => { Fn(_, _) => {
self.missing_named_lifetime_spots.push((&trait_item.generics).into()); self.missing_named_lifetime_spots.push((&trait_item.generics).into());
let tcx = self.tcx; let tcx = self.tcx;
self.visit_early_late( self.visit_early_late(
Some(tcx.hir().get_parent_item(trait_item.hir_id())), Some(tcx.hir().get_parent_item(trait_item.hir_id())),
trait_item.hir_id(), trait_item.hir_id(),
&sig.decl,
&trait_item.generics, &trait_item.generics,
|this| intravisit::walk_trait_item(this, trait_item), |this| intravisit::walk_trait_item(this, trait_item),
); );
@ -1156,13 +1112,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
use self::hir::ImplItemKind::*; use self::hir::ImplItemKind::*;
match impl_item.kind { match impl_item.kind {
Fn(ref sig, _) => { Fn(..) => {
self.missing_named_lifetime_spots.push((&impl_item.generics).into()); self.missing_named_lifetime_spots.push((&impl_item.generics).into());
let tcx = self.tcx; let tcx = self.tcx;
self.visit_early_late( self.visit_early_late(
Some(tcx.hir().get_parent_item(impl_item.hir_id())), Some(tcx.hir().get_parent_item(impl_item.hir_id())),
impl_item.hir_id(), impl_item.hir_id(),
&sig.decl,
&impl_item.generics, &impl_item.generics,
|this| intravisit::walk_impl_item(this, impl_item), |this| intravisit::walk_impl_item(this, impl_item),
); );
@ -1174,7 +1129,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
let mut index = self.next_early_index(); let mut index = self.next_early_index();
let mut non_lifetime_count = 0; let mut non_lifetime_count = 0;
debug!("visit_ty: index = {}", index); debug!("visit_ty: index = {}", index);
let lifetimes: FxIndexMap<hir::ParamName, Region> = generics let lifetimes: FxIndexMap<LocalDefId, Region> = generics
.params .params
.iter() .iter()
.filter_map(|param| match param.kind { .filter_map(|param| match param.kind {
@ -1218,15 +1173,17 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
#[tracing::instrument(level = "debug", skip(self))] #[tracing::instrument(level = "debug", skip(self))]
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
if lifetime_ref.is_elided() { match lifetime_ref.name {
self.resolve_elided_lifetimes(&[lifetime_ref]); hir::LifetimeName::ImplicitObjectLifetimeDefault
return; | 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 => {}
} }
if lifetime_ref.is_static() {
self.insert_lifetime(lifetime_ref, Region::Static);
return;
}
self.resolve_lifetime_ref(lifetime_ref);
} }
fn visit_assoc_type_binding(&mut self, type_binding: &'tcx hir::TypeBinding<'_>) { fn visit_assoc_type_binding(&mut self, type_binding: &'tcx hir::TypeBinding<'_>) {
@ -1311,7 +1268,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
ref bound_generic_params, ref bound_generic_params,
.. ..
}) => { }) => {
let (lifetimes, binders): (FxIndexMap<hir::ParamName, Region>, Vec<_>) = let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) =
bound_generic_params bound_generic_params
.iter() .iter()
.filter(|param| { .filter(|param| {
@ -1433,7 +1390,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
let (mut binders, scope_type) = self.poly_trait_ref_binder_info(); let (mut binders, scope_type) = self.poly_trait_ref_binder_info();
let initial_bound_vars = binders.len() as u32; let initial_bound_vars = binders.len() as u32;
let mut lifetimes: FxIndexMap<hir::ParamName, Region> = FxIndexMap::default(); let mut lifetimes: FxIndexMap<LocalDefId, Region> = FxIndexMap::default();
let binders_iter = trait_ref let binders_iter = trait_ref
.bound_generic_params .bound_generic_params
.iter() .iter()
@ -1580,14 +1537,17 @@ fn object_lifetime_defaults_for_item<'tcx>(
.iter() .iter()
.filter_map(|param| match param.kind { .filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => { 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, _ => None,
}) })
.enumerate() .enumerate()
.find(|&(_, (_, lt_name))| lt_name == name) .find(|&(_, (_, lt_name))| lt_name == name)
.map_or(Set1::Many, |(i, (id, _))| { .map_or(Set1::Many, |(i, (def_id, _))| {
let def_id = tcx.hir().local_def_id(id);
Set1::One(Region::EarlyBound(i as u32, def_id.to_def_id())) Set1::One(Region::EarlyBound(i as u32, def_id.to_def_id()))
}) })
} }
@ -1654,14 +1614,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
&mut self, &mut self,
parent_id: Option<LocalDefId>, parent_id: Option<LocalDefId>,
hir_id: hir::HirId, hir_id: hir::HirId,
decl: &'tcx hir::FnDecl<'tcx>,
generics: &'tcx hir::Generics<'tcx>, generics: &'tcx hir::Generics<'tcx>,
walk: F, walk: F,
) where ) where
F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>), 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. // Find the start of nested early scopes, e.g., in methods.
let mut next_early_index = 0; let mut next_early_index = 0;
if let Some(parent_id) = parent_id { if let Some(parent_id) = parent_id {
@ -1680,12 +1637,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
let mut non_lifetime_count = 0; let mut non_lifetime_count = 0;
let mut named_late_bound_vars = 0; let mut named_late_bound_vars = 0;
let lifetimes: FxIndexMap<hir::ParamName, Region> = generics let lifetimes: FxIndexMap<LocalDefId, Region> = generics
.params .params
.iter() .iter()
.filter_map(|param| match param.kind { .filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => { GenericParamKind::Lifetime { .. } => {
if self.map.late_bound.contains(&param.hir_id) { if self.tcx.is_late_bound(param.hir_id) {
let late_bound_idx = named_late_bound_vars; let late_bound_idx = named_late_bound_vars;
named_late_bound_vars += 1; named_late_bound_vars += 1;
Some(Region::late(late_bound_idx, self.tcx.hir(), param)) Some(Region::late(late_bound_idx, self.tcx.hir(), param))
@ -1706,7 +1663,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
.iter() .iter()
.filter(|param| { .filter(|param| {
matches!(param.kind, GenericParamKind::Lifetime { .. }) matches!(param.kind, GenericParamKind::Lifetime { .. })
&& self.map.late_bound.contains(&param.hir_id) && self.tcx.is_late_bound(param.hir_id)
}) })
.enumerate() .enumerate()
.map(|(late_bound_idx, param)| { .map(|(late_bound_idx, param)| {
@ -1763,14 +1720,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
self.next_early_index_helper(false) self.next_early_index_helper(false)
} }
fn resolve_lifetime_ref(&mut self, lifetime_ref: &'tcx hir::Lifetime) { #[tracing::instrument(level = "debug", skip(self))]
debug!("resolve_lifetime_ref(lifetime_ref={:?})", lifetime_ref); fn resolve_lifetime_ref(
&mut self,
// If we've already reported an error, just ignore `lifetime_ref`. region_def_id: LocalDefId,
if let LifetimeName::Error = lifetime_ref.name { lifetime_ref: &'tcx hir::Lifetime,
return; ) {
}
// Walk up the scope chain, tracking the number of fn scopes // Walk up the scope chain, tracking the number of fn scopes
// that we pass through, until we find a lifetime with the // that we pass through, until we find a lifetime with the
// given name or we run out of scopes. // given name or we run out of scopes.
@ -1790,14 +1745,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
} }
Scope::Binder { ref lifetimes, scope_type, s, .. } => { Scope::Binder { ref lifetimes, scope_type, s, .. } => {
match lifetime_ref.name { if let Some(&def) = lifetimes.get(&region_def_id) {
LifetimeName::Param(param_name) => { break Some(def.shifted(late_depth));
if let Some(&def) = lifetimes.get(&param_name.normalize_to_macros_2_0())
{
break Some(def.shifted(late_depth));
}
}
_ => bug!("expected LifetimeName::Param"),
} }
match scope_type { match scope_type {
BinderScopeType::Normal => late_depth += 1, BinderScopeType::Normal => late_depth += 1,
@ -2473,8 +2422,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
let mut late_depth = 0; let mut late_depth = 0;
let mut scope = self.scope; let mut scope = self.scope;
let mut lifetime_names = FxHashSet::default(); let mut in_scope_lifetimes = FxIndexSet::default();
let mut lifetime_spans = vec![];
let error = loop { let error = loop {
match *scope { match *scope {
// Do not assign any resolution, it will be inferred. // Do not assign any resolution, it will be inferred.
@ -2484,12 +2432,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
Scope::Binder { s, ref lifetimes, scope_type, .. } => { Scope::Binder { s, ref lifetimes, scope_type, .. } => {
// collect named lifetimes for suggestions // collect named lifetimes for suggestions
for name in lifetimes.keys() { in_scope_lifetimes.extend(lifetimes.keys().copied());
if let hir::ParamName::Plain(name) = name {
lifetime_names.insert(name.name);
lifetime_spans.push(name.span);
}
}
match scope_type { match scope_type {
BinderScopeType::Normal => late_depth += 1, BinderScopeType::Normal => late_depth += 1,
BinderScopeType::Concatenating => {} BinderScopeType::Concatenating => {}
@ -2524,12 +2467,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
match scope { match scope {
Scope::Binder { ref lifetimes, s, .. } => { Scope::Binder { ref lifetimes, s, .. } => {
// Collect named lifetimes for suggestions. // Collect named lifetimes for suggestions.
for name in lifetimes.keys() { in_scope_lifetimes.extend(lifetimes.keys().copied());
if let hir::ParamName::Plain(name) = name {
lifetime_names.insert(name.name);
lifetime_spans.push(name.span);
}
}
scope = s; scope = s;
} }
Scope::ObjectLifetimeDefault { ref s, .. } Scope::ObjectLifetimeDefault { ref s, .. }
@ -2574,19 +2512,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
let mut err = self.report_missing_lifetime_specifiers(spans.clone(), lifetime_refs.len()); 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( self.add_missing_lifetime_specifiers_label(
&mut err, &mut err,
spans_with_counts, spans_with_counts,
&lifetime_names, in_scope_lifetimes,
lifetime_spans, error,
error.unwrap_or(&[]),
); );
err.emit(); err.emit();
} }
@ -2638,7 +2568,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
} }
/// Detects late-bound lifetimes and inserts them into /// Detects late-bound lifetimes and inserts them into
/// `map.late_bound`. /// `late_bound`.
/// ///
/// A region declared on a fn is **late-bound** if: /// A region declared on a fn is **late-bound** if:
/// - it is constrained by an argument type; /// - it is constrained by an argument type;
@ -2647,12 +2577,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
/// "Constrained" basically means that it appears in any type but /// "Constrained" basically means that it appears in any type but
/// not amongst the inputs to a projection. In other words, `<&'a /// not amongst the inputs to a projection. In other words, `<&'a
/// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`. /// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`.
#[tracing::instrument(level = "debug", skip(map))] fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxHashSet<LocalDefId>> {
fn insert_late_bound_lifetimes( let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
map: &mut NamedRegionMap, let decl = tcx.hir().fn_decl_by_hir_id(hir_id)?;
decl: &hir::FnDecl<'_>, let generics = tcx.hir().get_generics(def_id)?;
generics: &hir::Generics<'_>,
) { let mut late_bound = FxHashSet::default();
let mut constrained_by_input = ConstrainedCollector::default(); let mut constrained_by_input = ConstrainedCollector::default();
for arg_ty in decl.inputs { for arg_ty in decl.inputs {
constrained_by_input.visit_ty(arg_ty); constrained_by_input.visit_ty(arg_ty);
@ -2683,30 +2614,32 @@ fn insert_late_bound_lifetimes(
hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => continue, 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. // appears in the where clauses? early-bound.
if appears_in_where_clause.regions.contains(&lt_name) { if appears_in_where_clause.regions.contains(&param_def_id) {
continue; continue;
} }
// does not appear in the inputs, but appears in the return type? early-bound. // does not appear in the inputs, but appears in the return type? early-bound.
if !constrained_by_input.regions.contains(&lt_name) if !constrained_by_input.regions.contains(&param_def_id)
&& appears_in_output.regions.contains(&lt_name) && appears_in_output.regions.contains(&param_def_id)
{ {
continue; continue;
} }
debug!("lifetime {:?} with id {:?} is late-bound", param.name.ident(), param.hir_id); debug!("lifetime {:?} with id {:?} is late-bound", param.name.ident(), param.hir_id);
let inserted = map.late_bound.insert(param.hir_id); let inserted = late_bound.insert(param_def_id);
assert!(inserted, "visited lifetime {:?} twice", param.hir_id); assert!(inserted, "visited lifetime {:?} twice", param.hir_id);
} }
return; debug!(?late_bound);
return Some(tcx.arena.alloc(late_bound));
#[derive(Default)] #[derive(Default)]
struct ConstrainedCollector { struct ConstrainedCollector {
regions: FxHashSet<hir::LifetimeName>, regions: FxHashSet<LocalDefId>,
} }
impl<'v> Visitor<'v> for ConstrainedCollector { impl<'v> Visitor<'v> for ConstrainedCollector {
@ -2738,18 +2671,22 @@ fn insert_late_bound_lifetimes(
} }
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { 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)] #[derive(Default)]
struct AllCollector { struct AllCollector {
regions: FxHashSet<hir::LifetimeName>, regions: FxHashSet<LocalDefId>,
} }
impl<'v> Visitor<'v> for AllCollector { impl<'v> Visitor<'v> for AllCollector {
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { 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);
}
} }
} }
} }

View file

@ -1364,7 +1364,6 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
fn has_late_bound_regions<'tcx>( fn has_late_bound_regions<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
generics: &'tcx hir::Generics<'tcx>, generics: &'tcx hir::Generics<'tcx>,
decl: &'tcx hir::FnDecl<'tcx>, decl: &'tcx hir::FnDecl<'tcx>,
) -> Option<Span> { ) -> Option<Span> {
@ -1373,14 +1372,9 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
outer_index: ty::INNERMOST, outer_index: ty::INNERMOST,
has_late_bound_regions: None, has_late_bound_regions: None,
}; };
let late_bound_map = tcx.is_late_bound_map(def_id);
let is_late_bound = |id| {
let id = tcx.hir().local_def_id(id);
late_bound_map.map_or(false, |(_, set)| set.contains(&id))
};
for param in generics.params { for param in generics.params {
if let GenericParamKind::Lifetime { .. } = param.kind { if let GenericParamKind::Lifetime { .. } = param.kind {
if is_late_bound(param.hir_id) { if tcx.is_late_bound(param.hir_id) {
return Some(param.span); return Some(param.span);
} }
} }
@ -1392,25 +1386,25 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
match node { match node {
Node::TraitItem(item) => match item.kind { Node::TraitItem(item) => match item.kind {
hir::TraitItemKind::Fn(ref sig, _) => { hir::TraitItemKind::Fn(ref sig, _) => {
has_late_bound_regions(tcx, item.def_id, &item.generics, sig.decl) has_late_bound_regions(tcx, &item.generics, sig.decl)
} }
_ => None, _ => None,
}, },
Node::ImplItem(item) => match item.kind { Node::ImplItem(item) => match item.kind {
hir::ImplItemKind::Fn(ref sig, _) => { hir::ImplItemKind::Fn(ref sig, _) => {
has_late_bound_regions(tcx, item.def_id, &item.generics, sig.decl) has_late_bound_regions(tcx, &item.generics, sig.decl)
} }
_ => None, _ => None,
}, },
Node::ForeignItem(item) => match item.kind { Node::ForeignItem(item) => match item.kind {
hir::ForeignItemKind::Fn(fn_decl, _, ref generics) => { hir::ForeignItemKind::Fn(fn_decl, _, ref generics) => {
has_late_bound_regions(tcx, item.def_id, generics, fn_decl) has_late_bound_regions(tcx, generics, fn_decl)
} }
_ => None, _ => None,
}, },
Node::Item(item) => match item.kind { Node::Item(item) => match item.kind {
hir::ItemKind::Fn(ref sig, .., ref generics, _) => { hir::ItemKind::Fn(ref sig, .., ref generics, _) => {
has_late_bound_regions(tcx, item.def_id, generics, sig.decl) has_late_bound_regions(tcx, generics, sig.decl)
} }
_ => None, _ => None,
}, },
@ -1671,7 +1665,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
params.push(opt_self); params.push(opt_self);
} }
let early_lifetimes = early_bound_lifetimes_from_generics(tcx, hir_id.owner, ast_generics); let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics);
params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef { params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef {
name: param.name.ident().name, name: param.name.ident().name,
index: own_start + i as u32, index: own_start + i as u32,
@ -2054,23 +2048,10 @@ fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ImplPolarity {
/// `resolve_lifetime::early_bound_lifetimes`. /// `resolve_lifetime::early_bound_lifetimes`.
fn early_bound_lifetimes_from_generics<'a, 'tcx: 'a>( fn early_bound_lifetimes_from_generics<'a, 'tcx: 'a>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
generics: &'a hir::Generics<'a>, generics: &'a hir::Generics<'a>,
) -> impl Iterator<Item = &'a hir::GenericParam<'a>> + Captures<'tcx> { ) -> impl Iterator<Item = &'a hir::GenericParam<'a>> + Captures<'tcx> {
let late_bound_map = if generics.params.is_empty() {
// This function may be called on `def_id == CRATE_DEF_ID`,
// which makes `is_late_bound_map` ICE. Don't even try if there
// is no generic parameter.
None
} else {
tcx.is_late_bound_map(def_id)
};
let is_late_bound = move |hir_id| {
let id = tcx.hir().local_def_id(hir_id);
late_bound_map.map_or(false, |(_, set)| set.contains(&id))
};
generics.params.iter().filter(move |param| match param.kind { generics.params.iter().filter(move |param| match param.kind {
GenericParamKind::Lifetime { .. } => !is_late_bound(param.hir_id), GenericParamKind::Lifetime { .. } => !tcx.is_late_bound(param.hir_id),
_ => false, _ => false,
}) })
} }
@ -2255,7 +2236,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
// have to be careful to only iterate over early-bound regions. // have to be careful to only iterate over early-bound regions.
let mut index = parent_count let mut index = parent_count
+ has_own_self as u32 + has_own_self as u32
+ early_bound_lifetimes_from_generics(tcx, hir_id.owner, ast_generics).count() as u32; + early_bound_lifetimes_from_generics(tcx, ast_generics).count() as u32;
// Collect the predicates that were written inline by the user on each // Collect the predicates that were written inline by the user on each
// type parameter (e.g., `<T: Foo>`). // type parameter (e.g., `<T: Foo>`).

View file

@ -514,7 +514,9 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
param_names param_names
.iter() .iter()
.take(num_params_to_take) .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::<Vec<_>>() .collect::<Vec<_>>()
.join(", ") .join(", ")
} else { } else {

View file

@ -475,24 +475,14 @@ fn clean_generic_param<'tcx>(
generics: Option<&hir::Generics<'tcx>>, generics: Option<&hir::Generics<'tcx>>,
param: &hir::GenericParam<'tcx>, param: &hir::GenericParam<'tcx>,
) -> GenericParamDef { ) -> GenericParamDef {
let did = cx.tcx.hir().local_def_id(param.hir_id);
let (name, kind) = match param.kind { let (name, kind) = match param.kind {
hir::GenericParamKind::Lifetime { .. } => { hir::GenericParamKind::Lifetime { .. } => {
let outlives = if let Some(generics) = generics { let outlives = if let Some(generics) = generics {
generics generics
.predicates .outlives_for_param(did)
.iter() .filter(|bp| !bp.in_where_clause)
.flat_map(|pred| { .flat_map(|bp| bp.bounds)
match pred {
hir::WherePredicate::RegionPredicate(rp)
if rp.lifetime.name == hir::LifetimeName::Param(param.name)
&& !rp.in_where_clause =>
{
rp.bounds
}
_ => &[],
}
.iter()
})
.map(|bound| match bound { .map(|bound| match bound {
hir::GenericBound::Outlives(lt) => lt.clean(cx), hir::GenericBound::Outlives(lt) => lt.clean(cx),
_ => panic!(), _ => panic!(),
@ -504,7 +494,6 @@ fn clean_generic_param<'tcx>(
(param.name.ident().name, GenericParamDefKind::Lifetime { outlives }) (param.name.ident().name, GenericParamDefKind::Lifetime { outlives })
} }
hir::GenericParamKind::Type { ref default, synthetic } => { hir::GenericParamKind::Type { ref default, synthetic } => {
let did = cx.tcx.hir().local_def_id(param.hir_id);
let bounds = if let Some(generics) = generics { let bounds = if let Some(generics) = generics {
generics generics
.bounds_for_param(did) .bounds_for_param(did)
@ -528,7 +517,7 @@ fn clean_generic_param<'tcx>(
hir::GenericParamKind::Const { ty, default } => ( hir::GenericParamKind::Const { ty, default } => (
param.name.ident().name, param.name.ident().name,
GenericParamDefKind::Const { 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)), ty: Box::new(ty.clean(cx)),
default: default.map(|ct| { default: default.map(|ct| {
let def_id = cx.tcx.hir().local_def_id(ct.hir_id); 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; // 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. // there's no case where it could cause the function to fail to compile.
let elided = 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)) }; let lifetime = if elided { None } else { Some(l.clean(cx)) };
BorrowedRef { lifetime, mutability: m.mutbl, type_: box m.ty.clean(cx) } BorrowedRef { lifetime, mutability: m.mutbl, type_: box m.ty.clean(cx) }
} }

View file

@ -371,7 +371,7 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
if let Some(ref lt) = *lifetime { if let Some(ref lt) = *lifetime {
if lt.name == LifetimeName::Static { if lt.name == LifetimeName::Static {
self.lts.push(RefLt::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. // Fresh lifetimes generated should be ignored.
} else if lt.is_elided() { } else if lt.is_elided() {
self.lts.push(RefLt::Unnamed); self.lts.push(RefLt::Unnamed);

View file

@ -343,7 +343,7 @@ impl fmt::Display for RefPrefix {
use fmt::Write; use fmt::Write;
f.write_char('&')?; f.write_char('&')?;
match self.lt { match self.lt {
LifetimeName::Param(ParamName::Plain(name)) => { LifetimeName::Param(_, ParamName::Plain(name)) => {
name.fmt(f)?; name.fmt(f)?;
f.write_char(' ')?; f.write_char(' ')?;
}, },

View file

@ -902,16 +902,14 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
pub fn hash_lifetime(&mut self, lifetime: Lifetime) { pub fn hash_lifetime(&mut self, lifetime: Lifetime) {
std::mem::discriminant(&lifetime.name).hash(&mut self.s); 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); std::mem::discriminant(name).hash(&mut self.s);
param_id.hash(&mut self.s);
match name { match name {
ParamName::Plain(ref ident) => { ParamName::Plain(ref ident) => {
ident.name.hash(&mut self.s); ident.name.hash(&mut self.s);
}, },
ParamName::Fresh(ref size) => { ParamName::Fresh | ParamName::Error => {},
size.hash(&mut self.s);
},
ParamName::Error => {},
} }
} }
} }