mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
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:
commit
53ab3b2e6e
@ -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 }
|
||||
}
|
||||
|
||||
|
@ -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 => {
|
||||
|
@ -830,11 +830,11 @@ fn for_each_late_bound_region_defined_on<'tcx>(
|
||||
fn_def_id: DefId,
|
||||
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 ®ion_def_id in late_bounds.iter() {
|
||||
let name = tcx.item_name(region_def_id.to_def_id());
|
||||
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),
|
||||
}));
|
||||
f(liberated_region);
|
||||
|
@ -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<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> {
|
||||
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> {
|
||||
|
@ -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 { .. } => {}
|
||||
|
@ -364,7 +364,11 @@ impl<'hir> Map<'hir> {
|
||||
match node.node {
|
||||
OwnerNode::ImplItem(impl_item) => Some(&impl_item.generics),
|
||||
OwnerNode::TraitItem(trait_item) => Some(&trait_item.generics),
|
||||
OwnerNode::Item(Item {
|
||||
OwnerNode::ForeignItem(ForeignItem {
|
||||
kind: ForeignItemKind::Fn(_, _, generics),
|
||||
..
|
||||
})
|
||||
| OwnerNode::Item(Item {
|
||||
kind:
|
||||
ItemKind::Fn(_, generics, _)
|
||||
| ItemKind::TyAlias(_, generics)
|
||||
|
@ -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<Symbol>),
|
||||
/// Contains all lifetime names that are in scope and could possibly be used in generics
|
||||
/// arguments of path.
|
||||
NonElided(Vec<LocalDefId>),
|
||||
|
||||
// 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,
|
||||
}
|
||||
|
||||
|
@ -1584,7 +1584,7 @@ rustc_queries! {
|
||||
Option<&'tcx FxHashMap<ItemLocalId, 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" }
|
||||
}
|
||||
/// For a given item (like a struct), gets the default lifetimes to be used
|
||||
|
@ -2803,6 +2803,13 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
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> {
|
||||
self.mk_bound_variable_kinds(
|
||||
self.late_bound_vars_map(id.owner)
|
||||
|
@ -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<Symbol>,
|
||||
lifetime_spans: Vec<Span>,
|
||||
params: &[ElisionFailureInfo],
|
||||
in_scope_lifetimes: FxIndexSet<LocalDefId>,
|
||||
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<Option<String>> = spans_with_counts
|
||||
.iter()
|
||||
.map(|(span, _)| self.tcx.sess.source_map().span_to_snippet(*span).ok())
|
||||
|
@ -8,19 +8,19 @@
|
||||
|
||||
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::{GenericParamKind, HirIdMap, HirIdSet};
|
||||
use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node};
|
||||
use rustc_hir::{GenericParamKind, HirIdMap};
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
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_span::def_id::DefId;
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
@ -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<u32>) -> 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<u32>) -> Region {
|
||||
@ -134,11 +134,6 @@ struct NamedRegionMap {
|
||||
// `Region` describing how that region is bound
|
||||
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:
|
||||
// - function defs
|
||||
// - function pointers
|
||||
@ -178,7 +173,7 @@ enum Scope<'a> {
|
||||
Binder {
|
||||
/// We use an IndexMap here because we want these lifetimes in order
|
||||
/// for diagnostics.
|
||||
lifetimes: FxIndexMap<hir::ParamName, Region>,
|
||||
lifetimes: FxIndexMap<LocalDefId, Region>,
|
||||
|
||||
/// if we extend this scope with another scope, what is the next index
|
||||
/// we should use for an early-bound region?
|
||||
@ -402,7 +397,7 @@ fn resolve_lifetimes_trait_definition(
|
||||
tcx: TyCtxt<'_>,
|
||||
local_def_id: LocalDefId,
|
||||
) -> 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`.
|
||||
@ -410,7 +405,7 @@ fn resolve_lifetimes_trait_definition(
|
||||
/// `named_region_map`, `is_late_bound_map`, etc.
|
||||
#[tracing::instrument(level = "debug", skip(tcx))]
|
||||
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(
|
||||
@ -422,7 +417,6 @@ fn do_resolve(
|
||||
let item = tcx.hir().expect_item(local_def_id);
|
||||
let mut named_region_map = NamedRegionMap {
|
||||
defs: Default::default(),
|
||||
late_bound: Default::default(),
|
||||
late_bound_vars: Default::default(),
|
||||
scope_for_path: with_scope_for_path.then(|| Default::default()),
|
||||
};
|
||||
@ -439,18 +433,13 @@ fn do_resolve(
|
||||
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();
|
||||
|
||||
for (hir_id, v) in named_region_map.defs {
|
||||
let map = rl.defs.entry(hir_id.owner).or_default();
|
||||
map.insert(hir_id.local_id, v);
|
||||
}
|
||||
for hir_id in named_region_map.late_bound {
|
||||
let map = rl.late_bound.entry(hir_id.owner).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 {
|
||||
let map = rl.late_bound_vars.entry(hir_id.owner).or_default();
|
||||
map.insert(hir_id.local_id, v);
|
||||
@ -506,28 +495,6 @@ fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> LocalDefId {
|
||||
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.
|
||||
/// 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.
|
||||
@ -554,10 +521,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, .. } => {
|
||||
@ -690,9 +654,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||
_ => {}
|
||||
}
|
||||
match item.kind {
|
||||
hir::ItemKind::Fn(ref sig, ref generics, _) => {
|
||||
hir::ItemKind::Fn(_, ref generics, _) => {
|
||||
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);
|
||||
});
|
||||
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);
|
||||
});
|
||||
}
|
||||
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
|
||||
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>) {
|
||||
match item.kind {
|
||||
hir::ForeignItemKind::Fn(ref decl, _, ref generics) => {
|
||||
self.visit_early_late(None, item.hir_id(), decl, generics, |this| {
|
||||
hir::ForeignItemKind::Fn(_, _, ref generics) => {
|
||||
self.visit_early_late(None, item.hir_id(), generics, |this| {
|
||||
intravisit::walk_foreign_item(this, item);
|
||||
})
|
||||
}
|
||||
@ -841,7 +798,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<hir::ParamName, Region>, Vec<_>) = c
|
||||
let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) = c
|
||||
.generic_params
|
||||
.iter()
|
||||
.filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
|
||||
@ -898,7 +855,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 +973,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 { .. } => {
|
||||
@ -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>) {
|
||||
use self::hir::TraitItemKind::*;
|
||||
match trait_item.kind {
|
||||
Fn(ref sig, _) => {
|
||||
Fn(_, _) => {
|
||||
self.missing_named_lifetime_spots.push((&trait_item.generics).into());
|
||||
let tcx = self.tcx;
|
||||
self.visit_early_late(
|
||||
Some(tcx.hir().get_parent_item(trait_item.hir_id())),
|
||||
trait_item.hir_id(),
|
||||
&sig.decl,
|
||||
&trait_item.generics,
|
||||
|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>) {
|
||||
use self::hir::ImplItemKind::*;
|
||||
match impl_item.kind {
|
||||
Fn(ref sig, _) => {
|
||||
Fn(..) => {
|
||||
self.missing_named_lifetime_spots.push((&impl_item.generics).into());
|
||||
let tcx = self.tcx;
|
||||
self.visit_early_late(
|
||||
Some(tcx.hir().get_parent_item(impl_item.hir_id())),
|
||||
impl_item.hir_id(),
|
||||
&sig.decl,
|
||||
&impl_item.generics,
|
||||
|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 non_lifetime_count = 0;
|
||||
debug!("visit_ty: index = {}", index);
|
||||
let lifetimes: FxIndexMap<hir::ParamName, Region> = generics
|
||||
let lifetimes: FxIndexMap<LocalDefId, Region> = generics
|
||||
.params
|
||||
.iter()
|
||||
.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))]
|
||||
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
|
||||
if lifetime_ref.is_elided() {
|
||||
self.resolve_elided_lifetimes(&[lifetime_ref]);
|
||||
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 => {}
|
||||
}
|
||||
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<'_>) {
|
||||
@ -1311,7 +1268,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||
ref bound_generic_params,
|
||||
..
|
||||
}) => {
|
||||
let (lifetimes, binders): (FxIndexMap<hir::ParamName, Region>, Vec<_>) =
|
||||
let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) =
|
||||
bound_generic_params
|
||||
.iter()
|
||||
.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 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
|
||||
.bound_generic_params
|
||||
.iter()
|
||||
@ -1580,14 +1537,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()))
|
||||
})
|
||||
}
|
||||
@ -1654,14 +1614,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||
&mut self,
|
||||
parent_id: Option<LocalDefId>,
|
||||
hir_id: hir::HirId,
|
||||
decl: &'tcx hir::FnDecl<'tcx>,
|
||||
generics: &'tcx hir::Generics<'tcx>,
|
||||
walk: F,
|
||||
) where
|
||||
F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>),
|
||||
{
|
||||
insert_late_bound_lifetimes(self.map, decl, generics);
|
||||
|
||||
// Find the start of nested early scopes, e.g., in methods.
|
||||
let mut next_early_index = 0;
|
||||
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 named_late_bound_vars = 0;
|
||||
let lifetimes: FxIndexMap<hir::ParamName, Region> = generics
|
||||
let lifetimes: FxIndexMap<LocalDefId, Region> = generics
|
||||
.params
|
||||
.iter()
|
||||
.filter_map(|param| match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => {
|
||||
if self.map.late_bound.contains(¶m.hir_id) {
|
||||
if self.tcx.is_late_bound(param.hir_id) {
|
||||
let late_bound_idx = named_late_bound_vars;
|
||||
named_late_bound_vars += 1;
|
||||
Some(Region::late(late_bound_idx, self.tcx.hir(), param))
|
||||
@ -1706,7 +1663,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||
.iter()
|
||||
.filter(|param| {
|
||||
matches!(param.kind, GenericParamKind::Lifetime { .. })
|
||||
&& self.map.late_bound.contains(¶m.hir_id)
|
||||
&& self.tcx.is_late_bound(param.hir_id)
|
||||
})
|
||||
.enumerate()
|
||||
.map(|(late_bound_idx, param)| {
|
||||
@ -1763,14 +1720,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 +1745,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 +2422,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 +2432,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 +2467,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 +2512,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();
|
||||
}
|
||||
@ -2638,7 +2568,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||
}
|
||||
|
||||
/// Detects late-bound lifetimes and inserts them into
|
||||
/// `map.late_bound`.
|
||||
/// `late_bound`.
|
||||
///
|
||||
/// A region declared on a fn is **late-bound** if:
|
||||
/// - 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
|
||||
/// 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))]
|
||||
fn insert_late_bound_lifetimes(
|
||||
map: &mut NamedRegionMap,
|
||||
decl: &hir::FnDecl<'_>,
|
||||
generics: &hir::Generics<'_>,
|
||||
) {
|
||||
fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxHashSet<LocalDefId>> {
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
let decl = tcx.hir().fn_decl_by_hir_id(hir_id)?;
|
||||
let generics = tcx.hir().get_generics(def_id)?;
|
||||
|
||||
let mut late_bound = FxHashSet::default();
|
||||
|
||||
let mut constrained_by_input = ConstrainedCollector::default();
|
||||
for arg_ty in decl.inputs {
|
||||
constrained_by_input.visit_ty(arg_ty);
|
||||
@ -2683,30 +2614,32 @@ 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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return;
|
||||
debug!(?late_bound);
|
||||
return Some(tcx.arena.alloc(late_bound));
|
||||
|
||||
#[derive(Default)]
|
||||
struct ConstrainedCollector {
|
||||
regions: FxHashSet<hir::LifetimeName>,
|
||||
regions: FxHashSet<LocalDefId>,
|
||||
}
|
||||
|
||||
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) {
|
||||
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<hir::LifetimeName>,
|
||||
regions: FxHashSet<LocalDefId>,
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1364,7 +1364,6 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
|
||||
|
||||
fn has_late_bound_regions<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
generics: &'tcx hir::Generics<'tcx>,
|
||||
decl: &'tcx hir::FnDecl<'tcx>,
|
||||
) -> Option<Span> {
|
||||
@ -1373,14 +1372,9 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
|
||||
outer_index: ty::INNERMOST,
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -1392,25 +1386,25 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
|
||||
match node {
|
||||
Node::TraitItem(item) => match item.kind {
|
||||
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,
|
||||
},
|
||||
Node::ImplItem(item) => match item.kind {
|
||||
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,
|
||||
},
|
||||
Node::ForeignItem(item) => match item.kind {
|
||||
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,
|
||||
},
|
||||
Node::Item(item) => match item.kind {
|
||||
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,
|
||||
},
|
||||
@ -1671,7 +1665,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
|
||||
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 {
|
||||
name: param.name.ident().name,
|
||||
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`.
|
||||
fn early_bound_lifetimes_from_generics<'a, 'tcx: 'a>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
generics: &'a hir::Generics<'a>,
|
||||
) -> 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 {
|
||||
GenericParamKind::Lifetime { .. } => !is_late_bound(param.hir_id),
|
||||
GenericParamKind::Lifetime { .. } => !tcx.is_late_bound(param.hir_id),
|
||||
_ => 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.
|
||||
let mut index = parent_count
|
||||
+ 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
|
||||
// type parameter (e.g., `<T: Foo>`).
|
||||
|
@ -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::<Vec<_>>()
|
||||
.join(", ")
|
||||
} else {
|
||||
|
@ -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) }
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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(' ')?;
|
||||
},
|
||||
|
@ -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 => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user