Auto merge of #91557 - cjgillot:ast-lifetimes-named, r=petrochenkov
Perform lifetime resolution on the AST for lowering Lifetime resolution is currently implemented several times. Once during lowering in order to introduce in-band lifetimes, and once in the resolve_lifetimes query. However, due to the global nature of lifetime resolution and how it interferes with hygiene, it is better suited on the AST. This PR implements a first draft of lifetime resolution on the AST. For now, we specifically target named lifetimes and everything we need to remove lifetime resolution from lowering. Some diagnostics have already been ported, and sometimes made more precise using available hygiene information. Follow-up PRs will address in particular the resolution of anonymous lifetimes on the AST. We reuse the rib design of the current resolution framework. Specific `LifetimeRib` and `LifetimeRibKind` types are introduced. The most important variant is `LifetimeRibKind::Generics`, which happens each time we encounter something which may introduce generic lifetime parameters. It can be an item or a `for<...>` binder. The `LifetimeBinderKind` specifies how this rib behaves with respect to in-band lifetimes. r? `@petrochenkov`
This commit is contained in:
commit
c95346b8ac
12 changed files with 761 additions and 985 deletions
|
@ -53,7 +53,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
e.span,
|
||||
seg,
|
||||
ParamMode::Optional,
|
||||
0,
|
||||
ParenthesizedGenericArgs::Err,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
));
|
||||
|
|
|
@ -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| {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use super::{AnonymousLifetimeMode, LoweringContext, ParamMode};
|
||||
use super::{AstOwner, ImplTraitContext, ImplTraitPosition, ResolverAstLowering};
|
||||
use super::{LoweringContext, ParamMode};
|
||||
use crate::{Arena, FnDeclKind};
|
||||
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::visit::AssocCtxt;
|
||||
use rustc_ast::*;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
|
@ -81,13 +81,10 @@ 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(),
|
||||
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,32 +140,14 @@ 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 {
|
||||
hir::ItemKind::Impl(hir::Impl { ref of_trait, ref generics, .. }) => {
|
||||
match parent_hir.node().expect_item().kind {
|
||||
hir::ItemKind::Impl(hir::Impl { ref of_trait, .. }) => {
|
||||
lctx.is_in_trait_impl = of_trait.is_some();
|
||||
lctx.in_scope_lifetimes = generics
|
||||
.params
|
||||
.iter()
|
||||
.filter(|param| {
|
||||
matches!(param.kind, hir::GenericParamKind::Lifetime { .. })
|
||||
})
|
||||
.map(|param| param.name)
|
||||
.collect();
|
||||
}
|
||||
hir::ItemKind::Trait(_, _, ref generics, ..) => {
|
||||
lctx.in_scope_lifetimes = generics
|
||||
.params
|
||||
.iter()
|
||||
.filter(|param| {
|
||||
matches!(param.kind, hir::GenericParamKind::Lifetime { .. })
|
||||
})
|
||||
.map(|param| param.name)
|
||||
.collect();
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
@ -276,7 +255,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ref body,
|
||||
..
|
||||
}) => {
|
||||
let fn_def_id = self.resolver.local_def_id(id);
|
||||
self.with_new_scopes(|this| {
|
||||
this.current_item = Some(ident.span);
|
||||
|
||||
|
@ -288,20 +266,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_implicit_generics(generics, 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),
|
||||
|
@ -339,12 +308,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
//
|
||||
// type Foo = Foo1
|
||||
// opaque type Foo1: Trait
|
||||
let ty = self.lower_ty(
|
||||
ty,
|
||||
ImplTraitContext::TypeAliasesOpaqueTy {
|
||||
capturable_lifetimes: &mut FxHashSet::default(),
|
||||
},
|
||||
);
|
||||
let ty = self.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy);
|
||||
let mut generics = generics.clone();
|
||||
add_ty_alias_where_clause(&mut generics, where_clauses, true);
|
||||
let generics = self.lower_generics(
|
||||
|
@ -419,12 +383,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
// method, it will not be considered an in-band
|
||||
// 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_implicit_generics(ast_generics, id, |this, _| {
|
||||
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
|
||||
this.lower_trait_ref(
|
||||
trait_ref,
|
||||
|
@ -436,16 +396,12 @@ 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| {
|
||||
this.arena.alloc_from_iter(
|
||||
impl_items.iter().map(|item| this.lower_impl_item_ref(item)),
|
||||
)
|
||||
});
|
||||
|
||||
let new_impl_items = self
|
||||
.arena
|
||||
.alloc_from_iter(impl_items.iter().map(|item| self.lower_impl_item_ref(item)));
|
||||
|
||||
// `defaultness.has_value()` is never called for an `impl`, always `true` in order
|
||||
// to not cause an assertion failure inside the `lower_defaultness` function.
|
||||
let has_val = true;
|
||||
|
@ -692,18 +648,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_implicit_generics(generics, i.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)
|
||||
}
|
||||
|
@ -810,13 +762,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), .. }) => {
|
||||
|
@ -826,7 +773,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(),
|
||||
);
|
||||
|
@ -900,8 +847,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));
|
||||
|
@ -918,7 +863,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(),
|
||||
);
|
||||
|
@ -938,12 +883,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir::ImplItemKind::TyAlias(ty)
|
||||
}
|
||||
Some(ty) => {
|
||||
let ty = self.lower_ty(
|
||||
ty,
|
||||
ImplTraitContext::TypeAliasesOpaqueTy {
|
||||
capturable_lifetimes: &mut FxHashSet::default(),
|
||||
},
|
||||
);
|
||||
let ty = self.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy);
|
||||
hir::ImplItemKind::TyAlias(ty)
|
||||
}
|
||||
};
|
||||
|
@ -1283,17 +1223,14 @@ 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 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_implicit_generics(generics, 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) })
|
||||
}
|
||||
|
||||
|
@ -1418,14 +1355,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> {
|
||||
|
@ -1435,24 +1370,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ref bounded_ty,
|
||||
ref bounds,
|
||||
span,
|
||||
}) => self.with_in_scope_lifetime_defs(&bound_generic_params, |this| {
|
||||
hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
|
||||
bound_generic_params: this.lower_generic_params(
|
||||
bound_generic_params,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
),
|
||||
bounded_ty: this.lower_ty(
|
||||
bounded_ty,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Type),
|
||||
),
|
||||
bounds: this.arena.alloc_from_iter(bounds.iter().map(|bound| {
|
||||
this.lower_param_bound(
|
||||
bound,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
)
|
||||
})),
|
||||
span: this.lower_span(span),
|
||||
})
|
||||
}) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
|
||||
bound_generic_params: self.lower_generic_params(
|
||||
bound_generic_params,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
),
|
||||
bounded_ty: self
|
||||
.lower_ty(bounded_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
|
||||
bounds: self.arena.alloc_from_iter(bounds.iter().map(|bound| {
|
||||
self.lower_param_bound(
|
||||
bound,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
)
|
||||
})),
|
||||
span: self.lower_span(span),
|
||||
}),
|
||||
WherePredicate::RegionPredicate(WhereRegionPredicate {
|
||||
ref lifetime,
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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,7 +353,7 @@ 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| {
|
||||
self.with_lifetime_binder(id, |this| {
|
||||
let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
|
||||
let inputs = this.arena.alloc_from_iter(inputs.iter().map(|ty| {
|
||||
this.lower_ty_direct(
|
||||
|
|
|
@ -93,8 +93,6 @@ pub enum LifetimeName {
|
|||
Param(ParamName),
|
||||
|
||||
/// User wrote nothing (e.g., the lifetime in `&u32`).
|
||||
///
|
||||
/// The bool indicates whether the user should have written something.
|
||||
Implicit,
|
||||
|
||||
/// Implicit lifetime in a context like `dyn Foo`. This is
|
||||
|
@ -444,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 {
|
||||
|
@ -3330,6 +3325,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>, 160);
|
||||
rustc_data_structures::static_assert_size!(super::TraitItem<'static>, 128);
|
||||
|
|
|
@ -14,13 +14,15 @@ use crate::{ResolutionError, Resolver, Segment, UseError};
|
|||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
|
||||
use rustc_ast::*;
|
||||
use rustc_ast_lowering::ResolverAstLowering;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_ast_lowering::{LifetimeRes, ResolverAstLowering};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
||||
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,8 @@ impl LifetimeBinderKind {
|
|||
#[derive(Debug)]
|
||||
struct LifetimeRib {
|
||||
kind: LifetimeRibKind,
|
||||
bindings: IdentMap<()>,
|
||||
// We need to preserve insertion order for async fns.
|
||||
bindings: FxIndexMap<Ident, (NodeId, LifetimeRes)>,
|
||||
}
|
||||
|
||||
impl LifetimeRib {
|
||||
|
@ -581,12 +584,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 +614,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 +639,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 +653,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 +671,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 +707,50 @@ 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)
|
||||
});
|
||||
// Construct the list of in-scope lifetime parameters for async lowering.
|
||||
// We include all lifetime parameters, either named or "Fresh".
|
||||
// The order of those parameters does not matter, as long as it is
|
||||
// deterministic.
|
||||
let mut extra_lifetime_params =
|
||||
this.r.extra_lifetime_params_map.get(&fn_id).cloned().unwrap_or_default();
|
||||
for rib in this.lifetime_ribs.iter().rev() {
|
||||
extra_lifetime_params.extend(
|
||||
rib.bindings
|
||||
.iter()
|
||||
.map(|(&ident, &(node_id, res))| (ident, node_id, res)),
|
||||
);
|
||||
match rib.kind {
|
||||
LifetimeRibKind::Item => break,
|
||||
LifetimeRibKind::AnonymousCreateParameter(id) => {
|
||||
if let Some(earlier_fresh) =
|
||||
this.r.extra_lifetime_params_map.get(&id)
|
||||
{
|
||||
extra_lifetime_params.extend(earlier_fresh);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
this.r.extra_lifetime_params_map.insert(async_node_id, extra_lifetime_params);
|
||||
|
||||
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 +762,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 +846,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 +875,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 +1141,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 +1153,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 +1174,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 +1184,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 +1207,64 @@ 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(<, 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, binder: item_node_id };
|
||||
self.record_lifetime_res(id, region);
|
||||
self.r.extra_lifetime_params_map.entry(item_node_id).or_insert_with(Vec::new).push((
|
||||
ident,
|
||||
def_node_id,
|
||||
region,
|
||||
));
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
fn resolve_elided_lifetimes_in_path(
|
||||
&mut self,
|
||||
|
@ -1231,7 +1328,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 +1338,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 +1409,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 +1502,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 +1573,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 +1586,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 +1616,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 +1636,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 +1705,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 +1843,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, (param.id, res));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
@ -1849,10 +1987,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 +2014,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 +2059,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 +2088,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
|
||||
|
@ -2655,9 +2793,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||
if !matches!(source, PathSource::TraitItem(..)) {
|
||||
// Avoid recording definition of `A::B` in `<T as A>::B::C`.
|
||||
self.r.record_partial_res(id, partial_res);
|
||||
self.resolve_elided_lifetimes_in_path(id, partial_res, path, source, finalize);
|
||||
}
|
||||
|
||||
self.resolve_elided_lifetimes_in_path(id, partial_res, path, source, finalize);
|
||||
partial_res
|
||||
}
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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,10 @@ 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>,
|
||||
/// Lifetime parameters that lowering will have to introduce.
|
||||
extra_lifetime_params_map: NodeMap<Vec<(Ident, NodeId, LifetimeRes)>>,
|
||||
|
||||
/// `CrateNum` resolutions of `extern crate` items.
|
||||
extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
|
||||
|
@ -1154,6 +1158,14 @@ 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 take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> {
|
||||
self.extra_lifetime_params_map.remove(&id).unwrap_or_default()
|
||||
}
|
||||
|
||||
fn create_stable_hashing_context(&self) -> StableHashingContext<'_> {
|
||||
StableHashingContext::new(self.session, &self.definitions, self.crate_loader.cstore())
|
||||
}
|
||||
|
@ -1302,6 +1314,8 @@ impl<'a> Resolver<'a> {
|
|||
partial_res_map: Default::default(),
|
||||
import_res_map: Default::default(),
|
||||
label_res_map: Default::default(),
|
||||
lifetimes_res_map: Default::default(),
|
||||
extra_lifetime_params_map: Default::default(),
|
||||
extern_crate_map: Default::default(),
|
||||
reexport_map: FxHashMap::default(),
|
||||
trait_map: NodeMap::default(),
|
||||
|
|
|
@ -46,6 +46,7 @@ where
|
|||
|
||||
fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'_>> {
|
||||
//~^ ERROR: missing lifetime specifier
|
||||
//~| ERROR: missing lifetime specifier
|
||||
DocumentImpl {}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,18 @@ help: consider using the `'static` lifetime
|
|||
LL | fn create_doc() -> impl Document<Cursor<'static> = DocCursorImpl<'_>> {
|
||||
| ~~~~~~~
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/issue-70304.rs:47:61
|
||||
|
|
||||
LL | fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'_>> {
|
||||
| ^^ expected named lifetime parameter
|
||||
|
|
||||
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
|
||||
help: consider using the `'static` lifetime
|
||||
|
|
||||
LL | fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'static>> {
|
||||
| ~~~~~~~
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0106`.
|
||||
|
|
|
@ -27,16 +27,16 @@ type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>
|
|||
|
||||
fn execute_transaction_fut<'f, F, O>(
|
||||
f: F,
|
||||
) -> impl FnOnce(&mut dyn Transaction) -> TransactionFuture<O>
|
||||
) -> impl FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O>
|
||||
where
|
||||
F: FnOnce(&mut dyn Transaction) -> TransactionFuture<O> + 'f
|
||||
F: FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O> + 'f
|
||||
{
|
||||
f
|
||||
}
|
||||
|
||||
impl Context {
|
||||
async fn do_transaction<O>(
|
||||
&self, f: impl FnOnce(&mut dyn Transaction) -> TransactionFuture<O>
|
||||
&self, f: impl FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O>
|
||||
) -> TransactionResult<O>
|
||||
{
|
||||
let mut conn = Connection {};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue