Auto merge of #104048 - cjgillot:split-lifetime, r=compiler-errors
Separate lifetime ident from lifetime resolution in HIR Drive-by: change how suggested generic args are computed. Fixes https://github.com/rust-lang/rust/issues/103815 I recommend reviewing commit-by-commit.
This commit is contained in:
commit
454784afba
49 changed files with 581 additions and 435 deletions
|
@ -605,6 +605,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
output,
|
||||
c_variadic: false,
|
||||
implicit_self: hir::ImplicitSelfKind::None,
|
||||
lifetime_elision_allowed: false,
|
||||
});
|
||||
|
||||
// Lower the argument pattern/ident. The ident is used again in the `.await` lowering.
|
||||
|
@ -917,7 +918,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
|
||||
// Lower outside new scope to preserve `is_in_loop_condition`.
|
||||
let fn_decl = self.lower_fn_decl(decl, None, fn_decl_span, FnDeclKind::Closure, None);
|
||||
let fn_decl = self.lower_fn_decl(decl, closure_id, fn_decl_span, FnDeclKind::Closure, None);
|
||||
|
||||
let c = self.arena.alloc(hir::Closure {
|
||||
def_id: self.local_def_id(closure_id),
|
||||
|
@ -1027,7 +1028,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
// have to conserve the state of being inside a loop condition for the
|
||||
// closure argument types.
|
||||
let fn_decl =
|
||||
self.lower_fn_decl(&outer_decl, None, fn_decl_span, FnDeclKind::Closure, None);
|
||||
self.lower_fn_decl(&outer_decl, closure_id, fn_decl_span, FnDeclKind::Closure, None);
|
||||
|
||||
let c = self.arena.alloc(hir::Closure {
|
||||
def_id: self.local_def_id(closure_id),
|
||||
|
|
|
@ -303,7 +303,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
|||
}
|
||||
|
||||
fn visit_lifetime(&mut self, lifetime: &'hir Lifetime) {
|
||||
self.insert(lifetime.span, lifetime.hir_id, Node::Lifetime(lifetime));
|
||||
self.insert(lifetime.ident.span, lifetime.hir_id, Node::Lifetime(lifetime));
|
||||
}
|
||||
|
||||
fn visit_variant(&mut self, v: &'hir Variant<'hir>) {
|
||||
|
|
|
@ -274,7 +274,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let mut itctx = ImplTraitContext::Universal;
|
||||
let (generics, decl) = this.lower_generics(generics, id, &mut itctx, |this| {
|
||||
let ret_id = asyncness.opt_return_id();
|
||||
this.lower_fn_decl(&decl, Some(id), *fn_sig_span, FnDeclKind::Fn, ret_id)
|
||||
this.lower_fn_decl(&decl, id, *fn_sig_span, FnDeclKind::Fn, ret_id)
|
||||
});
|
||||
let sig = hir::FnSig {
|
||||
decl,
|
||||
|
@ -659,7 +659,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
// Disallow `impl Trait` in foreign items.
|
||||
this.lower_fn_decl(
|
||||
fdec,
|
||||
None,
|
||||
i.id,
|
||||
sig.span,
|
||||
FnDeclKind::ExternFn,
|
||||
None,
|
||||
|
@ -1247,7 +1247,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let header = self.lower_fn_header(sig.header);
|
||||
let mut itctx = ImplTraitContext::Universal;
|
||||
let (generics, decl) = self.lower_generics(generics, id, &mut itctx, |this| {
|
||||
this.lower_fn_decl(&sig.decl, Some(id), sig.span, kind, is_async)
|
||||
this.lower_fn_decl(&sig.decl, id, sig.span, kind, is_async)
|
||||
});
|
||||
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
|
||||
}
|
||||
|
@ -1479,10 +1479,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}))
|
||||
}
|
||||
GenericParamKind::Lifetime => {
|
||||
let ident_span = self.lower_span(ident.span);
|
||||
let ident = self.lower_ident(ident);
|
||||
let lt_id = self.next_node_id();
|
||||
let lifetime = self.new_named_lifetime(id, lt_id, ident_span, ident);
|
||||
let lifetime = self.new_named_lifetime(id, lt_id, ident);
|
||||
Some(hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
|
||||
lifetime,
|
||||
span,
|
||||
|
|
|
@ -327,7 +327,14 @@ enum FnDeclKind {
|
|||
}
|
||||
|
||||
impl FnDeclKind {
|
||||
fn impl_trait_allowed(&self, tcx: TyCtxt<'_>) -> bool {
|
||||
fn param_impl_trait_allowed(&self) -> bool {
|
||||
match self {
|
||||
FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn return_impl_trait_allowed(&self, tcx: TyCtxt<'_>) -> bool {
|
||||
match self {
|
||||
FnDeclKind::Fn | FnDeclKind::Inherent => true,
|
||||
FnDeclKind::Impl if tcx.features().return_position_impl_trait_in_trait => true,
|
||||
|
@ -1255,7 +1262,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
} else {
|
||||
self.next_node_id()
|
||||
};
|
||||
let span = self.tcx.sess.source_map().start_point(t.span);
|
||||
let span = self.tcx.sess.source_map().start_point(t.span).shrink_to_hi();
|
||||
Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id }
|
||||
});
|
||||
let lifetime = self.lower_lifetime(®ion);
|
||||
|
@ -1267,7 +1274,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
generic_params,
|
||||
unsafety: self.lower_unsafety(f.unsafety),
|
||||
abi: self.lower_extern(f.ext),
|
||||
decl: self.lower_fn_decl(&f.decl, None, t.span, FnDeclKind::Pointer, None),
|
||||
decl: self.lower_fn_decl(&f.decl, t.id, t.span, FnDeclKind::Pointer, None),
|
||||
param_names: self.lower_fn_params_to_names(&f.decl),
|
||||
}))
|
||||
}
|
||||
|
@ -1546,15 +1553,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let lifetimes =
|
||||
self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(|(_, lifetime)| {
|
||||
let id = self.next_node_id();
|
||||
let span = lifetime.ident.span;
|
||||
|
||||
let ident = if lifetime.ident.name == kw::UnderscoreLifetime {
|
||||
Ident::with_dummy_span(kw::UnderscoreLifetime)
|
||||
} else {
|
||||
lifetime.ident
|
||||
};
|
||||
|
||||
let l = self.new_named_lifetime(lifetime.id, id, span, ident);
|
||||
let l = self.new_named_lifetime(lifetime.id, id, lifetime.ident);
|
||||
hir::GenericArg::Lifetime(l)
|
||||
}));
|
||||
debug!(?lifetimes);
|
||||
|
@ -1679,7 +1678,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
fn lower_fn_decl(
|
||||
&mut self,
|
||||
decl: &FnDecl,
|
||||
fn_node_id: Option<NodeId>,
|
||||
fn_node_id: NodeId,
|
||||
fn_span: Span,
|
||||
kind: FnDeclKind,
|
||||
make_ret_async: Option<(NodeId, Span)>,
|
||||
|
@ -1694,23 +1693,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
inputs = &inputs[..inputs.len() - 1];
|
||||
}
|
||||
let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| {
|
||||
if fn_node_id.is_some() {
|
||||
self.lower_ty_direct(¶m.ty, &ImplTraitContext::Universal)
|
||||
let itctx = if kind.param_impl_trait_allowed() {
|
||||
ImplTraitContext::Universal
|
||||
} else {
|
||||
self.lower_ty_direct(
|
||||
¶m.ty,
|
||||
&ImplTraitContext::Disallowed(match kind {
|
||||
FnDeclKind::Fn | FnDeclKind::Inherent => {
|
||||
unreachable!("fn should allow in-band lifetimes")
|
||||
}
|
||||
FnDeclKind::ExternFn => ImplTraitPosition::ExternFnParam,
|
||||
FnDeclKind::Closure => ImplTraitPosition::ClosureParam,
|
||||
FnDeclKind::Pointer => ImplTraitPosition::PointerParam,
|
||||
FnDeclKind::Trait => ImplTraitPosition::TraitParam,
|
||||
FnDeclKind::Impl => ImplTraitPosition::ImplParam,
|
||||
}),
|
||||
)
|
||||
}
|
||||
ImplTraitContext::Disallowed(match kind {
|
||||
FnDeclKind::Fn | FnDeclKind::Inherent => {
|
||||
unreachable!("fn should allow APIT")
|
||||
}
|
||||
FnDeclKind::ExternFn => ImplTraitPosition::ExternFnParam,
|
||||
FnDeclKind::Closure => ImplTraitPosition::ClosureParam,
|
||||
FnDeclKind::Pointer => ImplTraitPosition::PointerParam,
|
||||
FnDeclKind::Trait => ImplTraitPosition::TraitParam,
|
||||
FnDeclKind::Impl => ImplTraitPosition::ImplParam,
|
||||
})
|
||||
};
|
||||
self.lower_ty_direct(¶m.ty, &itctx)
|
||||
}));
|
||||
|
||||
let output = if let Some((ret_id, span)) = make_ret_async {
|
||||
|
@ -1733,22 +1730,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
self.lower_async_fn_ret_ty(
|
||||
&decl.output,
|
||||
fn_node_id.expect("`make_ret_async` but no `fn_def_id`"),
|
||||
fn_node_id,
|
||||
ret_id,
|
||||
matches!(kind, FnDeclKind::Trait),
|
||||
)
|
||||
} else {
|
||||
match &decl.output {
|
||||
FnRetTy::Ty(ty) => {
|
||||
let mut context = match fn_node_id {
|
||||
Some(fn_node_id) if kind.impl_trait_allowed(self.tcx) => {
|
||||
let fn_def_id = self.local_def_id(fn_node_id);
|
||||
ImplTraitContext::ReturnPositionOpaqueTy {
|
||||
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
|
||||
in_trait: matches!(kind, FnDeclKind::Trait),
|
||||
}
|
||||
let mut context = if kind.return_impl_trait_allowed(self.tcx) {
|
||||
let fn_def_id = self.local_def_id(fn_node_id);
|
||||
ImplTraitContext::ReturnPositionOpaqueTy {
|
||||
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
|
||||
in_trait: matches!(kind, FnDeclKind::Trait),
|
||||
}
|
||||
_ => ImplTraitContext::Disallowed(match kind {
|
||||
} else {
|
||||
ImplTraitContext::Disallowed(match kind {
|
||||
FnDeclKind::Fn | FnDeclKind::Inherent => {
|
||||
unreachable!("fn should allow in-band lifetimes")
|
||||
}
|
||||
|
@ -1757,7 +1753,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
FnDeclKind::Pointer => ImplTraitPosition::PointerReturn,
|
||||
FnDeclKind::Trait => ImplTraitPosition::TraitReturn,
|
||||
FnDeclKind::Impl => ImplTraitPosition::ImplReturn,
|
||||
}),
|
||||
})
|
||||
};
|
||||
hir::FnRetTy::Return(self.lower_ty(ty, &mut context))
|
||||
}
|
||||
|
@ -1769,6 +1765,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
inputs,
|
||||
output,
|
||||
c_variadic,
|
||||
lifetime_elision_allowed: self.resolver.lifetime_elision_allowed.contains(&fn_node_id),
|
||||
implicit_self: decl.inputs.get(0).map_or(hir::ImplicitSelfKind::None, |arg| {
|
||||
let is_mutable_pat = matches!(
|
||||
arg.pat.kind,
|
||||
|
@ -2010,18 +2007,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let generic_args = self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(
|
||||
|(_, lifetime, res)| {
|
||||
let id = self.next_node_id();
|
||||
let span = lifetime.ident.span;
|
||||
|
||||
let ident = if lifetime.ident.name == kw::UnderscoreLifetime {
|
||||
Ident::with_dummy_span(kw::UnderscoreLifetime)
|
||||
} else {
|
||||
lifetime.ident
|
||||
};
|
||||
|
||||
let res = res.unwrap_or(
|
||||
self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error),
|
||||
);
|
||||
hir::GenericArg::Lifetime(self.new_named_lifetime_with_res(id, span, ident, res))
|
||||
hir::GenericArg::Lifetime(self.new_named_lifetime_with_res(id, lifetime.ident, res))
|
||||
},
|
||||
));
|
||||
|
||||
|
@ -2091,43 +2080,40 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
|
||||
fn lower_lifetime(&mut self, l: &Lifetime) -> &'hir hir::Lifetime {
|
||||
let span = self.lower_span(l.ident.span);
|
||||
let ident = self.lower_ident(l.ident);
|
||||
self.new_named_lifetime(l.id, l.id, span, ident)
|
||||
self.new_named_lifetime(l.id, l.id, ident)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn new_named_lifetime_with_res(
|
||||
&mut self,
|
||||
id: NodeId,
|
||||
span: Span,
|
||||
ident: Ident,
|
||||
res: LifetimeRes,
|
||||
) -> &'hir hir::Lifetime {
|
||||
let name = match res {
|
||||
let res = match res {
|
||||
LifetimeRes::Param { param, .. } => {
|
||||
let p_name = ParamName::Plain(ident);
|
||||
let param = self.get_remapped_def_id(param);
|
||||
|
||||
hir::LifetimeName::Param(param, p_name)
|
||||
hir::LifetimeName::Param(param)
|
||||
}
|
||||
LifetimeRes::Fresh { param, .. } => {
|
||||
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
|
||||
let param = self.local_def_id(param);
|
||||
|
||||
hir::LifetimeName::Param(param, ParamName::Fresh)
|
||||
hir::LifetimeName::Param(param)
|
||||
}
|
||||
LifetimeRes::Infer => hir::LifetimeName::Infer,
|
||||
LifetimeRes::Static => hir::LifetimeName::Static,
|
||||
LifetimeRes::Error => hir::LifetimeName::Error,
|
||||
res => panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span),
|
||||
res => panic!(
|
||||
"Unexpected lifetime resolution {:?} for {:?} at {:?}",
|
||||
res, ident, ident.span
|
||||
),
|
||||
};
|
||||
|
||||
debug!(?name);
|
||||
debug!(?res);
|
||||
self.arena.alloc(hir::Lifetime {
|
||||
hir_id: self.lower_node_id(id),
|
||||
span: self.lower_span(span),
|
||||
name,
|
||||
ident: self.lower_ident(ident),
|
||||
res,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -2136,11 +2122,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&mut self,
|
||||
id: NodeId,
|
||||
new_id: NodeId,
|
||||
span: Span,
|
||||
ident: Ident,
|
||||
) -> &'hir hir::Lifetime {
|
||||
let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error);
|
||||
self.new_named_lifetime_with_res(new_id, span, ident, res)
|
||||
self.new_named_lifetime_with_res(new_id, ident, res)
|
||||
}
|
||||
|
||||
fn lower_generic_params_mut<'s>(
|
||||
|
@ -2552,8 +2537,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
fn elided_dyn_bound(&mut self, span: Span) -> &'hir hir::Lifetime {
|
||||
let r = hir::Lifetime {
|
||||
hir_id: self.next_id(),
|
||||
span: self.lower_span(span),
|
||||
name: hir::LifetimeName::ImplicitObjectLifetimeDefault,
|
||||
ident: Ident::new(kw::Empty, self.lower_span(span)),
|
||||
res: hir::LifetimeName::ImplicitObjectLifetimeDefault,
|
||||
};
|
||||
debug!("elided_dyn_bound: r={:?}", r);
|
||||
self.arena.alloc(r)
|
||||
|
|
|
@ -309,7 +309,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let id = NodeId::from_u32(i);
|
||||
let l = self.lower_lifetime(&Lifetime {
|
||||
id,
|
||||
ident: Ident::new(kw::UnderscoreLifetime, elided_lifetime_span),
|
||||
ident: Ident::new(kw::Empty, elided_lifetime_span),
|
||||
});
|
||||
GenericArg::Lifetime(l)
|
||||
}),
|
||||
|
|
|
@ -2670,7 +2670,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
if let hir::TyKind::Rptr(lifetime, _) = &fn_decl.inputs[index].kind {
|
||||
// With access to the lifetime, we can get
|
||||
// the span of it.
|
||||
arguments.push((*argument, lifetime.span));
|
||||
arguments.push((*argument, lifetime.ident.span));
|
||||
} else {
|
||||
bug!("ty type is a ref but hir type is not");
|
||||
}
|
||||
|
@ -2689,7 +2689,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
let mut return_span = fn_decl.output.span();
|
||||
if let hir::FnRetTy::Return(ty) = &fn_decl.output {
|
||||
if let hir::TyKind::Rptr(lifetime, _) = ty.kind {
|
||||
return_span = lifetime.span;
|
||||
return_span = lifetime.ident.span;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1211,7 +1211,7 @@ fn get_mut_span_in_struct_field<'tcx>(
|
|||
&& let hir::Node::Field(field) = node
|
||||
&& let hir::TyKind::Rptr(lt, hir::MutTy { mutbl: hir::Mutability::Not, ty }) = field.ty.kind
|
||||
{
|
||||
return Some(lt.span.between(ty.span));
|
||||
return Some(lt.ident.span.between(ty.span));
|
||||
}
|
||||
|
||||
None
|
||||
|
|
|
@ -576,30 +576,10 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
|||
let args = last_segment.args.as_ref()?;
|
||||
let lifetime =
|
||||
self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?;
|
||||
match lifetime.name {
|
||||
hir::LifetimeName::Param(_, hir::ParamName::Plain(_) | hir::ParamName::Error)
|
||||
| hir::LifetimeName::Error
|
||||
| hir::LifetimeName::Static => {
|
||||
let lifetime_span = lifetime.span;
|
||||
Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span))
|
||||
}
|
||||
|
||||
hir::LifetimeName::Param(_, hir::ParamName::Fresh)
|
||||
| hir::LifetimeName::ImplicitObjectLifetimeDefault
|
||||
| hir::LifetimeName::Infer => {
|
||||
// In this case, the user left off the lifetime; so
|
||||
// they wrote something like:
|
||||
//
|
||||
// ```
|
||||
// x: Foo<T>
|
||||
// ```
|
||||
//
|
||||
// where the fully elaborated form is `Foo<'_, '1,
|
||||
// T>`. We don't consider this a match; instead we let
|
||||
// the "fully elaborated" type fallback above handle
|
||||
// it.
|
||||
None
|
||||
}
|
||||
if lifetime.is_anonymous() {
|
||||
None
|
||||
} else {
|
||||
Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime.ident.span))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,15 +29,16 @@ use std::fmt;
|
|||
#[derive(Debug, Copy, Clone, Encodable, HashStable_Generic)]
|
||||
pub struct Lifetime {
|
||||
pub hir_id: HirId,
|
||||
pub span: Span,
|
||||
|
||||
/// Either "`'a`", referring to a named lifetime definition,
|
||||
/// or "``" (i.e., `kw::Empty`), for elision placeholders.
|
||||
/// `'_` referring to an anonymous lifetime (either explicitly `'_` or `&type`),
|
||||
/// or "``" (i.e., `kw::Empty`) when appearing in path.
|
||||
///
|
||||
/// HIR lowering inserts these placeholders in type paths that
|
||||
/// refer to type definitions needing lifetime parameters,
|
||||
/// `&T` and `&mut T`, and trait objects without `... + 'a`.
|
||||
pub name: LifetimeName,
|
||||
/// See `Lifetime::suggestion_position` for practical use.
|
||||
pub ident: Ident,
|
||||
|
||||
/// Semantics of this lifetime.
|
||||
pub res: LifetimeName,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Encodable, Hash, Copy)]
|
||||
|
@ -88,7 +89,7 @@ impl ParamName {
|
|||
#[derive(HashStable_Generic)]
|
||||
pub enum LifetimeName {
|
||||
/// User-given names or fresh (synthetic) names.
|
||||
Param(LocalDefId, ParamName),
|
||||
Param(LocalDefId),
|
||||
|
||||
/// Implicit lifetime in a context like `dyn Foo`. This is
|
||||
/// distinguished from implicit lifetimes elsewhere because the
|
||||
|
@ -116,25 +117,6 @@ pub enum LifetimeName {
|
|||
}
|
||||
|
||||
impl LifetimeName {
|
||||
pub fn ident(&self) -> Ident {
|
||||
match *self {
|
||||
LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Error => Ident::empty(),
|
||||
LifetimeName::Infer => Ident::with_dummy_span(kw::UnderscoreLifetime),
|
||||
LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime),
|
||||
LifetimeName::Param(_, param_name) => param_name.ident(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_anonymous(&self) -> bool {
|
||||
match *self {
|
||||
LifetimeName::ImplicitObjectLifetimeDefault
|
||||
| LifetimeName::Infer
|
||||
| LifetimeName::Param(_, ParamName::Fresh)
|
||||
| LifetimeName::Error => true,
|
||||
LifetimeName::Static | LifetimeName::Param(..) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_elided(&self) -> bool {
|
||||
match self {
|
||||
LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Infer => true,
|
||||
|
@ -146,34 +128,54 @@ impl LifetimeName {
|
|||
LifetimeName::Error | LifetimeName::Param(..) | LifetimeName::Static => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_static(&self) -> bool {
|
||||
self == &LifetimeName::Static
|
||||
}
|
||||
|
||||
pub fn normalize_to_macros_2_0(&self) -> LifetimeName {
|
||||
match *self {
|
||||
LifetimeName::Param(def_id, param_name) => {
|
||||
LifetimeName::Param(def_id, param_name.normalize_to_macros_2_0())
|
||||
}
|
||||
lifetime_name => lifetime_name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Lifetime {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.name.ident().fmt(f)
|
||||
if self.ident.name != kw::Empty { self.ident.name.fmt(f) } else { "'_".fmt(f) }
|
||||
}
|
||||
}
|
||||
|
||||
pub enum LifetimeSuggestionPosition {
|
||||
/// The user wrote `'a` or `'_`.
|
||||
Normal,
|
||||
/// The user wrote `&type` or `&mut type`.
|
||||
Ampersand,
|
||||
/// The user wrote `Path` and omitted the `<'_>`.
|
||||
ElidedPath,
|
||||
/// The user wrote `Path<T>`, and omitted the `'_,`.
|
||||
ElidedPathArgument,
|
||||
/// The user wrote `dyn Trait` and omitted the `+ '_`.
|
||||
ObjectDefault,
|
||||
}
|
||||
|
||||
impl Lifetime {
|
||||
pub fn is_elided(&self) -> bool {
|
||||
self.name.is_elided()
|
||||
self.res.is_elided()
|
||||
}
|
||||
|
||||
pub fn is_anonymous(&self) -> bool {
|
||||
self.ident.name == kw::Empty || self.ident.name == kw::UnderscoreLifetime
|
||||
}
|
||||
|
||||
pub fn suggestion_position(&self) -> (LifetimeSuggestionPosition, Span) {
|
||||
if self.ident.name == kw::Empty {
|
||||
if self.ident.span.is_empty() {
|
||||
(LifetimeSuggestionPosition::ElidedPathArgument, self.ident.span)
|
||||
} else {
|
||||
(LifetimeSuggestionPosition::ElidedPath, self.ident.span.shrink_to_hi())
|
||||
}
|
||||
} else if self.res == LifetimeName::ImplicitObjectLifetimeDefault {
|
||||
(LifetimeSuggestionPosition::ObjectDefault, self.ident.span)
|
||||
} else if self.ident.span.is_empty() {
|
||||
(LifetimeSuggestionPosition::Ampersand, self.ident.span)
|
||||
} else {
|
||||
(LifetimeSuggestionPosition::Normal, self.ident.span)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_static(&self) -> bool {
|
||||
self.name.is_static()
|
||||
self.res == LifetimeName::Static
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -267,7 +269,7 @@ pub enum GenericArg<'hir> {
|
|||
impl GenericArg<'_> {
|
||||
pub fn span(&self) -> Span {
|
||||
match self {
|
||||
GenericArg::Lifetime(l) => l.span,
|
||||
GenericArg::Lifetime(l) => l.ident.span,
|
||||
GenericArg::Type(t) => t.span,
|
||||
GenericArg::Const(c) => c.span,
|
||||
GenericArg::Infer(i) => i.span,
|
||||
|
@ -284,7 +286,7 @@ impl GenericArg<'_> {
|
|||
}
|
||||
|
||||
pub fn is_synthetic(&self) -> bool {
|
||||
matches!(self, GenericArg::Lifetime(lifetime) if lifetime.name.ident() == Ident::empty())
|
||||
matches!(self, GenericArg::Lifetime(lifetime) if lifetime.ident == Ident::empty())
|
||||
}
|
||||
|
||||
pub fn descr(&self) -> &'static str {
|
||||
|
@ -446,7 +448,7 @@ impl GenericBound<'_> {
|
|||
match self {
|
||||
GenericBound::Trait(t, ..) => t.span,
|
||||
GenericBound::LangItemTrait(_, span, ..) => *span,
|
||||
GenericBound::Outlives(l) => l.span,
|
||||
GenericBound::Outlives(l) => l.ident.span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -559,6 +561,19 @@ impl<'hir> Generics<'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
/// If there are generic parameters, return where to introduce a new one.
|
||||
pub fn span_for_lifetime_suggestion(&self) -> Option<Span> {
|
||||
if let Some(first) = self.params.first()
|
||||
&& self.span.contains(first.span)
|
||||
{
|
||||
// `fn foo<A>(t: impl Trait)`
|
||||
// ^ suggest `'a, ` here
|
||||
Some(first.span.shrink_to_lo())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// If there are generic parameters, return where to introduce a new one.
|
||||
pub fn span_for_param_suggestion(&self) -> Option<Span> {
|
||||
if self.params.iter().any(|p| self.span.contains(p.span)) {
|
||||
|
@ -765,10 +780,7 @@ pub struct WhereRegionPredicate<'hir> {
|
|||
impl<'hir> WhereRegionPredicate<'hir> {
|
||||
/// Returns `true` if `param_def_id` matches the `lifetime` of this predicate.
|
||||
pub fn is_param_bound(&self, param_def_id: LocalDefId) -> bool {
|
||||
match self.lifetime.name {
|
||||
LifetimeName::Param(id, _) => id == param_def_id,
|
||||
_ => false,
|
||||
}
|
||||
self.lifetime.res == LifetimeName::Param(param_def_id)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2688,6 +2700,8 @@ pub struct FnDecl<'hir> {
|
|||
pub c_variadic: bool,
|
||||
/// Does the function have an implicit self?
|
||||
pub implicit_self: ImplicitSelfKind,
|
||||
/// Is lifetime elision allowed.
|
||||
pub lifetime_elision_allowed: bool,
|
||||
}
|
||||
|
||||
/// Represents what type of implicit self a function has, if any.
|
||||
|
@ -3453,7 +3467,7 @@ impl<'hir> Node<'hir> {
|
|||
| Node::Variant(Variant { ident, .. })
|
||||
| Node::Item(Item { ident, .. })
|
||||
| Node::PathSegment(PathSegment { ident, .. }) => Some(*ident),
|
||||
Node::Lifetime(lt) => Some(lt.name.ident()),
|
||||
Node::Lifetime(lt) => Some(lt.ident),
|
||||
Node::GenericParam(p) => Some(p.name.ident()),
|
||||
Node::TypeBinding(b) => Some(b.ident),
|
||||
Node::Param(..)
|
||||
|
|
|
@ -1109,17 +1109,7 @@ pub fn walk_generic_arg<'v, V: Visitor<'v>>(visitor: &mut V, generic_arg: &'v Ge
|
|||
|
||||
pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
|
||||
visitor.visit_id(lifetime.hir_id);
|
||||
match lifetime.name {
|
||||
LifetimeName::Param(_, ParamName::Plain(ident)) => {
|
||||
visitor.visit_ident(ident);
|
||||
}
|
||||
LifetimeName::Param(_, ParamName::Fresh)
|
||||
| LifetimeName::Param(_, ParamName::Error)
|
||||
| LifetimeName::Static
|
||||
| LifetimeName::Error
|
||||
| LifetimeName::ImplicitObjectLifetimeDefault
|
||||
| LifetimeName::Infer => {}
|
||||
}
|
||||
visitor.visit_ident(lifetime.ident);
|
||||
}
|
||||
|
||||
pub fn walk_qpath<'v, V: Visitor<'v>>(visitor: &mut V, qpath: &'v QPath<'v>, id: HirId) {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#![feature(associated_type_defaults)]
|
||||
#![feature(closure_track_caller)]
|
||||
#![feature(const_btree_len)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(never_type)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
|
|
@ -241,14 +241,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
}
|
||||
|
||||
None => {
|
||||
self.re_infer(def, lifetime.span).unwrap_or_else(|| {
|
||||
self.re_infer(def, lifetime.ident.span).unwrap_or_else(|| {
|
||||
debug!(?lifetime, "unelided lifetime in signature");
|
||||
|
||||
// This indicates an illegal lifetime
|
||||
// elision. `resolve_lifetime` should have
|
||||
// reported an error in this case -- but if
|
||||
// not, let's error out.
|
||||
tcx.sess.delay_span_bug(lifetime.span, "unelided lifetime in signature");
|
||||
tcx.sess.delay_span_bug(lifetime.ident.span, "unelided lifetime in signature");
|
||||
|
||||
// Supply some dummy value. We don't have an
|
||||
// `re_error`, annoyingly, so use `'static`.
|
||||
|
@ -961,9 +961,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
}
|
||||
hir::GenericBound::Outlives(lifetime) => {
|
||||
let region = self.ast_region_to_region(lifetime, None);
|
||||
bounds
|
||||
.region_bounds
|
||||
.push((ty::Binder::bind_with_vars(region, bound_vars), lifetime.span));
|
||||
bounds.region_bounds.push((
|
||||
ty::Binder::bind_with_vars(region, bound_vars),
|
||||
lifetime.ident.span,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -398,7 +398,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
|
|||
Some(rl::Region::Static | rl::Region::EarlyBound(..)) => {}
|
||||
Some(rl::Region::LateBound(debruijn, _, _)) if debruijn < self.outer_index => {}
|
||||
Some(rl::Region::LateBound(..) | rl::Region::Free(..)) | None => {
|
||||
self.has_late_bound_regions = Some(lt.span);
|
||||
self.has_late_bound_regions = Some(lt.ident.span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -595,7 +595,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
this.visit_poly_trait_ref(bound);
|
||||
}
|
||||
});
|
||||
match lifetime.name {
|
||||
match lifetime.res {
|
||||
LifetimeName::ImplicitObjectLifetimeDefault => {
|
||||
// If the user does not write *anything*, we
|
||||
// use the object lifetime defaulting
|
||||
|
@ -686,7 +686,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
if !parent_id.is_owner() {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
lifetime.span,
|
||||
lifetime.ident.span,
|
||||
E0657,
|
||||
"`impl Trait` can only capture lifetimes bound at the fn or impl level"
|
||||
)
|
||||
|
@ -698,7 +698,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
}) = self.tcx.hir().get(parent_id)
|
||||
{
|
||||
let mut err = self.tcx.sess.struct_span_err(
|
||||
lifetime.span,
|
||||
lifetime.ident.span,
|
||||
"higher kinded lifetime bounds on nested opaque types are not supported yet",
|
||||
);
|
||||
err.span_note(self.tcx.def_span(def_id), "lifetime declared here");
|
||||
|
@ -802,9 +802,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
|
||||
match lifetime_ref.name {
|
||||
match lifetime_ref.res {
|
||||
hir::LifetimeName::Static => self.insert_lifetime(lifetime_ref, Region::Static),
|
||||
hir::LifetimeName::Param(param_def_id, _) => {
|
||||
hir::LifetimeName::Param(param_def_id) => {
|
||||
self.resolve_lifetime_ref(param_def_id, lifetime_ref)
|
||||
}
|
||||
// If we've already reported an error, just ignore `lifetime_ref`.
|
||||
|
@ -912,27 +912,27 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
this.visit_lifetime(lifetime);
|
||||
walk_list!(this, visit_param_bound, bounds);
|
||||
|
||||
if lifetime.name != hir::LifetimeName::Static {
|
||||
if lifetime.res != hir::LifetimeName::Static {
|
||||
for bound in bounds {
|
||||
let hir::GenericBound::Outlives(ref lt) = bound else {
|
||||
continue;
|
||||
};
|
||||
if lt.name != hir::LifetimeName::Static {
|
||||
if lt.res != hir::LifetimeName::Static {
|
||||
continue;
|
||||
}
|
||||
this.insert_lifetime(lt, Region::Static);
|
||||
this.tcx
|
||||
.sess
|
||||
.struct_span_warn(
|
||||
lifetime.span,
|
||||
lifetime.ident.span,
|
||||
&format!(
|
||||
"unnecessary lifetime parameter `{}`",
|
||||
lifetime.name.ident(),
|
||||
lifetime.ident,
|
||||
),
|
||||
)
|
||||
.help(&format!(
|
||||
"you can use the `'static` lifetime directly, in place of `{}`",
|
||||
lifetime.name.ident(),
|
||||
lifetime.ident,
|
||||
))
|
||||
.emit();
|
||||
}
|
||||
|
@ -1043,7 +1043,7 @@ fn object_lifetime_default<'tcx>(tcx: TyCtxt<'tcx>, param_def_id: DefId) -> Obje
|
|||
|
||||
for bound in bound.bounds {
|
||||
if let hir::GenericBound::Outlives(ref lifetime) = *bound {
|
||||
set.insert(lifetime.name.normalize_to_macros_2_0());
|
||||
set.insert(lifetime.res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1051,7 +1051,7 @@ fn object_lifetime_default<'tcx>(tcx: TyCtxt<'tcx>, param_def_id: DefId) -> Obje
|
|||
match set {
|
||||
Set1::Empty => ObjectLifetimeDefault::Empty,
|
||||
Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static,
|
||||
Set1::One(hir::LifetimeName::Param(param_def_id, _)) => {
|
||||
Set1::One(hir::LifetimeName::Param(param_def_id)) => {
|
||||
ObjectLifetimeDefault::Param(param_def_id.to_def_id())
|
||||
}
|
||||
_ => ObjectLifetimeDefault::Ambiguous,
|
||||
|
@ -1195,42 +1195,50 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
// Fresh lifetimes in APIT used to be allowed in async fns and forbidden in
|
||||
// regular fns.
|
||||
if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin
|
||||
&& let hir::LifetimeName::Param(_, hir::ParamName::Fresh) = lifetime_ref.name
|
||||
&& let hir::LifetimeName::Param(_) = lifetime_ref.res
|
||||
&& lifetime_ref.is_anonymous()
|
||||
&& let hir::IsAsync::NotAsync = self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id)
|
||||
&& !self.tcx.features().anonymous_lifetime_in_impl_trait
|
||||
{
|
||||
let mut diag = rustc_session::parse::feature_err(
|
||||
&self.tcx.sess.parse_sess,
|
||||
sym::anonymous_lifetime_in_impl_trait,
|
||||
lifetime_ref.span,
|
||||
lifetime_ref.ident.span,
|
||||
"anonymous lifetimes in `impl Trait` are unstable",
|
||||
);
|
||||
|
||||
match self.tcx.hir().get_generics(lifetime_ref.hir_id.owner.def_id) {
|
||||
Some(generics) => {
|
||||
if let Some(generics) =
|
||||
self.tcx.hir().get_generics(lifetime_ref.hir_id.owner.def_id)
|
||||
{
|
||||
let new_param_sugg = if let Some(span) =
|
||||
generics.span_for_lifetime_suggestion()
|
||||
{
|
||||
(span, "'a, ".to_owned())
|
||||
} else {
|
||||
(generics.span, "<'a>".to_owned())
|
||||
};
|
||||
|
||||
let new_param_sugg_tuple;
|
||||
let lifetime_sugg = match lifetime_ref.suggestion_position() {
|
||||
(hir::LifetimeSuggestionPosition::Normal, span) => (span, "'a".to_owned()),
|
||||
(hir::LifetimeSuggestionPosition::Ampersand, span) => (span, "'a ".to_owned()),
|
||||
(hir::LifetimeSuggestionPosition::ElidedPath, span) => (span, "<'a>".to_owned()),
|
||||
(hir::LifetimeSuggestionPosition::ElidedPathArgument, span) => (span, "'a, ".to_owned()),
|
||||
(hir::LifetimeSuggestionPosition::ObjectDefault, span) => (span, "+ 'a".to_owned()),
|
||||
};
|
||||
let suggestions = vec![
|
||||
lifetime_sugg,
|
||||
new_param_sugg,
|
||||
];
|
||||
|
||||
new_param_sugg_tuple = match generics.span_for_param_suggestion() {
|
||||
Some(_) => {
|
||||
Some((self.tcx.sess.source_map().span_through_char(generics.span, '<').shrink_to_hi(), "'a, ".to_owned()))
|
||||
},
|
||||
None => Some((generics.span, "<'a>".to_owned()))
|
||||
};
|
||||
|
||||
let mut multi_sugg_vec = vec![(lifetime_ref.span.shrink_to_hi(), "'a ".to_owned())];
|
||||
|
||||
if let Some(new_tuple) = new_param_sugg_tuple{
|
||||
multi_sugg_vec.push(new_tuple);
|
||||
}
|
||||
|
||||
diag.span_label(lifetime_ref.span, "expected named lifetime parameter");
|
||||
diag.multipart_suggestion("consider introducing a named lifetime parameter",
|
||||
multi_sugg_vec,
|
||||
rustc_errors::Applicability::MaybeIncorrect);
|
||||
|
||||
},
|
||||
None => { }
|
||||
diag.span_label(
|
||||
lifetime_ref.ident.span,
|
||||
"expected named lifetime parameter",
|
||||
);
|
||||
diag.multipart_suggestion(
|
||||
"consider introducing a named lifetime parameter",
|
||||
suggestions,
|
||||
rustc_errors::Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
||||
diag.emit();
|
||||
|
@ -1287,7 +1295,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
where_bound_origin: Some(hir::PredicateOrigin::ImplTrait), ..
|
||||
} => {
|
||||
let mut err = self.tcx.sess.struct_span_err(
|
||||
lifetime_ref.span,
|
||||
lifetime_ref.ident.span,
|
||||
"`impl Trait` can only mention lifetimes bound at the fn or impl level",
|
||||
);
|
||||
err.span_note(self.tcx.def_span(region_def_id), "lifetime declared here");
|
||||
|
@ -1307,7 +1315,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
self.tcx.sess.delay_span_bug(
|
||||
lifetime_ref.span,
|
||||
lifetime_ref.ident.span,
|
||||
&format!("Could not resolve {:?} in scope {:#?}", lifetime_ref, self.scope,),
|
||||
);
|
||||
}
|
||||
|
@ -1625,10 +1633,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) {
|
||||
debug!(
|
||||
node = ?self.tcx.hir().node_to_string(lifetime_ref.hir_id),
|
||||
span = ?self.tcx.sess.source_map().span_to_diagnostic_string(lifetime_ref.span)
|
||||
);
|
||||
debug!(span = ?lifetime_ref.ident.span);
|
||||
self.map.defs.insert(lifetime_ref.hir_id, def);
|
||||
}
|
||||
|
||||
|
@ -1839,7 +1844,7 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
|
|||
}
|
||||
|
||||
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
|
||||
if let hir::LifetimeName::Param(def_id, _) = lifetime_ref.name {
|
||||
if let hir::LifetimeName::Param(def_id) = lifetime_ref.res {
|
||||
self.regions.insert(def_id);
|
||||
}
|
||||
}
|
||||
|
@ -1852,7 +1857,7 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
|
|||
|
||||
impl<'v> Visitor<'v> for AllCollector {
|
||||
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
|
||||
if let hir::LifetimeName::Param(def_id, _) = lifetime_ref.name {
|
||||
if let hir::LifetimeName::Param(def_id) = lifetime_ref.res {
|
||||
self.regions.insert(def_id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -229,7 +229,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
|
|||
predicates.extend(region_pred.bounds.iter().map(|bound| {
|
||||
let (r2, span) = match bound {
|
||||
hir::GenericBound::Outlives(lt) => {
|
||||
(<dyn AstConv<'_>>::ast_region_to_region(&icx, lt, None), lt.span)
|
||||
(<dyn AstConv<'_>>::ast_region_to_region(&icx, lt, None), lt.ident.span)
|
||||
}
|
||||
_ => bug!(),
|
||||
};
|
||||
|
|
|
@ -296,25 +296,35 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
|||
) -> String {
|
||||
debug!(?path_hir_id);
|
||||
|
||||
// If there was already a lifetime among the arguments, just replicate that one.
|
||||
if let Some(lt) = self.gen_args.args.iter().find_map(|arg| match arg {
|
||||
hir::GenericArg::Lifetime(lt) => Some(lt),
|
||||
_ => None,
|
||||
}) {
|
||||
return std::iter::repeat(lt.to_string())
|
||||
.take(num_params_to_take)
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
}
|
||||
|
||||
let mut ret = Vec::new();
|
||||
let mut ty_id = None;
|
||||
for (id, node) in self.tcx.hir().parent_iter(path_hir_id) {
|
||||
debug!(?id);
|
||||
let params = if let Some(generics) = node.generics() {
|
||||
generics.params
|
||||
} else if let hir::Node::Ty(ty) = node
|
||||
&& let hir::TyKind::BareFn(bare_fn) = ty.kind
|
||||
{
|
||||
bare_fn.generic_params
|
||||
} else {
|
||||
&[]
|
||||
};
|
||||
ret.extend(params.iter().filter_map(|p| {
|
||||
let hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }
|
||||
= p.kind
|
||||
else { return None };
|
||||
let hir::ParamName::Plain(name) = p.name else { return None };
|
||||
Some(name.to_string())
|
||||
}));
|
||||
if let hir::Node::Ty(_) = node {
|
||||
ty_id = Some(id);
|
||||
}
|
||||
|
||||
// Suggest `'_` when in function parameter or elided function return.
|
||||
if let Some(fn_decl) = node.fn_decl() && let Some(ty_id) = ty_id {
|
||||
let in_arg = fn_decl.inputs.iter().any(|t| t.hir_id == ty_id);
|
||||
let in_ret = matches!(fn_decl.output, hir::FnRetTy::Return(ty) if ty.hir_id == ty_id);
|
||||
|
||||
if in_arg || (in_ret && fn_decl.lifetime_elision_allowed) {
|
||||
return std::iter::repeat("'_".to_owned()).take(num_params_to_take).collect::<Vec<_>>().join(", ");
|
||||
}
|
||||
}
|
||||
|
||||
// Suggest `'static` when in const/static item-like.
|
||||
if let hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Static { .. } | hir::ItemKind::Const { .. },
|
||||
|
@ -334,11 +344,29 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
|||
})
|
||||
| hir::Node::AnonConst(..) = node
|
||||
{
|
||||
ret.extend(
|
||||
std::iter::repeat("'static".to_owned())
|
||||
.take(num_params_to_take.saturating_sub(ret.len())),
|
||||
);
|
||||
return std::iter::repeat("'static".to_owned())
|
||||
.take(num_params_to_take.saturating_sub(ret.len()))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
}
|
||||
|
||||
let params = if let Some(generics) = node.generics() {
|
||||
generics.params
|
||||
} else if let hir::Node::Ty(ty) = node
|
||||
&& let hir::TyKind::BareFn(bare_fn) = ty.kind
|
||||
{
|
||||
bare_fn.generic_params
|
||||
} else {
|
||||
&[]
|
||||
};
|
||||
ret.extend(params.iter().filter_map(|p| {
|
||||
let hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }
|
||||
= p.kind
|
||||
else { return None };
|
||||
let hir::ParamName::Plain(name) = p.name else { return None };
|
||||
Some(name.to_string())
|
||||
}));
|
||||
|
||||
if ret.len() >= num_params_to_take {
|
||||
return ret[..num_params_to_take].join(", ");
|
||||
}
|
||||
|
|
|
@ -2159,7 +2159,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
pub fn print_lifetime(&mut self, lifetime: &hir::Lifetime) {
|
||||
self.print_ident(lifetime.name.ident())
|
||||
self.print_ident(lifetime.ident)
|
||||
}
|
||||
|
||||
pub fn print_where_clause(&mut self, generics: &hir::Generics<'_>) {
|
||||
|
|
|
@ -375,7 +375,7 @@ impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> {
|
|||
return false;
|
||||
};
|
||||
|
||||
if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() {
|
||||
if !lifetime_sub.is_anonymous() || !lifetime_sup.is_anonymous() {
|
||||
return false;
|
||||
};
|
||||
|
||||
|
@ -407,20 +407,20 @@ impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> {
|
|||
let suggestion_param_name =
|
||||
suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
|
||||
|
||||
debug!(?lifetime_sup.span);
|
||||
debug!(?lifetime_sub.span);
|
||||
let make_suggestion = |span: rustc_span::Span| {
|
||||
if span.is_empty() {
|
||||
(span, format!("{}, ", suggestion_param_name))
|
||||
} else if let Ok("&") = self.tcx.sess.source_map().span_to_snippet(span).as_deref()
|
||||
{
|
||||
(span.shrink_to_hi(), format!("{} ", suggestion_param_name))
|
||||
debug!(?lifetime_sup.ident.span);
|
||||
debug!(?lifetime_sub.ident.span);
|
||||
let make_suggestion = |ident: Ident| {
|
||||
let sugg = if ident.name == kw::Empty {
|
||||
format!("{}, ", suggestion_param_name)
|
||||
} else if ident.name == kw::UnderscoreLifetime && ident.span.is_empty() {
|
||||
format!("{} ", suggestion_param_name)
|
||||
} else {
|
||||
(span, suggestion_param_name.clone())
|
||||
}
|
||||
suggestion_param_name.clone()
|
||||
};
|
||||
(ident.span, sugg)
|
||||
};
|
||||
let mut suggestions =
|
||||
vec![make_suggestion(lifetime_sub.span), make_suggestion(lifetime_sup.span)];
|
||||
vec![make_suggestion(lifetime_sub.ident), make_suggestion(lifetime_sup.ident)];
|
||||
|
||||
if introduce_new {
|
||||
let new_param_suggestion = if let Some(first) =
|
||||
|
|
|
@ -314,10 +314,10 @@ pub fn suggest_new_region_bound(
|
|||
.iter()
|
||||
.filter_map(|arg| match arg {
|
||||
GenericBound::Outlives(Lifetime {
|
||||
name: LifetimeName::Static,
|
||||
span,
|
||||
res: LifetimeName::Static,
|
||||
ident,
|
||||
..
|
||||
}) => Some(*span),
|
||||
}) => Some(ident.span),
|
||||
_ => None,
|
||||
})
|
||||
.next()
|
||||
|
@ -342,10 +342,10 @@ pub fn suggest_new_region_bound(
|
|||
.bounds
|
||||
.iter()
|
||||
.filter_map(|arg| match arg {
|
||||
GenericBound::Outlives(Lifetime { name, span, .. })
|
||||
if name.ident().to_string() == lifetime_name =>
|
||||
GenericBound::Outlives(Lifetime { ident, .. })
|
||||
if ident.name.to_string() == lifetime_name =>
|
||||
{
|
||||
Some(*span)
|
||||
Some(ident.span)
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
|
@ -361,8 +361,8 @@ pub fn suggest_new_region_bound(
|
|||
);
|
||||
}
|
||||
}
|
||||
TyKind::TraitObject(_, lt, _) => match lt.name {
|
||||
LifetimeName::ImplicitObjectLifetimeDefault => {
|
||||
TyKind::TraitObject(_, lt, _) => {
|
||||
if let LifetimeName::ImplicitObjectLifetimeDefault = lt.res {
|
||||
err.span_suggestion_verbose(
|
||||
fn_return.span.shrink_to_hi(),
|
||||
&format!(
|
||||
|
@ -374,15 +374,14 @@ pub fn suggest_new_region_bound(
|
|||
&plus_lt,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
name if name.ident().to_string() != lifetime_name => {
|
||||
} else if lt.ident.name.to_string() != lifetime_name {
|
||||
// With this check we avoid suggesting redundant bounds. This
|
||||
// would happen if there are nested impl/dyn traits and only
|
||||
// one of them has the bound we'd suggest already there, like
|
||||
// in `impl Foo<X = dyn Bar> + '_`.
|
||||
if let Some(explicit_static) = &explicit_static {
|
||||
err.span_suggestion_verbose(
|
||||
lt.span,
|
||||
lt.ident.span,
|
||||
&format!("{} the trait object's {}", consider, explicit_static),
|
||||
&lifetime_name,
|
||||
Applicability::MaybeIncorrect,
|
||||
|
@ -397,8 +396,7 @@ pub fn suggest_new_region_bound(
|
|||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -561,7 +559,7 @@ impl<'a, 'tcx> Visitor<'tcx> for HirTraitObjectVisitor<'a> {
|
|||
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
|
||||
if let TyKind::TraitObject(
|
||||
poly_trait_refs,
|
||||
Lifetime { name: LifetimeName::ImplicitObjectLifetimeDefault, .. },
|
||||
Lifetime { res: LifetimeName::ImplicitObjectLifetimeDefault, .. },
|
||||
_,
|
||||
) = t.kind
|
||||
{
|
||||
|
|
|
@ -272,11 +272,7 @@ fn gen_args(segment: &PathSegment<'_>) -> String {
|
|||
.args
|
||||
.iter()
|
||||
.filter_map(|arg| {
|
||||
if let GenericArg::Lifetime(lt) = arg {
|
||||
Some(lt.name.ident().to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
if let GenericArg::Lifetime(lt) = arg { Some(lt.ident.to_string()) } else { None }
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ fn gen_args(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> String {
|
|||
.args
|
||||
.iter()
|
||||
.map(|arg| match arg {
|
||||
GenericArg::Lifetime(lt) => lt.name.ident().to_string(),
|
||||
GenericArg::Lifetime(lt) => lt.to_string(),
|
||||
GenericArg::Type(ty) => {
|
||||
cx.tcx.sess.source_map().span_to_snippet(ty.span).unwrap_or_else(|_| "_".into())
|
||||
}
|
||||
|
|
|
@ -1058,7 +1058,7 @@ impl<'hir> Map<'hir> {
|
|||
Node::Arm(arm) => arm.span,
|
||||
Node::Block(block) => block.span,
|
||||
Node::Ctor(..) => self.span_with_body(self.get_parent_node(hir_id)),
|
||||
Node::Lifetime(lifetime) => lifetime.span,
|
||||
Node::Lifetime(lifetime) => lifetime.ident.span,
|
||||
Node::GenericParam(param) => param.span,
|
||||
Node::Infer(i) => i.span,
|
||||
Node::Local(local) => local.span,
|
||||
|
|
|
@ -397,7 +397,7 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
|
|||
hir::TyKind::TraitObject(
|
||||
_,
|
||||
hir::Lifetime {
|
||||
name:
|
||||
res:
|
||||
hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static,
|
||||
..
|
||||
},
|
||||
|
@ -421,10 +421,9 @@ pub struct StaticLifetimeVisitor<'tcx>(pub Vec<Span>, pub crate::hir::map::Map<'
|
|||
|
||||
impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> {
|
||||
fn visit_lifetime(&mut self, lt: &'v hir::Lifetime) {
|
||||
if let hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static =
|
||||
lt.name
|
||||
if let hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static = lt.res
|
||||
{
|
||||
self.0.push(lt.span);
|
||||
self.0.push(lt.ident.span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::ty::{EarlyBinder, SubstsRef};
|
|||
use rustc_ast as ast;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::symbol::{kw, Symbol};
|
||||
use rustc_span::Span;
|
||||
|
||||
use super::{EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, Predicate, TyCtxt};
|
||||
|
@ -78,6 +78,15 @@ impl GenericParamDef {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_anonymous_lifetime(&self) -> bool {
|
||||
match self.kind {
|
||||
GenericParamDefKind::Lifetime => {
|
||||
self.name == kw::UnderscoreLifetime || self.name == kw::Empty
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_value<'tcx>(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
|
|
@ -208,6 +208,8 @@ pub struct ResolverAstLowering {
|
|||
/// A small map keeping true kinds of built-in macros that appear to be fn-like on
|
||||
/// the surface (`macro` items in libcore), but are actually attributes or derives.
|
||||
pub builtin_macro_kinds: FxHashMap<LocalDefId, MacroKind>,
|
||||
/// List functions and methods for which lifetime elision was successful.
|
||||
pub lifetime_elision_allowed: FxHashSet<ast::NodeId>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
|
@ -529,7 +531,7 @@ impl ty::EarlyBoundRegion {
|
|||
/// Does this early bound region have a name? Early bound regions normally
|
||||
/// always have names except when using anonymous lifetimes (`'_`).
|
||||
pub fn has_name(&self) -> bool {
|
||||
self.name != kw::UnderscoreLifetime
|
||||
self.name != kw::UnderscoreLifetime && self.name != kw::Empty
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1977,17 +1977,13 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
|
|||
let identify_regions = self.tcx.sess.opts.unstable_opts.identify_regions;
|
||||
|
||||
match *region {
|
||||
ty::ReEarlyBound(ref data) => {
|
||||
data.name != kw::Empty && data.name != kw::UnderscoreLifetime
|
||||
}
|
||||
ty::ReEarlyBound(ref data) => data.has_name(),
|
||||
|
||||
ty::ReLateBound(_, ty::BoundRegion { kind: br, .. })
|
||||
| ty::ReFree(ty::FreeRegion { bound_region: br, .. })
|
||||
| ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
|
||||
if let ty::BrNamed(_, name) = br {
|
||||
if name != kw::Empty && name != kw::UnderscoreLifetime {
|
||||
return true;
|
||||
}
|
||||
if br.is_named() {
|
||||
return true;
|
||||
}
|
||||
|
||||
if let Some((region, _)) = highlight.highlight_bound_region {
|
||||
|
@ -2063,11 +2059,9 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
|
|||
ty::ReLateBound(_, ty::BoundRegion { kind: br, .. })
|
||||
| ty::ReFree(ty::FreeRegion { bound_region: br, .. })
|
||||
| ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
|
||||
if let ty::BrNamed(_, name) = br {
|
||||
if name != kw::Empty && name != kw::UnderscoreLifetime {
|
||||
p!(write("{}", name));
|
||||
return Ok(self);
|
||||
}
|
||||
if let ty::BrNamed(_, name) = br && br.is_named() {
|
||||
p!(write("{}", name));
|
||||
return Ok(self);
|
||||
}
|
||||
|
||||
if let Some((region, counter)) = highlight.highlight_bound_region {
|
||||
|
@ -2280,7 +2274,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
|
|||
|
||||
(name, ty::BrNamed(CRATE_DEF_ID.to_def_id(), name))
|
||||
}
|
||||
ty::BrNamed(def_id, kw::UnderscoreLifetime) => {
|
||||
ty::BrNamed(def_id, kw::UnderscoreLifetime | kw::Empty) => {
|
||||
let name = next_name(&self);
|
||||
|
||||
if let Some(lt_idx) = lifetime_idx {
|
||||
|
|
|
@ -83,7 +83,9 @@ pub struct BoundRegion {
|
|||
impl BoundRegionKind {
|
||||
pub fn is_named(&self) -> bool {
|
||||
match *self {
|
||||
BoundRegionKind::BrNamed(_, name) => name != kw::UnderscoreLifetime,
|
||||
BoundRegionKind::BrNamed(_, name) => {
|
||||
name != kw::UnderscoreLifetime && name != kw::Empty
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1838,6 +1838,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||
|
||||
let outer_failures = take(&mut self.diagnostic_metadata.current_elision_failures);
|
||||
let output_rib = if let Ok(res) = elision_lifetime.as_ref() {
|
||||
self.r.lifetime_elision_allowed.insert(fn_id);
|
||||
LifetimeRibKind::Elided(*res)
|
||||
} else {
|
||||
LifetimeRibKind::ElisionFailure
|
||||
|
|
|
@ -1036,6 +1036,8 @@ pub struct Resolver<'a> {
|
|||
/// they are declared in the static array generated by proc_macro_harness.
|
||||
proc_macros: Vec<NodeId>,
|
||||
confused_type_with_std_module: FxHashMap<Span, Span>,
|
||||
/// Whether lifetime elision was successful.
|
||||
lifetime_elision_allowed: FxHashSet<NodeId>,
|
||||
|
||||
effective_visibilities: EffectiveVisibilities,
|
||||
}
|
||||
|
@ -1354,6 +1356,7 @@ impl<'a> Resolver<'a> {
|
|||
trait_impls: Default::default(),
|
||||
proc_macros: Default::default(),
|
||||
confused_type_with_std_module: Default::default(),
|
||||
lifetime_elision_allowed: Default::default(),
|
||||
effective_visibilities: Default::default(),
|
||||
};
|
||||
|
||||
|
@ -1448,6 +1451,7 @@ impl<'a> Resolver<'a> {
|
|||
def_id_to_node_id: self.def_id_to_node_id,
|
||||
trait_map: self.trait_map,
|
||||
builtin_macro_kinds: self.builtin_macro_kinds,
|
||||
lifetime_elision_allowed: self.lifetime_elision_allowed,
|
||||
};
|
||||
ResolverOutputs { definitions, global_ctxt, ast_lowering }
|
||||
}
|
||||
|
@ -1491,6 +1495,7 @@ impl<'a> Resolver<'a> {
|
|||
def_id_to_node_id: self.def_id_to_node_id.clone(),
|
||||
trait_map: self.trait_map.clone(),
|
||||
builtin_macro_kinds: self.builtin_macro_kinds.clone(),
|
||||
lifetime_elision_allowed: self.lifetime_elision_allowed.clone(),
|
||||
};
|
||||
ResolverOutputs { definitions, global_ctxt, ast_lowering }
|
||||
}
|
||||
|
|
|
@ -167,7 +167,7 @@ impl<'hir> Sig for hir::Ty<'hir> {
|
|||
}
|
||||
hir::TyKind::Rptr(ref lifetime, ref mt) => {
|
||||
let mut prefix = "&".to_owned();
|
||||
prefix.push_str(&lifetime.name.ident().to_string());
|
||||
prefix.push_str(&lifetime.ident.to_string());
|
||||
prefix.push(' ');
|
||||
if mt.mutbl.is_mut() {
|
||||
prefix.push_str("mut ");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue