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

@ -53,7 +53,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
e.span,
seg,
ParamMode::Optional,
0,
ParenthesizedGenericArgs::Err,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
));

View File

@ -30,6 +30,7 @@ pub(super) struct NodeCollector<'a, 'hir> {
definitions: &'a definitions::Definitions,
}
#[tracing::instrument(level = "debug", skip(sess, definitions, bodies))]
pub(super) fn index_hir<'hir>(
sess: &Session,
definitions: &definitions::Definitions,
@ -65,6 +66,7 @@ pub(super) fn index_hir<'hir>(
}
impl<'a, 'hir> NodeCollector<'a, 'hir> {
#[tracing::instrument(level = "debug", skip(self))]
fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) {
debug_assert_eq!(self.owner, hir_id.owner);
debug_assert_ne!(hir_id.local_id.as_u32(), 0);
@ -138,8 +140,8 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
});
}
#[tracing::instrument(level = "debug", skip(self))]
fn visit_item(&mut self, i: &'hir Item<'hir>) {
debug!("visit_item: {:?}", i);
debug_assert_eq!(i.def_id, self.owner);
self.with_parent(i.hir_id(), |this| {
if let ItemKind::Struct(ref struct_def, _) = i.kind {
@ -152,6 +154,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
});
}
#[tracing::instrument(level = "debug", skip(self))]
fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) {
debug_assert_eq!(fi.def_id, self.owner);
self.with_parent(fi.hir_id(), |this| {
@ -170,6 +173,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
})
}
#[tracing::instrument(level = "debug", skip(self))]
fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
debug_assert_eq!(ti.def_id, self.owner);
self.with_parent(ti.hir_id(), |this| {
@ -177,6 +181,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
});
}
#[tracing::instrument(level = "debug", skip(self))]
fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) {
debug_assert_eq!(ii.def_id, self.owner);
self.with_parent(ii.hir_id(), |this| {

View File

@ -1,5 +1,5 @@
use super::{AnonymousLifetimeMode, LoweringContext, ParamMode};
use super::{AstOwner, ImplTraitContext, ImplTraitPosition, ResolverAstLowering};
use super::{LoweringContext, ParamMode};
use crate::{Arena, FnDeclKind};
use rustc_ast::ptr::P;
@ -81,13 +81,13 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
is_in_loop_condition: false,
is_in_trait_impl: false,
is_in_dyn_type: false,
anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
generator_kind: None,
task_context: None,
current_item: None,
lifetimes_to_define: Vec::new(),
lifetimes_to_define: Default::default(),
is_collecting_anonymous_lifetimes: None,
in_scope_lifetimes: Vec::new(),
captured_lifetimes: None,
allow_try_trait: Some([sym::try_trait_v2][..].into()),
allow_gen_future: Some([sym::gen_future][..].into()),
allow_into_future: Some([sym::into_future][..].into()),
@ -143,12 +143,12 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
LocalDefId { local_def_index }
};
let parent_hir = self.lower_node(parent_id).unwrap().node().expect_item();
let parent_hir = self.lower_node(parent_id).unwrap();
self.with_lctx(item.id, |lctx| {
// Evaluate with the lifetimes in `params` in-scope.
// This is used to track which lifetimes have already been defined,
// and which need to be replicated when lowering an async fn.
match parent_hir.kind {
match parent_hir.node().expect_item().kind {
hir::ItemKind::Impl(hir::Impl { ref of_trait, ref generics, .. }) => {
lctx.is_in_trait_impl = of_trait.is_some();
lctx.in_scope_lifetimes = generics
@ -157,7 +157,12 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
.filter(|param| {
matches!(param.kind, hir::GenericParamKind::Lifetime { .. })
})
.map(|param| param.name)
.map(|param| {
let def_id =
parent_hir.nodes.local_id_to_def_id[&param.hir_id.local_id];
let name = param.name;
(name, def_id)
})
.collect();
}
hir::ItemKind::Trait(_, _, ref generics, ..) => {
@ -167,7 +172,12 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
.filter(|param| {
matches!(param.kind, hir::GenericParamKind::Lifetime { .. })
})
.map(|param| param.name)
.map(|param| {
let def_id =
parent_hir.nodes.local_id_to_def_id[&param.hir_id.local_id];
let name = param.name;
(name, def_id)
})
.collect();
}
_ => {}
@ -288,20 +298,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
let body_id =
this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref());
let (generics, decl) = this.add_in_band_defs(
generics,
fn_def_id,
AnonymousLifetimeMode::PassThrough,
|this, idty| {
let (generics, decl) =
this.add_in_band_defs(generics, fn_def_id, |this, idty| {
let ret_id = asyncness.opt_return_id();
this.lower_fn_decl(
&decl,
Some((fn_def_id, idty)),
FnDeclKind::Fn,
ret_id,
)
},
);
this.lower_fn_decl(&decl, Some((id, idty)), FnDeclKind::Fn, ret_id)
});
let sig = hir::FnSig {
decl,
header: this.lower_fn_header(header),
@ -420,11 +421,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
// lifetime to be added, but rather a reference to a
// parent lifetime.
let lowered_trait_def_id = hir_id.expect_owner();
let (generics, (trait_ref, lowered_ty)) = self.add_in_band_defs(
ast_generics,
lowered_trait_def_id,
AnonymousLifetimeMode::CreateParameter,
|this, _| {
let (generics, (trait_ref, lowered_ty)) =
self.add_in_band_defs(ast_generics, lowered_trait_def_id, |this, _| {
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
this.lower_trait_ref(
trait_ref,
@ -436,8 +434,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
(trait_ref, lowered_ty)
},
);
});
let new_impl_items =
self.with_in_scope_lifetime_defs(&ast_generics.params, |this| {
@ -750,18 +747,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
kind: match i.kind {
ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => {
let fdec = &sig.decl;
let (generics, (fn_dec, fn_args)) = self.add_in_band_defs(
generics,
def_id,
AnonymousLifetimeMode::PassThrough,
|this, _| {
let (generics, (fn_dec, fn_args)) =
self.add_in_band_defs(generics, def_id, |this, _| {
(
// Disallow `impl Trait` in foreign items.
this.lower_fn_decl(fdec, None, FnDeclKind::ExternFn, None),
this.lower_fn_params_to_names(fdec),
)
},
);
});
hir::ForeignItemKind::Fn(fn_dec, fn_args, generics)
}
@ -868,13 +861,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
AssocItemKind::Fn(box Fn { ref sig, ref generics, body: None, .. }) => {
let names = self.lower_fn_params_to_names(&sig.decl);
let (generics, sig) = self.lower_method_sig(
generics,
sig,
trait_item_def_id,
FnDeclKind::Trait,
None,
);
let (generics, sig) =
self.lower_method_sig(generics, sig, i.id, FnDeclKind::Trait, None);
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)))
}
AssocItemKind::Fn(box Fn { ref sig, ref generics, body: Some(ref body), .. }) => {
@ -884,7 +872,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, sig) = self.lower_method_sig(
generics,
sig,
trait_item_def_id,
i.id,
FnDeclKind::Trait,
asyncness.opt_return_id(),
);
@ -958,8 +946,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
let impl_item_def_id = self.resolver.local_def_id(i.id);
let (generics, kind) = match &i.kind {
AssocItemKind::Const(_, ty, expr) => {
let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
@ -976,7 +962,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, sig) = self.lower_method_sig(
generics,
sig,
impl_item_def_id,
i.id,
if self.is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent },
asyncness.opt_return_id(),
);
@ -1363,17 +1349,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
&mut self,
generics: &Generics,
sig: &FnSig,
fn_def_id: LocalDefId,
id: NodeId,
kind: FnDeclKind,
is_async: Option<NodeId>,
) -> (hir::Generics<'hir>, hir::FnSig<'hir>) {
let fn_def_id = self.resolver.local_def_id(id);
let header = self.lower_fn_header(sig.header);
let (generics, decl) = self.add_in_band_defs(
generics,
fn_def_id,
AnonymousLifetimeMode::PassThrough,
|this, idty| this.lower_fn_decl(&sig.decl, Some((fn_def_id, idty)), kind, is_async),
);
let (generics, decl) = self.add_in_band_defs(generics, fn_def_id, |this, idty| {
this.lower_fn_decl(&sig.decl, Some((id, idty)), kind, is_async)
});
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
}
@ -1498,14 +1482,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
fn lower_where_clause(&mut self, wc: &WhereClause) -> hir::WhereClause<'hir> {
self.with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| {
hir::WhereClause {
predicates: this.arena.alloc_from_iter(
wc.predicates.iter().map(|predicate| this.lower_where_predicate(predicate)),
),
span: this.lower_span(wc.span),
}
})
hir::WhereClause {
predicates: self.arena.alloc_from_iter(
wc.predicates.iter().map(|predicate| self.lower_where_predicate(predicate)),
),
span: self.lower_span(wc.span),
}
}
fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate<'hir> {

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,14 @@
use crate::ImplTraitPosition;
use super::{AnonymousLifetimeMode, ImplTraitContext, LoweringContext, ParamMode};
use super::{GenericArgsCtor, ParenthesizedGenericArgs};
use super::{GenericArgsCtor, LifetimeRes, ParenthesizedGenericArgs};
use super::{ImplTraitContext, LoweringContext, ParamMode};
use rustc_ast::{self as ast, *};
use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, PartialRes, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::GenericArg;
use rustc_span::symbol::Ident;
use rustc_span::symbol::{kw, Ident};
use rustc_span::{BytePos, Span, DUMMY_SP};
use smallvec::smallvec;
@ -47,30 +46,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
_ => param_mode,
};
// Figure out if this is a type/trait segment,
// which may need lifetime elision performed.
let parent_def_id = |this: &mut Self, def_id: DefId| DefId {
krate: def_id.krate,
index: this.resolver.def_key(def_id).parent.expect("missing parent"),
};
let type_def_id = match partial_res.base_res() {
Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => {
Some(parent_def_id(self, def_id))
}
Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => {
Some(parent_def_id(self, def_id))
}
Res::Def(DefKind::Struct, def_id)
| Res::Def(DefKind::Union, def_id)
| Res::Def(DefKind::Enum, def_id)
| Res::Def(DefKind::TyAlias, def_id)
| Res::Def(DefKind::Trait, def_id)
if i + 1 == proj_start =>
{
Some(def_id)
}
_ => None,
};
let parenthesized_generic_args = match partial_res.base_res() {
// `a::b::Trait(Args)`
Res::Def(DefKind::Trait, _) if i + 1 == proj_start => {
@ -90,13 +65,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
_ => ParenthesizedGenericArgs::Err,
};
let num_lifetimes = type_def_id
.map_or(0, |def_id| self.resolver.item_generics_num_lifetimes(def_id));
self.lower_path_segment(
p.span,
segment,
param_mode,
num_lifetimes,
parenthesized_generic_args,
itctx.reborrow(),
)
@ -143,7 +115,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
p.span,
segment,
param_mode,
0,
ParenthesizedGenericArgs::Err,
itctx.reborrow(),
));
@ -184,7 +155,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
p.span,
segment,
param_mode,
0,
ParenthesizedGenericArgs::Err,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
)
@ -209,14 +179,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
path_span: Span,
segment: &PathSegment,
param_mode: ParamMode,
expected_lifetimes: usize,
parenthesized_generic_args: ParenthesizedGenericArgs,
itctx: ImplTraitContext<'_, 'hir>,
) -> hir::PathSegment<'hir> {
debug!(
"path_span: {:?}, lower_path_segment(segment: {:?}, expected_lifetimes: {:?})",
path_span, segment, expected_lifetimes
);
debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment,);
let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args {
let msg = "parenthesized type parameters may only be used with a `Fn` trait";
match **generic_args {
@ -224,7 +190,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
}
GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args {
ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
ParenthesizedGenericArgs::Ok => {
self.lower_parenthesized_parameter_data(segment.id, data)
}
ParenthesizedGenericArgs::Err => {
let mut err = struct_span_err!(self.sess, data.span, E0214, "{}", msg);
err.span_label(data.span, "only `Fn` traits may use parentheses");
@ -274,33 +242,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let has_lifetimes =
generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)));
if !generic_args.parenthesized && !has_lifetimes && expected_lifetimes > 0 {
// Note: these spans are used for diagnostics when they can't be inferred.
// See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label
let elided_lifetime_span = if generic_args.span.is_empty() {
// If there are no brackets, use the identifier span.
// HACK: we use find_ancestor_inside to properly suggest elided spans in paths
// originating from macros, since the segment's span might be from a macro arg.
segment.ident.span.find_ancestor_inside(path_span).unwrap_or(path_span)
} else if generic_args.is_empty() {
// If there are brackets, but not generic arguments, then use the opening bracket
generic_args.span.with_hi(generic_args.span.lo() + BytePos(1))
} else {
// Else use an empty span right after the opening bracket.
generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo()
};
generic_args.args = self
.elided_path_lifetimes(elided_lifetime_span, expected_lifetimes)
.map(GenericArg::Lifetime)
.chain(generic_args.args.into_iter())
.collect();
if let (ParamMode::Explicit, AnonymousLifetimeMode::CreateParameter) =
(param_mode, self.anonymous_lifetime_mode)
{
// Late resolver should have issued the error.
self.sess
.delay_span_bug(elided_lifetime_span, "implicit lifetime not allowed here");
}
if !generic_args.parenthesized && !has_lifetimes {
self.maybe_insert_elided_lifetimes_in_path(
path_span,
segment.id,
segment.ident.span,
&mut generic_args,
);
}
let res = self.expect_full_res(segment.id);
@ -323,6 +271,49 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
}
fn maybe_insert_elided_lifetimes_in_path(
&mut self,
path_span: Span,
segment_id: NodeId,
segment_ident_span: Span,
generic_args: &mut GenericArgsCtor<'hir>,
) {
let (start, end) = match self.resolver.get_lifetime_res(segment_id) {
Some(LifetimeRes::ElidedAnchor { start, end }) => (start, end),
None => return,
Some(_) => panic!(),
};
let expected_lifetimes = end.as_usize() - start.as_usize();
debug!(expected_lifetimes);
// Note: these spans are used for diagnostics when they can't be inferred.
// See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label
let elided_lifetime_span = if generic_args.span.is_empty() {
// If there are no brackets, use the identifier span.
// HACK: we use find_ancestor_inside to properly suggest elided spans in paths
// originating from macros, since the segment's span might be from a macro arg.
segment_ident_span.find_ancestor_inside(path_span).unwrap_or(path_span)
} else if generic_args.is_empty() {
// If there are brackets, but not generic arguments, then use the opening bracket
generic_args.span.with_hi(generic_args.span.lo() + BytePos(1))
} else {
// Else use an empty span right after the opening bracket.
generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo()
};
generic_args.args.insert_many(
0,
(start.as_u32()..end.as_u32()).map(|i| {
let id = NodeId::from_u32(i);
let l = self.lower_lifetime(&Lifetime {
id,
ident: Ident::new(kw::UnderscoreLifetime, elided_lifetime_span),
});
GenericArg::Lifetime(l)
}),
);
}
pub(crate) fn lower_angle_bracketed_parameter_data(
&mut self,
data: &AngleBracketedArgs,
@ -354,6 +345,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_parenthesized_parameter_data(
&mut self,
id: NodeId,
data: &ParenthesizedArgs,
) -> (GenericArgsCtor<'hir>, bool) {
// Switch to `PassThrough` mode for anonymous lifetimes; this
@ -361,31 +353,33 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// a hidden lifetime parameter. This is needed for backwards
// compatibility, even in contexts like an impl header where
// we generally don't permit such things (see #51008).
self.with_anonymous_lifetime_mode(AnonymousLifetimeMode::PassThrough, |this| {
let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
let inputs = this.arena.alloc_from_iter(inputs.iter().map(|ty| {
this.lower_ty_direct(
ty,
ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam),
)
}));
let output_ty = match output {
FnRetTy::Ty(ty) => this
.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)),
FnRetTy::Default(_) => this.arena.alloc(this.ty_tup(*span, &[])),
};
let args = smallvec![GenericArg::Type(this.ty_tup(*inputs_span, inputs))];
let binding = this.output_ty_binding(output_ty.span, output_ty);
(
GenericArgsCtor {
args,
bindings: arena_vec![this; binding],
parenthesized: true,
span: data.inputs_span,
},
false,
)
})
if let Some((_, _, binders)) = &mut self.captured_lifetimes {
binders.insert(id);
}
let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| {
self.lower_ty_direct(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
}));
let output_ty = match output {
FnRetTy::Ty(ty) => {
self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn))
}
FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
};
let args = smallvec![GenericArg::Type(self.ty_tup(*inputs_span, inputs))];
let binding = self.output_ty_binding(output_ty.span, output_ty);
if let Some((_, _, binders)) = &mut self.captured_lifetimes {
binders.remove(&id);
}
(
GenericArgsCtor {
args,
bindings: arena_vec![self; binding],
parenthesized: true,
span: data.inputs_span,
},
false,
)
}
/// An associated type binding `Output = $ty`.

View File

@ -442,9 +442,6 @@ pub enum GenericBound<'hir> {
Outlives(Lifetime),
}
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(GenericBound<'_>, 48);
impl GenericBound<'_> {
pub fn trait_ref(&self) -> Option<&TraitRef<'_>> {
match self {
@ -3347,6 +3344,7 @@ mod size_asserts {
rustc_data_structures::static_assert_size!(super::Pat<'static>, 88);
rustc_data_structures::static_assert_size!(super::QPath<'static>, 24);
rustc_data_structures::static_assert_size!(super::Ty<'static>, 72);
rustc_data_structures::static_assert_size!(super::GenericBound<'_>, 48);
rustc_data_structures::static_assert_size!(super::Item<'static>, 184);
rustc_data_structures::static_assert_size!(super::TraitItem<'static>, 128);

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