Use LifetimeRes during lowering.

This commit is contained in:
Camille GILLOT 2022-04-07 20:54:13 +02:00
parent 69985f0175
commit f385f856cd
9 changed files with 709 additions and 799 deletions

View file

@ -14,13 +14,15 @@ use crate::{ResolutionError, Resolver, Segment, UseError};
use rustc_ast::ptr::P;
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use rustc_ast::*;
use rustc_ast_lowering::ResolverAstLowering;
use rustc_ast_lowering::{LifetimeRes, ResolverAstLowering};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::DiagnosticId;
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, DefKind, PartialRes, PerNS};
use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
use rustc_hir::definitions::DefPathData;
use rustc_hir::{PrimTy, TraitCandidate};
use rustc_index::vec::Idx;
use rustc_middle::ty::DefIdTree;
use rustc_middle::{bug, span_bug};
use rustc_session::lint;
@ -195,7 +197,7 @@ enum LifetimeRibKind {
Item,
/// This rib declares generic parameters.
Generics { span: Span, kind: LifetimeBinderKind },
Generics { parent: NodeId, span: Span, kind: LifetimeBinderKind },
/// For **Modern** cases, create a new anonymous region parameter
/// and reference that.
@ -204,7 +206,7 @@ enum LifetimeRibKind {
/// `resolve_lifetime` code.
///
/// For **Deprecated** cases, report an error.
AnonymousCreateParameter,
AnonymousCreateParameter(NodeId),
/// Give a hard error when either `&` or `'_` is written. Used to
/// rule out things like `where T: Foo<'_>`. Does not imply an
@ -212,7 +214,7 @@ enum LifetimeRibKind {
AnonymousReportError,
/// Pass responsibility to `resolve_lifetime` code for all cases.
AnonymousPassThrough,
AnonymousPassThrough(NodeId),
}
#[derive(Copy, Clone, Debug)]
@ -242,7 +244,7 @@ impl LifetimeBinderKind {
#[derive(Debug)]
struct LifetimeRib {
kind: LifetimeRibKind,
bindings: IdentMap<()>,
bindings: IdentMap<LifetimeRes>,
}
impl LifetimeRib {
@ -581,12 +583,19 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
self.with_generic_param_rib(
&bare_fn.generic_params,
NormalRibKind,
LifetimeRibKind::Generics { kind: LifetimeBinderKind::BareFnType, span },
LifetimeRibKind::Generics {
parent: ty.id,
kind: LifetimeBinderKind::BareFnType,
span,
},
|this| {
this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
this.visit_generic_param_vec(&bare_fn.generic_params, false);
visit::walk_fn_decl(this, &bare_fn.decl);
});
this.with_lifetime_rib(
LifetimeRibKind::AnonymousPassThrough(ty.id),
|this| {
this.visit_generic_param_vec(&bare_fn.generic_params, false);
visit::walk_fn_decl(this, &bare_fn.decl);
},
);
},
);
self.diagnostic_metadata.current_trait_object = prev;
@ -604,7 +613,11 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
self.with_generic_param_rib(
&tref.bound_generic_params,
NormalRibKind,
LifetimeRibKind::Generics { kind: LifetimeBinderKind::PolyTrait, span },
LifetimeRibKind::Generics {
parent: tref.trait_ref.ref_id,
kind: LifetimeBinderKind::PolyTrait,
span,
},
|this| {
this.visit_generic_param_vec(&tref.bound_generic_params, false);
this.smart_resolve_path(
@ -625,6 +638,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
&generics.params,
ItemRibKind(HasGenericParams::Yes),
LifetimeRibKind::Generics {
parent: foreign_item.id,
kind: LifetimeBinderKind::Item,
span: generics.span,
},
@ -638,6 +652,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
&generics.params,
ItemRibKind(HasGenericParams::Yes),
LifetimeRibKind::Generics {
parent: foreign_item.id,
kind: LifetimeBinderKind::Function,
span: generics.span,
},
@ -655,13 +670,13 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
}
}
}
fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, _: NodeId) {
fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, fn_id: NodeId) {
let rib_kind = match fn_kind {
// Bail if the function is foreign, and thus cannot validly have
// a body, or if there's no body for some other reason.
FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _)
| FnKind::Fn(_, _, sig, _, generics, None) => {
self.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
self.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(fn_id), |this| {
// We don't need to deal with patterns in parameters, because
// they are not possible for foreign or bodiless functions.
this.visit_fn_header(&sig.header);
@ -691,20 +706,24 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
this.visit_generics(generics);
}
if async_node_id.is_some() {
if let Some(async_node_id) = async_node_id {
// In `async fn`, argument-position elided lifetimes
// must be transformed into fresh generic parameters so that
// they can be applied to the opaque `impl Trait` return type.
this.with_lifetime_rib(LifetimeRibKind::AnonymousCreateParameter, |this| {
// Add each argument to the rib.
this.resolve_params(&declaration.inputs)
});
this.with_lifetime_rib(
LifetimeRibKind::AnonymousCreateParameter(fn_id),
|this| {
// Add each argument to the rib.
this.resolve_params(&declaration.inputs)
},
);
this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
visit::walk_fn_ret_ty(this, &declaration.output)
});
this.with_lifetime_rib(
LifetimeRibKind::AnonymousPassThrough(async_node_id),
|this| visit::walk_fn_ret_ty(this, &declaration.output),
);
} else {
this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(fn_id), |this| {
// Add each argument to the rib.
this.resolve_params(&declaration.inputs);
@ -716,13 +735,12 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
// Be sure not to set this until the function signature has been resolved.
let previous_state = replace(&mut this.in_func_body, true);
// Resolve the function body, potentially inside the body of an async closure
this.with_lifetime_rib(
LifetimeRibKind::AnonymousPassThrough,
|this| match fn_kind {
this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(fn_id), |this| {
match fn_kind {
FnKind::Fn(.., body) => walk_list!(this, visit_block, body),
FnKind::Closure(_, body) => this.visit_expr(body),
},
);
}
});
debug!("(resolving function) leaving function");
this.in_func_body = previous_state;
@ -801,10 +819,10 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
if let Some(ref args) = path_segment.args {
match &**args {
GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, path_span, args),
GenericArgs::Parenthesized(..) => self
.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
visit::walk_generic_args(this, path_span, args)
}),
GenericArgs::Parenthesized(..) => self.with_lifetime_rib(
LifetimeRibKind::AnonymousPassThrough(path_segment.id),
|this| visit::walk_generic_args(this, path_span, args),
),
}
}
}
@ -830,7 +848,11 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
this.with_generic_param_rib(
&bound_generic_params,
NormalRibKind,
LifetimeRibKind::Generics { kind: LifetimeBinderKind::WhereBound, span },
LifetimeRibKind::Generics {
parent: bounded_ty.id,
kind: LifetimeBinderKind::WhereBound,
span,
},
|this| {
this.visit_generic_param_vec(&bound_generic_params, false);
this.visit_ty(bounded_ty);
@ -1092,6 +1114,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
let ident = lifetime.ident;
if ident.name == kw::StaticLifetime {
self.record_lifetime_res(lifetime.id, LifetimeRes::Static);
return;
}
@ -1103,7 +1126,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
for i in &mut indices {
let rib = &self.lifetime_ribs[i];
let normalized_ident = ident.normalize_to_macros_2_0();
if let Some(_) = rib.bindings.get_key_value(&normalized_ident) {
if let Some(&region) = rib.bindings.get(&normalized_ident) {
self.record_lifetime_res(lifetime.id, region);
return;
}
@ -1123,6 +1147,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
}
self.emit_undeclared_lifetime_error(lifetime, outer_res);
self.record_lifetime_res(lifetime.id, LifetimeRes::Error);
}
#[tracing::instrument(level = "debug", skip(self))]
@ -1132,6 +1157,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
for i in (0..self.lifetime_ribs.len()).rev() {
let rib = &mut self.lifetime_ribs[i];
match rib.kind {
LifetimeRibKind::AnonymousCreateParameter(item_node_id) => {
self.create_fresh_lifetime(lifetime.id, lifetime.ident, item_node_id);
return;
}
LifetimeRibKind::AnonymousReportError => {
let (msg, note) = if elided {
(
@ -1151,23 +1180,63 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
.span_label(lifetime.ident.span, note)
.emit();
self.record_lifetime_res(lifetime.id, LifetimeRes::Error);
return;
}
LifetimeRibKind::AnonymousCreateParameter
| LifetimeRibKind::AnonymousPassThrough
| LifetimeRibKind::Item => return,
LifetimeRibKind::AnonymousPassThrough(node_id) => {
self.record_lifetime_res(
lifetime.id,
LifetimeRes::Anonymous { binder: node_id, elided },
);
return;
}
LifetimeRibKind::Item => break,
_ => {}
}
}
// This resolution is wrong, it passes the work to HIR lifetime resolution.
// We cannot use `LifetimeRes::Error` because we do not emit a diagnostic.
self.record_lifetime_res(
lifetime.id,
LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided },
);
}
#[tracing::instrument(level = "debug", skip(self))]
fn resolve_elided_lifetime(&mut self, anchor_id: NodeId, span: Span) {
let id = self.r.next_node_id();
self.record_lifetime_res(
anchor_id,
LifetimeRes::ElidedAnchor { start: id, end: NodeId::from_u32(id.as_u32() + 1) },
);
let lt = Lifetime { id, ident: Ident::new(kw::UnderscoreLifetime, span) };
self.resolve_anonymous_lifetime(&lt, true);
}
#[tracing::instrument(level = "debug", skip(self))]
fn create_fresh_lifetime(&mut self, id: NodeId, ident: Ident, item_node_id: NodeId) {
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
debug!(?ident.span);
let item_def_id = self.r.local_def_id(item_node_id);
let def_node_id = self.r.next_node_id();
let def_id = self.r.create_def(
item_def_id,
def_node_id,
DefPathData::LifetimeNs(kw::UnderscoreLifetime),
self.parent_scope.expansion.to_expn_id(),
ident.span,
);
debug!(?def_id);
let region = LifetimeRes::Fresh {
param: def_id,
introducer: Some(def_node_id),
binder: item_node_id,
};
self.record_lifetime_res(id, region);
}
#[tracing::instrument(level = "debug", skip(self))]
fn resolve_elided_lifetimes_in_path(
&mut self,
@ -1231,7 +1300,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
//
// impl Foo for std::cell::Ref<u32> // note lack of '_
// async fn foo(_: std::cell::Ref<u32>) { ... }
LifetimeRibKind::AnonymousCreateParameter => {
LifetimeRibKind::AnonymousCreateParameter(_) => {
error = true;
break;
}
@ -1241,13 +1310,29 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
// `PathSegment`, for which there is no associated `'_` or `&T` with no explicit
// lifetime. Instead, we simply create an implicit lifetime, which will be checked
// later, at which point a suitable error will be emitted.
LifetimeRibKind::AnonymousPassThrough
LifetimeRibKind::AnonymousPassThrough(..)
| LifetimeRibKind::AnonymousReportError
| LifetimeRibKind::Item => break,
_ => {}
}
}
let res = if error {
LifetimeRes::Error
} else {
LifetimeRes::Anonymous { binder: segment_id, elided: true }
};
let node_ids = self.r.next_node_ids(expected_lifetimes);
self.record_lifetime_res(
segment_id,
LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end },
);
for i in 0..expected_lifetimes {
let id = node_ids.start.plus(i);
self.record_lifetime_res(id, res);
}
if !missing {
continue;
}
@ -1296,6 +1381,16 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
}
}
#[tracing::instrument(level = "debug", skip(self))]
fn record_lifetime_res(&mut self, id: NodeId, res: LifetimeRes) {
if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) {
panic!(
"lifetime {:?} resolved multiple times ({:?} before, {:?} now)",
id, prev_res, res
)
}
}
/// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved
/// label and reports an error if the label is not found or is unreachable.
fn resolve_label(&self, mut label: Ident) -> Option<NodeId> {
@ -1379,7 +1474,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
this.with_generic_param_rib(
&generics.params,
ItemRibKind(HasGenericParams::Yes),
LifetimeRibKind::Generics { kind: LifetimeBinderKind::Item, span: generics.span },
LifetimeRibKind::Generics {
parent: item.id,
kind: LifetimeBinderKind::Item,
span: generics.span,
},
|this| {
let item_def_id = this.r.local_def_id(item.id).to_def_id();
this.with_self_rib(
@ -1446,6 +1545,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
&generics.params,
ItemRibKind(HasGenericParams::Yes),
LifetimeRibKind::Generics {
parent: item.id,
kind: LifetimeBinderKind::Item,
span: generics.span,
},
@ -1458,6 +1558,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
&generics.params,
ItemRibKind(HasGenericParams::Yes),
LifetimeRibKind::Generics {
parent: item.id,
kind: LifetimeBinderKind::Function,
span: generics.span,
},
@ -1487,6 +1588,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
&generics.params,
ItemRibKind(HasGenericParams::Yes),
LifetimeRibKind::Generics {
parent: item.id,
kind: LifetimeBinderKind::Item,
span: generics.span,
},
@ -1506,7 +1608,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
this.with_generic_param_rib(
&generics.params,
AssocItemRibKind,
LifetimeRibKind::Generics { span: generics.span, kind },
LifetimeRibKind::Generics {
parent: item.id,
span: generics.span,
kind,
},
|this| {
visit::walk_assoc_item(this, item, AssocCtxt::Trait)
},
@ -1571,6 +1677,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
&generics.params,
ItemRibKind(HasGenericParams::Yes),
LifetimeRibKind::Generics {
parent: item.id,
kind: LifetimeBinderKind::Item,
span: generics.span,
},
@ -1708,7 +1815,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
GenericParamKind::Type { .. } => (&mut function_type_rib, DefKind::TyParam),
GenericParamKind::Const { .. } => (&mut function_value_rib, DefKind::ConstParam),
GenericParamKind::Lifetime => {
function_lifetime_rib.bindings.insert(ident, ());
let LifetimeRibKind::Generics { parent, .. } = lifetime_kind else { panic!() };
let res = LifetimeRes::Param { param: def_id, binder: parent };
self.record_lifetime_res(param.id, res);
function_lifetime_rib.bindings.insert(ident, res);
continue;
}
};
@ -1849,10 +1959,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
) {
debug!("resolve_implementation");
// If applicable, create a rib for the type parameters.
self.with_generic_param_rib(&generics.params, ItemRibKind(HasGenericParams::Yes), LifetimeRibKind::Generics { span: generics.span, kind: LifetimeBinderKind::ImplBlock }, |this| {
self.with_generic_param_rib(&generics.params, ItemRibKind(HasGenericParams::Yes), LifetimeRibKind::Generics { span: generics.span, parent: item_id, kind: LifetimeBinderKind::ImplBlock }, |this| {
// Dummy self type for better errors if `Self` is used in the trait path.
this.with_self_rib(Res::SelfTy { trait_: None, alias_to: None }, |this| {
this.with_lifetime_rib(LifetimeRibKind::AnonymousCreateParameter, |this| {
this.with_lifetime_rib(LifetimeRibKind::AnonymousCreateParameter(item_id), |this| {
// Resolve the trait reference, if necessary.
this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
let item_def_id = this.r.local_def_id(item_id);
@ -1876,7 +1986,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
this.visit_generics(generics);
// Resolve the items within the impl.
this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough,
this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(item_id),
|this| {
this.with_current_self_type(self_type, |this| {
this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| {
@ -1921,7 +2031,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
this.with_generic_param_rib(
&generics.params,
AssocItemRibKind,
LifetimeRibKind::Generics { span: generics.span, kind: LifetimeBinderKind::Function },
LifetimeRibKind::Generics { parent: item.id, span: generics.span, kind: LifetimeBinderKind::Function },
|this| {
// If this is a trait impl, ensure the method
// exists in trait
@ -1950,7 +2060,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
this.with_generic_param_rib(
&generics.params,
AssocItemRibKind,
LifetimeRibKind::Generics { span: generics.span, kind: LifetimeBinderKind::Item },
LifetimeRibKind::Generics { parent: item.id, span: generics.span, kind: LifetimeBinderKind::Item },
|this| {
// If this is a trait impl, ensure the type
// exists in trait

View file

@ -1824,7 +1824,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
for rib in self.lifetime_ribs.iter().rev() {
match rib.kind {
LifetimeRibKind::Generics { span, kind } => {
LifetimeRibKind::Generics { parent: _, span, kind } => {
if !span.can_be_used_for_suggestions() && suggest_note {
suggest_note = false; // Avoid displaying the same help multiple times.
err.span_label(

View file

@ -29,7 +29,7 @@ use rustc_arena::{DroplessArena, TypedArena};
use rustc_ast::node_id::NodeMap;
use rustc_ast::{self as ast, NodeId, CRATE_NODE_ID};
use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path};
use rustc_ast_lowering::ResolverAstLowering;
use rustc_ast_lowering::{LifetimeRes, ResolverAstLowering};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_data_structures::intern::Interned;
use rustc_data_structures::sync::Lrc;
@ -901,6 +901,8 @@ pub struct Resolver<'a> {
import_res_map: NodeMap<PerNS<Option<Res>>>,
/// Resolutions for labels (node IDs of their corresponding blocks or loops).
label_res_map: NodeMap<NodeId>,
/// Resolutions for lifetimes.
lifetimes_res_map: NodeMap<LifetimeRes>,
/// `CrateNum` resolutions of `extern crate` items.
extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
@ -1153,6 +1155,10 @@ impl ResolverAstLowering for Resolver<'_> {
self.label_res_map.get(&id).cloned()
}
fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes> {
self.lifetimes_res_map.get(&id).copied()
}
fn create_stable_hashing_context(&self) -> StableHashingContext<'_> {
StableHashingContext::new(self.session, &self.definitions, self.crate_loader.cstore())
}
@ -1301,6 +1307,7 @@ impl<'a> Resolver<'a> {
partial_res_map: Default::default(),
import_res_map: Default::default(),
label_res_map: Default::default(),
lifetimes_res_map: Default::default(),
extern_crate_map: Default::default(),
reexport_map: FxHashMap::default(),
trait_map: NodeMap::default(),