1
Fork 0

Manipulate lifetimes by LocalDefId for region resolution.

This commit is contained in:
Camille GILLOT 2022-04-27 22:15:58 +02:00
parent 3a90bedb33
commit b1294e86bb
12 changed files with 161 additions and 170 deletions

View file

@ -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())

View file

@ -8,14 +8,14 @@
use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot};
use rustc_ast::walk_list;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefIdMap, LocalDefId};
use rustc_hir::hir_id::ItemLocalId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node, ParamName};
use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node};
use rustc_hir::{GenericParamKind, HirIdMap, HirIdSet};
use rustc_middle::hir::map::Map;
use rustc_middle::hir::nested_filter;
@ -33,9 +33,9 @@ use std::mem::take;
use tracing::{debug, span, Level};
trait RegionExt {
fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region);
fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region);
fn late(index: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region);
fn late(index: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region);
fn late_anon(named_late_bound_vars: u32, index: &Cell<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 {
@ -178,7 +178,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?
@ -554,10 +554,7 @@ fn get_lifetime_scopes_for_path(mut scope: &Scope<'_>) -> LifetimeScopeForPath {
loop {
match scope {
Scope::Binder { lifetimes, s, .. } => {
available_lifetimes.extend(lifetimes.keys().filter_map(|p| match p {
hir::ParamName::Plain(ident) => Some(ident.name),
_ => None,
}));
available_lifetimes.extend(lifetimes.keys());
scope = s;
}
Scope::Body { s, .. } => {
@ -841,7 +838,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
};
self.missing_named_lifetime_spots
.push(MissingLifetimeSpot::HigherRanked { span, span_type });
let (lifetimes, binders): (FxIndexMap<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 +895,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// cc #48468
self.resolve_elided_lifetimes(&[lifetime])
}
LifetimeName::Param(_) | LifetimeName::Static => {
LifetimeName::Param(..) | LifetimeName::Static => {
// If the user wrote an explicit name, use that.
self.visit_lifetime(lifetime);
}
@ -1016,17 +1013,17 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
for param in generics.params {
match param.kind {
GenericParamKind::Lifetime { .. } => {
let (name, reg) = Region::early(self.tcx.hir(), &mut index, &param);
let (def_id, reg) = Region::early(self.tcx.hir(), &mut index, &param);
if let hir::ParamName::Plain(Ident {
name: kw::UnderscoreLifetime,
..
}) = name
}) = param.name
{
// Pick the elided lifetime "definition" if one exists
// and use it to make an elision scope.
elision = Some(reg);
} else {
lifetimes.insert(name, reg);
lifetimes.insert(def_id, reg);
}
}
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
@ -1174,7 +1171,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
let mut index = self.next_early_index();
let mut non_lifetime_count = 0;
debug!("visit_ty: index = {}", index);
let lifetimes: FxIndexMap<hir::ParamName, Region> = generics
let lifetimes: FxIndexMap<LocalDefId, Region> = generics
.params
.iter()
.filter_map(|param| match param.kind {
@ -1218,15 +1215,17 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
#[tracing::instrument(level = "debug", skip(self))]
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
if lifetime_ref.is_elided() {
self.resolve_elided_lifetimes(&[lifetime_ref]);
return;
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 +1310,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 +1432,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
let (mut binders, scope_type) = self.poly_trait_ref_binder_info();
let initial_bound_vars = binders.len() as u32;
let mut lifetimes: FxIndexMap<hir::ParamName, Region> = FxIndexMap::default();
let mut lifetimes: FxIndexMap<LocalDefId, Region> = FxIndexMap::default();
let binders_iter = trait_ref
.bound_generic_params
.iter()
@ -1580,14 +1579,17 @@ fn object_lifetime_defaults_for_item<'tcx>(
.iter()
.filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => {
Some((param.hir_id, hir::LifetimeName::Param(param.name)))
let param_def_id = tcx.hir().local_def_id(param.hir_id);
Some((
param_def_id,
hir::LifetimeName::Param(param_def_id, param.name),
))
}
_ => None,
})
.enumerate()
.find(|&(_, (_, lt_name))| lt_name == name)
.map_or(Set1::Many, |(i, (id, _))| {
let def_id = tcx.hir().local_def_id(id);
.map_or(Set1::Many, |(i, (def_id, _))| {
Set1::One(Region::EarlyBound(i as u32, def_id.to_def_id()))
})
}
@ -1660,7 +1662,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
) where
F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>),
{
insert_late_bound_lifetimes(self.map, decl, generics);
insert_late_bound_lifetimes(self.tcx, self.map, decl, generics);
// Find the start of nested early scopes, e.g., in methods.
let mut next_early_index = 0;
@ -1680,7 +1682,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
let mut non_lifetime_count = 0;
let mut named_late_bound_vars = 0;
let lifetimes: FxIndexMap<hir::ParamName, Region> = generics
let lifetimes: FxIndexMap<LocalDefId, Region> = generics
.params
.iter()
.filter_map(|param| match param.kind {
@ -1763,14 +1765,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
self.next_early_index_helper(false)
}
fn resolve_lifetime_ref(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
debug!("resolve_lifetime_ref(lifetime_ref={:?})", lifetime_ref);
// If we've already reported an error, just ignore `lifetime_ref`.
if let LifetimeName::Error = lifetime_ref.name {
return;
}
#[tracing::instrument(level = "debug", skip(self))]
fn resolve_lifetime_ref(
&mut self,
region_def_id: LocalDefId,
lifetime_ref: &'tcx hir::Lifetime,
) {
// Walk up the scope chain, tracking the number of fn scopes
// that we pass through, until we find a lifetime with the
// given name or we run out of scopes.
@ -1790,14 +1790,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}
Scope::Binder { ref lifetimes, scope_type, s, .. } => {
match lifetime_ref.name {
LifetimeName::Param(param_name) => {
if let Some(&def) = lifetimes.get(&param_name.normalize_to_macros_2_0())
{
break Some(def.shifted(late_depth));
}
}
_ => bug!("expected LifetimeName::Param"),
if let Some(&def) = lifetimes.get(&region_def_id) {
break Some(def.shifted(late_depth));
}
match scope_type {
BinderScopeType::Normal => late_depth += 1,
@ -2473,8 +2467,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
let mut late_depth = 0;
let mut scope = self.scope;
let mut lifetime_names = FxHashSet::default();
let mut lifetime_spans = vec![];
let mut in_scope_lifetimes = FxIndexSet::default();
let error = loop {
match *scope {
// Do not assign any resolution, it will be inferred.
@ -2484,12 +2477,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
Scope::Binder { s, ref lifetimes, scope_type, .. } => {
// collect named lifetimes for suggestions
for name in lifetimes.keys() {
if let hir::ParamName::Plain(name) = name {
lifetime_names.insert(name.name);
lifetime_spans.push(name.span);
}
}
in_scope_lifetimes.extend(lifetimes.keys().copied());
match scope_type {
BinderScopeType::Normal => late_depth += 1,
BinderScopeType::Concatenating => {}
@ -2524,12 +2512,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
match scope {
Scope::Binder { ref lifetimes, s, .. } => {
// Collect named lifetimes for suggestions.
for name in lifetimes.keys() {
if let hir::ParamName::Plain(name) = name {
lifetime_names.insert(name.name);
lifetime_spans.push(name.span);
}
}
in_scope_lifetimes.extend(lifetimes.keys().copied());
scope = s;
}
Scope::ObjectLifetimeDefault { ref s, .. }
@ -2574,19 +2557,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
let mut err = self.report_missing_lifetime_specifiers(spans.clone(), lifetime_refs.len());
if let Some(params) = error {
// If there's no lifetime available, suggest `'static`.
if self.report_elision_failure(&mut err, params) && lifetime_names.is_empty() {
lifetime_names.insert(kw::StaticLifetime);
}
}
self.add_missing_lifetime_specifiers_label(
&mut err,
spans_with_counts,
&lifetime_names,
lifetime_spans,
error.unwrap_or(&[]),
in_scope_lifetimes,
error,
);
err.emit();
}
@ -2647,8 +2622,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
/// "Constrained" basically means that it appears in any type but
/// not amongst the inputs to a projection. In other words, `<&'a
/// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`.
#[tracing::instrument(level = "debug", skip(map))]
#[tracing::instrument(level = "debug", skip(tcx, map))]
fn insert_late_bound_lifetimes(
tcx: TyCtxt<'_>,
map: &mut NamedRegionMap,
decl: &hir::FnDecl<'_>,
generics: &hir::Generics<'_>,
@ -2683,15 +2659,16 @@ fn insert_late_bound_lifetimes(
hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => continue,
}
let lt_name = hir::LifetimeName::Param(param.name.normalize_to_macros_2_0());
let param_def_id = tcx.hir().local_def_id(param.hir_id);
// appears in the where clauses? early-bound.
if appears_in_where_clause.regions.contains(&lt_name) {
if appears_in_where_clause.regions.contains(&param_def_id) {
continue;
}
// does not appear in the inputs, but appears in the return type? early-bound.
if !constrained_by_input.regions.contains(&lt_name)
&& appears_in_output.regions.contains(&lt_name)
if !constrained_by_input.regions.contains(&param_def_id)
&& appears_in_output.regions.contains(&param_def_id)
{
continue;
}
@ -2706,7 +2683,7 @@ fn insert_late_bound_lifetimes(
#[derive(Default)]
struct ConstrainedCollector {
regions: FxHashSet<hir::LifetimeName>,
regions: FxHashSet<LocalDefId>,
}
impl<'v> Visitor<'v> for ConstrainedCollector {
@ -2738,18 +2715,22 @@ fn insert_late_bound_lifetimes(
}
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
self.regions.insert(lifetime_ref.name.normalize_to_macros_2_0());
if let hir::LifetimeName::Param(def_id, _) = lifetime_ref.name {
self.regions.insert(def_id);
}
}
}
#[derive(Default)]
struct AllCollector {
regions: FxHashSet<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);
}
}
}
}