1
Fork 0

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:
bors 2022-11-27 14:30:19 +00:00
commit 454784afba
49 changed files with 581 additions and 435 deletions

View file

@ -605,6 +605,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
output, output,
c_variadic: false, c_variadic: false,
implicit_self: hir::ImplicitSelfKind::None, implicit_self: hir::ImplicitSelfKind::None,
lifetime_elision_allowed: false,
}); });
// Lower the argument pattern/ident. The ident is used again in the `.await` lowering. // 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); let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
// Lower outside new scope to preserve `is_in_loop_condition`. // 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 { let c = self.arena.alloc(hir::Closure {
def_id: self.local_def_id(closure_id), 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 // have to conserve the state of being inside a loop condition for the
// closure argument types. // closure argument types.
let fn_decl = 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 { let c = self.arena.alloc(hir::Closure {
def_id: self.local_def_id(closure_id), def_id: self.local_def_id(closure_id),

View file

@ -303,7 +303,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
} }
fn visit_lifetime(&mut self, lifetime: &'hir Lifetime) { 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>) { fn visit_variant(&mut self, v: &'hir Variant<'hir>) {

View file

@ -274,7 +274,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let mut itctx = ImplTraitContext::Universal; let mut itctx = ImplTraitContext::Universal;
let (generics, decl) = this.lower_generics(generics, id, &mut itctx, |this| { let (generics, decl) = this.lower_generics(generics, id, &mut itctx, |this| {
let ret_id = asyncness.opt_return_id(); 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 { let sig = hir::FnSig {
decl, decl,
@ -659,7 +659,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
// Disallow `impl Trait` in foreign items. // Disallow `impl Trait` in foreign items.
this.lower_fn_decl( this.lower_fn_decl(
fdec, fdec,
None, i.id,
sig.span, sig.span,
FnDeclKind::ExternFn, FnDeclKind::ExternFn,
None, None,
@ -1247,7 +1247,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let header = self.lower_fn_header(sig.header); let header = self.lower_fn_header(sig.header);
let mut itctx = ImplTraitContext::Universal; let mut itctx = ImplTraitContext::Universal;
let (generics, decl) = self.lower_generics(generics, id, &mut itctx, |this| { 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) }) (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
} }
@ -1479,10 +1479,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
})) }))
} }
GenericParamKind::Lifetime => { GenericParamKind::Lifetime => {
let ident_span = self.lower_span(ident.span);
let ident = self.lower_ident(ident); let ident = self.lower_ident(ident);
let lt_id = self.next_node_id(); 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 { Some(hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
lifetime, lifetime,
span, span,

View file

@ -327,7 +327,14 @@ enum FnDeclKind {
} }
impl 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 { match self {
FnDeclKind::Fn | FnDeclKind::Inherent => true, FnDeclKind::Fn | FnDeclKind::Inherent => true,
FnDeclKind::Impl if tcx.features().return_position_impl_trait_in_trait => true, FnDeclKind::Impl if tcx.features().return_position_impl_trait_in_trait => true,
@ -1255,7 +1262,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
} else { } else {
self.next_node_id() 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 } Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id }
}); });
let lifetime = self.lower_lifetime(&region); let lifetime = self.lower_lifetime(&region);
@ -1267,7 +1274,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
generic_params, generic_params,
unsafety: self.lower_unsafety(f.unsafety), unsafety: self.lower_unsafety(f.unsafety),
abi: self.lower_extern(f.ext), 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), param_names: self.lower_fn_params_to_names(&f.decl),
})) }))
} }
@ -1546,15 +1553,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let lifetimes = let lifetimes =
self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(|(_, lifetime)| { self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(|(_, lifetime)| {
let id = self.next_node_id(); let id = self.next_node_id();
let span = lifetime.ident.span; let l = self.new_named_lifetime(lifetime.id, id, lifetime.ident);
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);
hir::GenericArg::Lifetime(l) hir::GenericArg::Lifetime(l)
})); }));
debug!(?lifetimes); debug!(?lifetimes);
@ -1679,7 +1678,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_fn_decl( fn lower_fn_decl(
&mut self, &mut self,
decl: &FnDecl, decl: &FnDecl,
fn_node_id: Option<NodeId>, fn_node_id: NodeId,
fn_span: Span, fn_span: Span,
kind: FnDeclKind, kind: FnDeclKind,
make_ret_async: Option<(NodeId, Span)>, make_ret_async: Option<(NodeId, Span)>,
@ -1694,23 +1693,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
inputs = &inputs[..inputs.len() - 1]; inputs = &inputs[..inputs.len() - 1];
} }
let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| { let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| {
if fn_node_id.is_some() { let itctx = if kind.param_impl_trait_allowed() {
self.lower_ty_direct(&param.ty, &ImplTraitContext::Universal) ImplTraitContext::Universal
} else { } else {
self.lower_ty_direct( ImplTraitContext::Disallowed(match kind {
&param.ty, FnDeclKind::Fn | FnDeclKind::Inherent => {
&ImplTraitContext::Disallowed(match kind { unreachable!("fn should allow APIT")
FnDeclKind::Fn | FnDeclKind::Inherent => { }
unreachable!("fn should allow in-band lifetimes") FnDeclKind::ExternFn => ImplTraitPosition::ExternFnParam,
} FnDeclKind::Closure => ImplTraitPosition::ClosureParam,
FnDeclKind::ExternFn => ImplTraitPosition::ExternFnParam, FnDeclKind::Pointer => ImplTraitPosition::PointerParam,
FnDeclKind::Closure => ImplTraitPosition::ClosureParam, FnDeclKind::Trait => ImplTraitPosition::TraitParam,
FnDeclKind::Pointer => ImplTraitPosition::PointerParam, FnDeclKind::Impl => ImplTraitPosition::ImplParam,
FnDeclKind::Trait => ImplTraitPosition::TraitParam, })
FnDeclKind::Impl => ImplTraitPosition::ImplParam, };
}), self.lower_ty_direct(&param.ty, &itctx)
)
}
})); }));
let output = if let Some((ret_id, span)) = make_ret_async { 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( self.lower_async_fn_ret_ty(
&decl.output, &decl.output,
fn_node_id.expect("`make_ret_async` but no `fn_def_id`"), fn_node_id,
ret_id, ret_id,
matches!(kind, FnDeclKind::Trait), matches!(kind, FnDeclKind::Trait),
) )
} else { } else {
match &decl.output { match &decl.output {
FnRetTy::Ty(ty) => { FnRetTy::Ty(ty) => {
let mut context = match fn_node_id { let mut context = if kind.return_impl_trait_allowed(self.tcx) {
Some(fn_node_id) if kind.impl_trait_allowed(self.tcx) => { let fn_def_id = self.local_def_id(fn_node_id);
let fn_def_id = self.local_def_id(fn_node_id); ImplTraitContext::ReturnPositionOpaqueTy {
ImplTraitContext::ReturnPositionOpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), in_trait: matches!(kind, FnDeclKind::Trait),
in_trait: matches!(kind, FnDeclKind::Trait),
}
} }
_ => ImplTraitContext::Disallowed(match kind { } else {
ImplTraitContext::Disallowed(match kind {
FnDeclKind::Fn | FnDeclKind::Inherent => { FnDeclKind::Fn | FnDeclKind::Inherent => {
unreachable!("fn should allow in-band lifetimes") unreachable!("fn should allow in-band lifetimes")
} }
@ -1757,7 +1753,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
FnDeclKind::Pointer => ImplTraitPosition::PointerReturn, FnDeclKind::Pointer => ImplTraitPosition::PointerReturn,
FnDeclKind::Trait => ImplTraitPosition::TraitReturn, FnDeclKind::Trait => ImplTraitPosition::TraitReturn,
FnDeclKind::Impl => ImplTraitPosition::ImplReturn, FnDeclKind::Impl => ImplTraitPosition::ImplReturn,
}), })
}; };
hir::FnRetTy::Return(self.lower_ty(ty, &mut context)) hir::FnRetTy::Return(self.lower_ty(ty, &mut context))
} }
@ -1769,6 +1765,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
inputs, inputs,
output, output,
c_variadic, 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| { implicit_self: decl.inputs.get(0).map_or(hir::ImplicitSelfKind::None, |arg| {
let is_mutable_pat = matches!( let is_mutable_pat = matches!(
arg.pat.kind, 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( let generic_args = self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(
|(_, lifetime, res)| { |(_, lifetime, res)| {
let id = self.next_node_id(); 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( let res = res.unwrap_or(
self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error), 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 { 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); 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))] #[instrument(level = "debug", skip(self))]
fn new_named_lifetime_with_res( fn new_named_lifetime_with_res(
&mut self, &mut self,
id: NodeId, id: NodeId,
span: Span,
ident: Ident, ident: Ident,
res: LifetimeRes, res: LifetimeRes,
) -> &'hir hir::Lifetime { ) -> &'hir hir::Lifetime {
let name = match res { let res = match res {
LifetimeRes::Param { param, .. } => { LifetimeRes::Param { param, .. } => {
let p_name = ParamName::Plain(ident);
let param = self.get_remapped_def_id(param); let param = self.get_remapped_def_id(param);
hir::LifetimeName::Param(param)
hir::LifetimeName::Param(param, p_name)
} }
LifetimeRes::Fresh { param, .. } => { LifetimeRes::Fresh { param, .. } => {
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
let param = self.local_def_id(param); let param = self.local_def_id(param);
hir::LifetimeName::Param(param)
hir::LifetimeName::Param(param, ParamName::Fresh)
} }
LifetimeRes::Infer => hir::LifetimeName::Infer, LifetimeRes::Infer => hir::LifetimeName::Infer,
LifetimeRes::Static => hir::LifetimeName::Static, LifetimeRes::Static => hir::LifetimeName::Static,
LifetimeRes::Error => hir::LifetimeName::Error, 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 { self.arena.alloc(hir::Lifetime {
hir_id: self.lower_node_id(id), hir_id: self.lower_node_id(id),
span: self.lower_span(span), ident: self.lower_ident(ident),
name, res,
}) })
} }
@ -2136,11 +2122,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&mut self, &mut self,
id: NodeId, id: NodeId,
new_id: NodeId, new_id: NodeId,
span: Span,
ident: Ident, ident: Ident,
) -> &'hir hir::Lifetime { ) -> &'hir hir::Lifetime {
let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error); 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>( 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 { fn elided_dyn_bound(&mut self, span: Span) -> &'hir hir::Lifetime {
let r = hir::Lifetime { let r = hir::Lifetime {
hir_id: self.next_id(), hir_id: self.next_id(),
span: self.lower_span(span), ident: Ident::new(kw::Empty, self.lower_span(span)),
name: hir::LifetimeName::ImplicitObjectLifetimeDefault, res: hir::LifetimeName::ImplicitObjectLifetimeDefault,
}; };
debug!("elided_dyn_bound: r={:?}", r); debug!("elided_dyn_bound: r={:?}", r);
self.arena.alloc(r) self.arena.alloc(r)

View file

@ -309,7 +309,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let id = NodeId::from_u32(i); let id = NodeId::from_u32(i);
let l = self.lower_lifetime(&Lifetime { let l = self.lower_lifetime(&Lifetime {
id, id,
ident: Ident::new(kw::UnderscoreLifetime, elided_lifetime_span), ident: Ident::new(kw::Empty, elided_lifetime_span),
}); });
GenericArg::Lifetime(l) GenericArg::Lifetime(l)
}), }),

View file

@ -2670,7 +2670,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if let hir::TyKind::Rptr(lifetime, _) = &fn_decl.inputs[index].kind { if let hir::TyKind::Rptr(lifetime, _) = &fn_decl.inputs[index].kind {
// With access to the lifetime, we can get // With access to the lifetime, we can get
// the span of it. // the span of it.
arguments.push((*argument, lifetime.span)); arguments.push((*argument, lifetime.ident.span));
} else { } else {
bug!("ty type is a ref but hir type is not"); 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(); let mut return_span = fn_decl.output.span();
if let hir::FnRetTy::Return(ty) = &fn_decl.output { if let hir::FnRetTy::Return(ty) = &fn_decl.output {
if let hir::TyKind::Rptr(lifetime, _) = ty.kind { if let hir::TyKind::Rptr(lifetime, _) = ty.kind {
return_span = lifetime.span; return_span = lifetime.ident.span;
} }
} }

View file

@ -1211,7 +1211,7 @@ fn get_mut_span_in_struct_field<'tcx>(
&& let hir::Node::Field(field) = node && let hir::Node::Field(field) = node
&& let hir::TyKind::Rptr(lt, hir::MutTy { mutbl: hir::Mutability::Not, ty }) = field.ty.kind && 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 None

View file

@ -576,30 +576,10 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
let args = last_segment.args.as_ref()?; let args = last_segment.args.as_ref()?;
let lifetime = let lifetime =
self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?; self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?;
match lifetime.name { if lifetime.is_anonymous() {
hir::LifetimeName::Param(_, hir::ParamName::Plain(_) | hir::ParamName::Error) None
| hir::LifetimeName::Error } else {
| hir::LifetimeName::Static => { Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime.ident.span))
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
}
} }
} }

View file

@ -29,15 +29,16 @@ use std::fmt;
#[derive(Debug, Copy, Clone, Encodable, HashStable_Generic)] #[derive(Debug, Copy, Clone, Encodable, HashStable_Generic)]
pub struct Lifetime { pub struct Lifetime {
pub hir_id: HirId, pub hir_id: HirId,
pub span: Span,
/// Either "`'a`", referring to a named lifetime definition, /// 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 /// See `Lifetime::suggestion_position` for practical use.
/// refer to type definitions needing lifetime parameters, pub ident: Ident,
/// `&T` and `&mut T`, and trait objects without `... + 'a`.
pub name: LifetimeName, /// Semantics of this lifetime.
pub res: LifetimeName,
} }
#[derive(Debug, Clone, PartialEq, Eq, Encodable, Hash, Copy)] #[derive(Debug, Clone, PartialEq, Eq, Encodable, Hash, Copy)]
@ -88,7 +89,7 @@ impl ParamName {
#[derive(HashStable_Generic)] #[derive(HashStable_Generic)]
pub enum LifetimeName { pub enum LifetimeName {
/// User-given names or fresh (synthetic) names. /// User-given names or fresh (synthetic) names.
Param(LocalDefId, ParamName), Param(LocalDefId),
/// Implicit lifetime in a context like `dyn Foo`. This is /// Implicit lifetime in a context like `dyn Foo`. This is
/// distinguished from implicit lifetimes elsewhere because the /// distinguished from implicit lifetimes elsewhere because the
@ -116,25 +117,6 @@ pub enum LifetimeName {
} }
impl 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 { pub fn is_elided(&self) -> bool {
match self { match self {
LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Infer => true, LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Infer => true,
@ -146,34 +128,54 @@ impl LifetimeName {
LifetimeName::Error | LifetimeName::Param(..) | LifetimeName::Static => false, 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 { impl fmt::Display for Lifetime {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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 { impl Lifetime {
pub fn is_elided(&self) -> bool { 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 { pub fn is_static(&self) -> bool {
self.name.is_static() self.res == LifetimeName::Static
} }
} }
@ -267,7 +269,7 @@ pub enum GenericArg<'hir> {
impl GenericArg<'_> { impl GenericArg<'_> {
pub fn span(&self) -> Span { pub fn span(&self) -> Span {
match self { match self {
GenericArg::Lifetime(l) => l.span, GenericArg::Lifetime(l) => l.ident.span,
GenericArg::Type(t) => t.span, GenericArg::Type(t) => t.span,
GenericArg::Const(c) => c.span, GenericArg::Const(c) => c.span,
GenericArg::Infer(i) => i.span, GenericArg::Infer(i) => i.span,
@ -284,7 +286,7 @@ impl GenericArg<'_> {
} }
pub fn is_synthetic(&self) -> bool { 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 { pub fn descr(&self) -> &'static str {
@ -446,7 +448,7 @@ impl GenericBound<'_> {
match self { match self {
GenericBound::Trait(t, ..) => t.span, GenericBound::Trait(t, ..) => t.span,
GenericBound::LangItemTrait(_, span, ..) => *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. /// If there are generic parameters, return where to introduce a new one.
pub fn span_for_param_suggestion(&self) -> Option<Span> { pub fn span_for_param_suggestion(&self) -> Option<Span> {
if self.params.iter().any(|p| self.span.contains(p.span)) { if self.params.iter().any(|p| self.span.contains(p.span)) {
@ -765,10 +780,7 @@ pub struct WhereRegionPredicate<'hir> {
impl<'hir> WhereRegionPredicate<'hir> { impl<'hir> WhereRegionPredicate<'hir> {
/// Returns `true` if `param_def_id` matches the `lifetime` of this predicate. /// Returns `true` if `param_def_id` matches the `lifetime` of this predicate.
pub fn is_param_bound(&self, param_def_id: LocalDefId) -> bool { pub fn is_param_bound(&self, param_def_id: LocalDefId) -> bool {
match self.lifetime.name { self.lifetime.res == LifetimeName::Param(param_def_id)
LifetimeName::Param(id, _) => id == param_def_id,
_ => false,
}
} }
} }
@ -2688,6 +2700,8 @@ pub struct FnDecl<'hir> {
pub c_variadic: bool, pub c_variadic: bool,
/// Does the function have an implicit self? /// Does the function have an implicit self?
pub implicit_self: ImplicitSelfKind, pub implicit_self: ImplicitSelfKind,
/// Is lifetime elision allowed.
pub lifetime_elision_allowed: bool,
} }
/// Represents what type of implicit self a function has, if any. /// Represents what type of implicit self a function has, if any.
@ -3453,7 +3467,7 @@ impl<'hir> Node<'hir> {
| Node::Variant(Variant { ident, .. }) | Node::Variant(Variant { ident, .. })
| Node::Item(Item { ident, .. }) | Node::Item(Item { ident, .. })
| Node::PathSegment(PathSegment { ident, .. }) => Some(*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::GenericParam(p) => Some(p.name.ident()),
Node::TypeBinding(b) => Some(b.ident), Node::TypeBinding(b) => Some(b.ident),
Node::Param(..) Node::Param(..)

View file

@ -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) { pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
visitor.visit_id(lifetime.hir_id); visitor.visit_id(lifetime.hir_id);
match lifetime.name { visitor.visit_ident(lifetime.ident);
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 => {}
}
} }
pub fn walk_qpath<'v, V: Visitor<'v>>(visitor: &mut V, qpath: &'v QPath<'v>, id: HirId) { pub fn walk_qpath<'v, V: Visitor<'v>>(visitor: &mut V, qpath: &'v QPath<'v>, id: HirId) {

View file

@ -5,6 +5,7 @@
#![feature(associated_type_defaults)] #![feature(associated_type_defaults)]
#![feature(closure_track_caller)] #![feature(closure_track_caller)]
#![feature(const_btree_len)] #![feature(const_btree_len)]
#![feature(let_chains)]
#![feature(min_specialization)] #![feature(min_specialization)]
#![feature(never_type)] #![feature(never_type)]
#![feature(rustc_attrs)] #![feature(rustc_attrs)]

View file

@ -241,14 +241,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
} }
None => { 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"); debug!(?lifetime, "unelided lifetime in signature");
// This indicates an illegal lifetime // This indicates an illegal lifetime
// elision. `resolve_lifetime` should have // elision. `resolve_lifetime` should have
// reported an error in this case -- but if // reported an error in this case -- but if
// not, let's error out. // 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 // Supply some dummy value. We don't have an
// `re_error`, annoyingly, so use `'static`. // `re_error`, annoyingly, so use `'static`.
@ -961,9 +961,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
} }
hir::GenericBound::Outlives(lifetime) => { hir::GenericBound::Outlives(lifetime) => {
let region = self.ast_region_to_region(lifetime, None); let region = self.ast_region_to_region(lifetime, None);
bounds bounds.region_bounds.push((
.region_bounds ty::Binder::bind_with_vars(region, bound_vars),
.push((ty::Binder::bind_with_vars(region, bound_vars), lifetime.span)); lifetime.ident.span,
));
} }
} }
} }

View file

@ -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::Static | rl::Region::EarlyBound(..)) => {}
Some(rl::Region::LateBound(debruijn, _, _)) if debruijn < self.outer_index => {} Some(rl::Region::LateBound(debruijn, _, _)) if debruijn < self.outer_index => {}
Some(rl::Region::LateBound(..) | rl::Region::Free(..)) | None => { 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);
} }
} }
} }

View file

@ -595,7 +595,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
this.visit_poly_trait_ref(bound); this.visit_poly_trait_ref(bound);
} }
}); });
match lifetime.name { match lifetime.res {
LifetimeName::ImplicitObjectLifetimeDefault => { LifetimeName::ImplicitObjectLifetimeDefault => {
// If the user does not write *anything*, we // If the user does not write *anything*, we
// use the object lifetime defaulting // use the object lifetime defaulting
@ -686,7 +686,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
if !parent_id.is_owner() { if !parent_id.is_owner() {
struct_span_err!( struct_span_err!(
self.tcx.sess, self.tcx.sess,
lifetime.span, lifetime.ident.span,
E0657, E0657,
"`impl Trait` can only capture lifetimes bound at the fn or impl level" "`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) }) = self.tcx.hir().get(parent_id)
{ {
let mut err = self.tcx.sess.struct_span_err( 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", "higher kinded lifetime bounds on nested opaque types are not supported yet",
); );
err.span_note(self.tcx.def_span(def_id), "lifetime declared here"); 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))] #[instrument(level = "debug", skip(self))]
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { 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::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) self.resolve_lifetime_ref(param_def_id, lifetime_ref)
} }
// If we've already reported an error, just ignore `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); this.visit_lifetime(lifetime);
walk_list!(this, visit_param_bound, bounds); walk_list!(this, visit_param_bound, bounds);
if lifetime.name != hir::LifetimeName::Static { if lifetime.res != hir::LifetimeName::Static {
for bound in bounds { for bound in bounds {
let hir::GenericBound::Outlives(ref lt) = bound else { let hir::GenericBound::Outlives(ref lt) = bound else {
continue; continue;
}; };
if lt.name != hir::LifetimeName::Static { if lt.res != hir::LifetimeName::Static {
continue; continue;
} }
this.insert_lifetime(lt, Region::Static); this.insert_lifetime(lt, Region::Static);
this.tcx this.tcx
.sess .sess
.struct_span_warn( .struct_span_warn(
lifetime.span, lifetime.ident.span,
&format!( &format!(
"unnecessary lifetime parameter `{}`", "unnecessary lifetime parameter `{}`",
lifetime.name.ident(), lifetime.ident,
), ),
) )
.help(&format!( .help(&format!(
"you can use the `'static` lifetime directly, in place of `{}`", "you can use the `'static` lifetime directly, in place of `{}`",
lifetime.name.ident(), lifetime.ident,
)) ))
.emit(); .emit();
} }
@ -1043,7 +1043,7 @@ fn object_lifetime_default<'tcx>(tcx: TyCtxt<'tcx>, param_def_id: DefId) -> Obje
for bound in bound.bounds { for bound in bound.bounds {
if let hir::GenericBound::Outlives(ref lifetime) = *bound { 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 { match set {
Set1::Empty => ObjectLifetimeDefault::Empty, Set1::Empty => ObjectLifetimeDefault::Empty,
Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static, 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::Param(param_def_id.to_def_id())
} }
_ => ObjectLifetimeDefault::Ambiguous, _ => 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 // Fresh lifetimes in APIT used to be allowed in async fns and forbidden in
// regular fns. // regular fns.
if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin 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) && let hir::IsAsync::NotAsync = self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id)
&& !self.tcx.features().anonymous_lifetime_in_impl_trait && !self.tcx.features().anonymous_lifetime_in_impl_trait
{ {
let mut diag = rustc_session::parse::feature_err( let mut diag = rustc_session::parse::feature_err(
&self.tcx.sess.parse_sess, &self.tcx.sess.parse_sess,
sym::anonymous_lifetime_in_impl_trait, sym::anonymous_lifetime_in_impl_trait,
lifetime_ref.span, lifetime_ref.ident.span,
"anonymous lifetimes in `impl Trait` are unstable", "anonymous lifetimes in `impl Trait` are unstable",
); );
match self.tcx.hir().get_generics(lifetime_ref.hir_id.owner.def_id) { if let Some(generics) =
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() { diag.span_label(
Some(_) => { lifetime_ref.ident.span,
Some((self.tcx.sess.source_map().span_through_char(generics.span, '<').shrink_to_hi(), "'a, ".to_owned())) "expected named lifetime parameter",
}, );
None => Some((generics.span, "<'a>".to_owned())) diag.multipart_suggestion(
}; "consider introducing a named lifetime parameter",
suggestions,
let mut multi_sugg_vec = vec![(lifetime_ref.span.shrink_to_hi(), "'a ".to_owned())]; rustc_errors::Applicability::MaybeIncorrect,
);
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.emit(); diag.emit();
@ -1287,7 +1295,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
where_bound_origin: Some(hir::PredicateOrigin::ImplTrait), .. where_bound_origin: Some(hir::PredicateOrigin::ImplTrait), ..
} => { } => {
let mut err = self.tcx.sess.struct_span_err( 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", "`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"); 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( self.tcx.sess.delay_span_bug(
lifetime_ref.span, lifetime_ref.ident.span,
&format!("Could not resolve {:?} in scope {:#?}", lifetime_ref, self.scope,), &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))] #[instrument(level = "debug", skip(self))]
fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) { fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) {
debug!( debug!(span = ?lifetime_ref.ident.span);
node = ?self.tcx.hir().node_to_string(lifetime_ref.hir_id),
span = ?self.tcx.sess.source_map().span_to_diagnostic_string(lifetime_ref.span)
);
self.map.defs.insert(lifetime_ref.hir_id, def); 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) { 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); 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 { impl<'v> Visitor<'v> for AllCollector {
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { 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); self.regions.insert(def_id);
} }
} }

View file

@ -229,7 +229,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
predicates.extend(region_pred.bounds.iter().map(|bound| { predicates.extend(region_pred.bounds.iter().map(|bound| {
let (r2, span) = match bound { let (r2, span) = match bound {
hir::GenericBound::Outlives(lt) => { 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!(), _ => bug!(),
}; };

View file

@ -296,25 +296,35 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
) -> String { ) -> String {
debug!(?path_hir_id); 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 ret = Vec::new();
let mut ty_id = None;
for (id, node) in self.tcx.hir().parent_iter(path_hir_id) { for (id, node) in self.tcx.hir().parent_iter(path_hir_id) {
debug!(?id); debug!(?id);
let params = if let Some(generics) = node.generics() { if let hir::Node::Ty(_) = node {
generics.params ty_id = Some(id);
} else if let hir::Node::Ty(ty) = node }
&& let hir::TyKind::BareFn(bare_fn) = ty.kind
{ // Suggest `'_` when in function parameter or elided function return.
bare_fn.generic_params if let Some(fn_decl) = node.fn_decl() && let Some(ty_id) = ty_id {
} else { 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);
};
ret.extend(params.iter().filter_map(|p| { if in_arg || (in_ret && fn_decl.lifetime_elision_allowed) {
let hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit } return std::iter::repeat("'_".to_owned()).take(num_params_to_take).collect::<Vec<_>>().join(", ");
= p.kind }
else { return None }; }
let hir::ParamName::Plain(name) = p.name else { return None };
Some(name.to_string())
}));
// Suggest `'static` when in const/static item-like. // Suggest `'static` when in const/static item-like.
if let hir::Node::Item(hir::Item { if let hir::Node::Item(hir::Item {
kind: hir::ItemKind::Static { .. } | hir::ItemKind::Const { .. }, kind: hir::ItemKind::Static { .. } | hir::ItemKind::Const { .. },
@ -334,11 +344,29 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
}) })
| hir::Node::AnonConst(..) = node | hir::Node::AnonConst(..) = node
{ {
ret.extend( return std::iter::repeat("'static".to_owned())
std::iter::repeat("'static".to_owned()) .take(num_params_to_take.saturating_sub(ret.len()))
.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 { if ret.len() >= num_params_to_take {
return ret[..num_params_to_take].join(", "); return ret[..num_params_to_take].join(", ");
} }

View file

@ -2159,7 +2159,7 @@ impl<'a> State<'a> {
} }
pub fn print_lifetime(&mut self, lifetime: &hir::Lifetime) { 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<'_>) { pub fn print_where_clause(&mut self, generics: &hir::Generics<'_>) {

View file

@ -375,7 +375,7 @@ impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> {
return false; return false;
}; };
if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() { if !lifetime_sub.is_anonymous() || !lifetime_sup.is_anonymous() {
return false; return false;
}; };
@ -407,20 +407,20 @@ impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> {
let suggestion_param_name = let suggestion_param_name =
suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned()); suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
debug!(?lifetime_sup.span); debug!(?lifetime_sup.ident.span);
debug!(?lifetime_sub.span); debug!(?lifetime_sub.ident.span);
let make_suggestion = |span: rustc_span::Span| { let make_suggestion = |ident: Ident| {
if span.is_empty() { let sugg = if ident.name == kw::Empty {
(span, format!("{}, ", suggestion_param_name)) format!("{}, ", suggestion_param_name)
} else if let Ok("&") = self.tcx.sess.source_map().span_to_snippet(span).as_deref() } else if ident.name == kw::UnderscoreLifetime && ident.span.is_empty() {
{ format!("{} ", suggestion_param_name)
(span.shrink_to_hi(), format!("{} ", suggestion_param_name))
} else { } else {
(span, suggestion_param_name.clone()) suggestion_param_name.clone()
} };
(ident.span, sugg)
}; };
let mut suggestions = 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 { if introduce_new {
let new_param_suggestion = if let Some(first) = let new_param_suggestion = if let Some(first) =

View file

@ -314,10 +314,10 @@ pub fn suggest_new_region_bound(
.iter() .iter()
.filter_map(|arg| match arg { .filter_map(|arg| match arg {
GenericBound::Outlives(Lifetime { GenericBound::Outlives(Lifetime {
name: LifetimeName::Static, res: LifetimeName::Static,
span, ident,
.. ..
}) => Some(*span), }) => Some(ident.span),
_ => None, _ => None,
}) })
.next() .next()
@ -342,10 +342,10 @@ pub fn suggest_new_region_bound(
.bounds .bounds
.iter() .iter()
.filter_map(|arg| match arg { .filter_map(|arg| match arg {
GenericBound::Outlives(Lifetime { name, span, .. }) GenericBound::Outlives(Lifetime { ident, .. })
if name.ident().to_string() == lifetime_name => if ident.name.to_string() == lifetime_name =>
{ {
Some(*span) Some(ident.span)
} }
_ => None, _ => None,
}) })
@ -361,8 +361,8 @@ pub fn suggest_new_region_bound(
); );
} }
} }
TyKind::TraitObject(_, lt, _) => match lt.name { TyKind::TraitObject(_, lt, _) => {
LifetimeName::ImplicitObjectLifetimeDefault => { if let LifetimeName::ImplicitObjectLifetimeDefault = lt.res {
err.span_suggestion_verbose( err.span_suggestion_verbose(
fn_return.span.shrink_to_hi(), fn_return.span.shrink_to_hi(),
&format!( &format!(
@ -374,15 +374,14 @@ pub fn suggest_new_region_bound(
&plus_lt, &plus_lt,
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
} } else if lt.ident.name.to_string() != lifetime_name {
name if name.ident().to_string() != lifetime_name => {
// With this check we avoid suggesting redundant bounds. This // With this check we avoid suggesting redundant bounds. This
// would happen if there are nested impl/dyn traits and only // would happen if there are nested impl/dyn traits and only
// one of them has the bound we'd suggest already there, like // one of them has the bound we'd suggest already there, like
// in `impl Foo<X = dyn Bar> + '_`. // in `impl Foo<X = dyn Bar> + '_`.
if let Some(explicit_static) = &explicit_static { if let Some(explicit_static) = &explicit_static {
err.span_suggestion_verbose( err.span_suggestion_verbose(
lt.span, lt.ident.span,
&format!("{} the trait object's {}", consider, explicit_static), &format!("{} the trait object's {}", consider, explicit_static),
&lifetime_name, &lifetime_name,
Applicability::MaybeIncorrect, 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>) { fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
if let TyKind::TraitObject( if let TyKind::TraitObject(
poly_trait_refs, poly_trait_refs,
Lifetime { name: LifetimeName::ImplicitObjectLifetimeDefault, .. }, Lifetime { res: LifetimeName::ImplicitObjectLifetimeDefault, .. },
_, _,
) = t.kind ) = t.kind
{ {

View file

@ -272,11 +272,7 @@ fn gen_args(segment: &PathSegment<'_>) -> String {
.args .args
.iter() .iter()
.filter_map(|arg| { .filter_map(|arg| {
if let GenericArg::Lifetime(lt) = arg { if let GenericArg::Lifetime(lt) = arg { Some(lt.ident.to_string()) } else { None }
Some(lt.name.ident().to_string())
} else {
None
}
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();

View file

@ -78,7 +78,7 @@ fn gen_args(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> String {
.args .args
.iter() .iter()
.map(|arg| match arg { .map(|arg| match arg {
GenericArg::Lifetime(lt) => lt.name.ident().to_string(), GenericArg::Lifetime(lt) => lt.to_string(),
GenericArg::Type(ty) => { GenericArg::Type(ty) => {
cx.tcx.sess.source_map().span_to_snippet(ty.span).unwrap_or_else(|_| "_".into()) cx.tcx.sess.source_map().span_to_snippet(ty.span).unwrap_or_else(|_| "_".into())
} }

View file

@ -1058,7 +1058,7 @@ impl<'hir> Map<'hir> {
Node::Arm(arm) => arm.span, Node::Arm(arm) => arm.span,
Node::Block(block) => block.span, Node::Block(block) => block.span,
Node::Ctor(..) => self.span_with_body(self.get_parent_node(hir_id)), 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::GenericParam(param) => param.span,
Node::Infer(i) => i.span, Node::Infer(i) => i.span,
Node::Local(local) => local.span, Node::Local(local) => local.span,

View file

@ -397,7 +397,7 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
hir::TyKind::TraitObject( hir::TyKind::TraitObject(
_, _,
hir::Lifetime { hir::Lifetime {
name: res:
hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static, 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> { impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> {
fn visit_lifetime(&mut self, lt: &'v hir::Lifetime) { fn visit_lifetime(&mut self, lt: &'v hir::Lifetime) {
if let hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static = if let hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static = lt.res
lt.name
{ {
self.0.push(lt.span); self.0.push(lt.ident.span);
} }
} }
} }

View file

@ -3,7 +3,7 @@ use crate::ty::{EarlyBinder, SubstsRef};
use rustc_ast as ast; use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_span::symbol::Symbol; use rustc_span::symbol::{kw, Symbol};
use rustc_span::Span; use rustc_span::Span;
use super::{EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, Predicate, TyCtxt}; 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>( pub fn default_value<'tcx>(
&self, &self,
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,

View file

@ -208,6 +208,8 @@ pub struct ResolverAstLowering {
/// A small map keeping true kinds of built-in macros that appear to be fn-like on /// 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. /// the surface (`macro` items in libcore), but are actually attributes or derives.
pub builtin_macro_kinds: FxHashMap<LocalDefId, MacroKind>, 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)] #[derive(Clone, Copy, Debug)]
@ -529,7 +531,7 @@ impl ty::EarlyBoundRegion {
/// Does this early bound region have a name? Early bound regions normally /// Does this early bound region have a name? Early bound regions normally
/// always have names except when using anonymous lifetimes (`'_`). /// always have names except when using anonymous lifetimes (`'_`).
pub fn has_name(&self) -> bool { pub fn has_name(&self) -> bool {
self.name != kw::UnderscoreLifetime self.name != kw::UnderscoreLifetime && self.name != kw::Empty
} }
} }

View file

@ -1977,17 +1977,13 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
let identify_regions = self.tcx.sess.opts.unstable_opts.identify_regions; let identify_regions = self.tcx.sess.opts.unstable_opts.identify_regions;
match *region { match *region {
ty::ReEarlyBound(ref data) => { ty::ReEarlyBound(ref data) => data.has_name(),
data.name != kw::Empty && data.name != kw::UnderscoreLifetime
}
ty::ReLateBound(_, ty::BoundRegion { kind: br, .. }) ty::ReLateBound(_, ty::BoundRegion { kind: br, .. })
| ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | ty::ReFree(ty::FreeRegion { bound_region: br, .. })
| ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
if let ty::BrNamed(_, name) = br { if br.is_named() {
if name != kw::Empty && name != kw::UnderscoreLifetime { return true;
return true;
}
} }
if let Some((region, _)) = highlight.highlight_bound_region { if let Some((region, _)) = highlight.highlight_bound_region {
@ -2063,11 +2059,9 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
ty::ReLateBound(_, ty::BoundRegion { kind: br, .. }) ty::ReLateBound(_, ty::BoundRegion { kind: br, .. })
| ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | ty::ReFree(ty::FreeRegion { bound_region: br, .. })
| ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
if let ty::BrNamed(_, name) = br { if let ty::BrNamed(_, name) = br && br.is_named() {
if name != kw::Empty && name != kw::UnderscoreLifetime { p!(write("{}", name));
p!(write("{}", name)); return Ok(self);
return Ok(self);
}
} }
if let Some((region, counter)) = highlight.highlight_bound_region { 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)) (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); let name = next_name(&self);
if let Some(lt_idx) = lifetime_idx { if let Some(lt_idx) = lifetime_idx {

View file

@ -83,7 +83,9 @@ pub struct BoundRegion {
impl BoundRegionKind { impl BoundRegionKind {
pub fn is_named(&self) -> bool { pub fn is_named(&self) -> bool {
match *self { match *self {
BoundRegionKind::BrNamed(_, name) => name != kw::UnderscoreLifetime, BoundRegionKind::BrNamed(_, name) => {
name != kw::UnderscoreLifetime && name != kw::Empty
}
_ => false, _ => false,
} }
} }

View file

@ -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 outer_failures = take(&mut self.diagnostic_metadata.current_elision_failures);
let output_rib = if let Ok(res) = elision_lifetime.as_ref() { let output_rib = if let Ok(res) = elision_lifetime.as_ref() {
self.r.lifetime_elision_allowed.insert(fn_id);
LifetimeRibKind::Elided(*res) LifetimeRibKind::Elided(*res)
} else { } else {
LifetimeRibKind::ElisionFailure LifetimeRibKind::ElisionFailure

View file

@ -1036,6 +1036,8 @@ pub struct Resolver<'a> {
/// they are declared in the static array generated by proc_macro_harness. /// they are declared in the static array generated by proc_macro_harness.
proc_macros: Vec<NodeId>, proc_macros: Vec<NodeId>,
confused_type_with_std_module: FxHashMap<Span, Span>, confused_type_with_std_module: FxHashMap<Span, Span>,
/// Whether lifetime elision was successful.
lifetime_elision_allowed: FxHashSet<NodeId>,
effective_visibilities: EffectiveVisibilities, effective_visibilities: EffectiveVisibilities,
} }
@ -1354,6 +1356,7 @@ impl<'a> Resolver<'a> {
trait_impls: Default::default(), trait_impls: Default::default(),
proc_macros: Default::default(), proc_macros: Default::default(),
confused_type_with_std_module: Default::default(), confused_type_with_std_module: Default::default(),
lifetime_elision_allowed: Default::default(),
effective_visibilities: 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, def_id_to_node_id: self.def_id_to_node_id,
trait_map: self.trait_map, trait_map: self.trait_map,
builtin_macro_kinds: self.builtin_macro_kinds, builtin_macro_kinds: self.builtin_macro_kinds,
lifetime_elision_allowed: self.lifetime_elision_allowed,
}; };
ResolverOutputs { definitions, global_ctxt, ast_lowering } 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(), def_id_to_node_id: self.def_id_to_node_id.clone(),
trait_map: self.trait_map.clone(), trait_map: self.trait_map.clone(),
builtin_macro_kinds: self.builtin_macro_kinds.clone(), builtin_macro_kinds: self.builtin_macro_kinds.clone(),
lifetime_elision_allowed: self.lifetime_elision_allowed.clone(),
}; };
ResolverOutputs { definitions, global_ctxt, ast_lowering } ResolverOutputs { definitions, global_ctxt, ast_lowering }
} }

View file

@ -167,7 +167,7 @@ impl<'hir> Sig for hir::Ty<'hir> {
} }
hir::TyKind::Rptr(ref lifetime, ref mt) => { hir::TyKind::Rptr(ref lifetime, ref mt) => {
let mut prefix = "&".to_owned(); let mut prefix = "&".to_owned();
prefix.push_str(&lifetime.name.ident().to_string()); prefix.push_str(&lifetime.ident.to_string());
prefix.push(' '); prefix.push(' ');
if mt.mutbl.is_mut() { if mt.mutbl.is_mut() {
prefix.push_str("mut "); prefix.push_str("mut ");

View file

@ -182,9 +182,7 @@ fn clean_poly_trait_ref_with_bindings<'tcx>(
.collect_referenced_late_bound_regions(&poly_trait_ref) .collect_referenced_late_bound_regions(&poly_trait_ref)
.into_iter() .into_iter()
.filter_map(|br| match br { .filter_map(|br| match br {
ty::BrNamed(_, name) if name != kw::UnderscoreLifetime => { ty::BrNamed(_, name) if br.is_named() => Some(GenericParamDef::lifetime(name)),
Some(GenericParamDef::lifetime(name))
}
_ => None, _ => None,
}) })
.collect(); .collect();
@ -208,7 +206,7 @@ fn clean_lifetime<'tcx>(lifetime: &hir::Lifetime, cx: &mut DocContext<'tcx>) ->
return lt; return lt;
} }
} }
Lifetime(lifetime.name.ident().name) Lifetime(lifetime.ident.name)
} }
pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg, cx: &mut DocContext<'tcx>) -> Constant { pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg, cx: &mut DocContext<'tcx>) -> Constant {
@ -233,16 +231,11 @@ pub(crate) fn clean_middle_const<'tcx>(
pub(crate) fn clean_middle_region<'tcx>(region: ty::Region<'tcx>) -> Option<Lifetime> { pub(crate) fn clean_middle_region<'tcx>(region: ty::Region<'tcx>) -> Option<Lifetime> {
match *region { match *region {
ty::ReStatic => Some(Lifetime::statik()), ty::ReStatic => Some(Lifetime::statik()),
_ if !region.has_name() => None,
ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) => { ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) => {
if name != kw::UnderscoreLifetime { Some(Lifetime(name)) } else { None } Some(Lifetime(name))
}
ty::ReEarlyBound(ref data) => {
if data.name != kw::UnderscoreLifetime {
Some(Lifetime(data.name))
} else {
None
}
} }
ty::ReEarlyBound(ref data) => Some(Lifetime(data.name)),
ty::ReLateBound(..) ty::ReLateBound(..)
| ty::ReFree(..) | ty::ReFree(..)
| ty::ReVar(..) | ty::ReVar(..)
@ -400,7 +393,7 @@ fn clean_projection_predicate<'tcx>(
.collect_referenced_late_bound_regions(&pred) .collect_referenced_late_bound_regions(&pred)
.into_iter() .into_iter()
.filter_map(|br| match br { .filter_map(|br| match br {
ty::BrNamed(_, name) if name != kw::UnderscoreLifetime => Some(Lifetime(name)), ty::BrNamed(_, name) if br.is_named() => Some(Lifetime(name)),
_ => None, _ => None,
}) })
.collect(); .collect();
@ -664,7 +657,7 @@ fn clean_ty_generics<'tcx>(
.params .params
.iter() .iter()
.filter_map(|param| match param.kind { .filter_map(|param| match param.kind {
ty::GenericParamDefKind::Lifetime if param.name == kw::UnderscoreLifetime => None, ty::GenericParamDefKind::Lifetime if param.is_anonymous_lifetime() => None,
ty::GenericParamDefKind::Lifetime => Some(clean_generic_param_def(param, cx)), ty::GenericParamDefKind::Lifetime => Some(clean_generic_param_def(param, cx)),
ty::GenericParamDefKind::Type { synthetic, .. } => { ty::GenericParamDefKind::Type { synthetic, .. } => {
if param.name == kw::SelfUpper { if param.name == kw::SelfUpper {
@ -1467,8 +1460,11 @@ fn maybe_expand_private_type_alias<'tcx>(
}); });
if let Some(lt) = lifetime { if let Some(lt) = lifetime {
let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id); let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
let cleaned = let cleaned = if !lt.is_anonymous() {
if !lt.is_elided() { clean_lifetime(lt, cx) } else { Lifetime::elided() }; clean_lifetime(lt, cx)
} else {
Lifetime::elided()
};
substs.insert(lt_def_id.to_def_id(), SubstParam::Lifetime(cleaned)); substs.insert(lt_def_id.to_def_id(), SubstParam::Lifetime(cleaned));
} }
indices.lifetimes += 1; indices.lifetimes += 1;
@ -1531,16 +1527,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
TyKind::Never => Primitive(PrimitiveType::Never), TyKind::Never => Primitive(PrimitiveType::Never),
TyKind::Ptr(ref m) => RawPointer(m.mutbl, Box::new(clean_ty(m.ty, cx))), TyKind::Ptr(ref m) => RawPointer(m.mutbl, Box::new(clean_ty(m.ty, cx))),
TyKind::Rptr(ref l, ref m) => { TyKind::Rptr(ref l, ref m) => {
// There are two times a `Fresh` lifetime can be created: let lifetime = if l.is_anonymous() { None } else { Some(clean_lifetime(*l, cx)) };
// 1. For `&'_ x`, written by the user. This corresponds to `lower_lifetime` in `rustc_ast_lowering`.
// 2. For `&x` as a parameter to an `async fn`. This corresponds to `elided_ref_lifetime in `rustc_ast_lowering`.
// See #59286 for more information.
// Ideally we would only hide the `'_` for case 2., but I don't know a way to distinguish it.
// Turning `fn f(&'_ self)` into `fn f(&self)` isn't the worst thing in the world, though;
// there's no case where it could cause the function to fail to compile.
let elided =
l.is_elided() || matches!(l.name, LifetimeName::Param(_, ParamName::Fresh));
let lifetime = if elided { None } else { Some(clean_lifetime(*l, cx)) };
BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(clean_ty(m.ty, cx)) } BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(clean_ty(m.ty, cx)) }
} }
TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))), TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))),
@ -1915,7 +1902,7 @@ fn clean_generic_args<'tcx>(
.args .args
.iter() .iter()
.map(|arg| match arg { .map(|arg| match arg {
hir::GenericArg::Lifetime(lt) if !lt.is_elided() => { hir::GenericArg::Lifetime(lt) if !lt.is_anonymous() => {
GenericArg::Lifetime(clean_lifetime(*lt, cx)) GenericArg::Lifetime(clean_lifetime(*lt, cx))
} }
hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()), hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),

View file

@ -11,7 +11,7 @@ LL | type Y<'a>;
| ^ -- | ^ --
help: add missing lifetime argument help: add missing lifetime argument
| |
LL | fn f2<'a>(arg: Box<dyn X<Y<'a, 1> = &'a ()>>) {} LL | fn f2<'a>(arg: Box<dyn X<Y<'_, 1> = &'a ()>>) {}
| +++ | +++
error[E0107]: this associated type takes 0 generic arguments but 1 generic argument was supplied error[E0107]: this associated type takes 0 generic arguments but 1 generic argument was supplied

View file

@ -13,8 +13,8 @@ LL | struct S<'a, 'b>(&'a u8, &'b u8);
| ^ -- -- | ^ -- --
help: add missing lifetime argument help: add missing lifetime argument
| |
LL | S::<'static, 'b>(&0, &0); LL | S::<'static, 'static>(&0, &0);
| ++++ | +++++++++
error[E0107]: this struct takes 2 lifetime arguments but 3 lifetime arguments were supplied error[E0107]: this struct takes 2 lifetime arguments but 3 lifetime arguments were supplied
--> $DIR/constructor-lifetime-args.rs:19:5 --> $DIR/constructor-lifetime-args.rs:19:5
@ -45,8 +45,8 @@ LL | enum E<'a, 'b> {
| ^ -- -- | ^ -- --
help: add missing lifetime argument help: add missing lifetime argument
| |
LL | E::V::<'static, 'b>(&0); LL | E::V::<'static, 'static>(&0);
| ++++ | +++++++++
error[E0107]: this enum takes 2 lifetime arguments but 3 lifetime arguments were supplied error[E0107]: this enum takes 2 lifetime arguments but 3 lifetime arguments were supplied
--> $DIR/constructor-lifetime-args.rs:24:8 --> $DIR/constructor-lifetime-args.rs:24:8

View file

@ -11,7 +11,7 @@ LL | type Assoc<'a> where Self: 'a;
| ^^^^^ -- | ^^^^^ --
help: add missing lifetime argument help: add missing lifetime argument
| |
LL | fn g(&self) -> Self::Assoc<'a>; LL | fn g(&self) -> Self::Assoc<'_>;
| ~~~~~~~~~ | ~~~~~~~~~
error[E0107]: missing generics for associated type `Trait::Assoc` error[E0107]: missing generics for associated type `Trait::Assoc`
@ -27,7 +27,7 @@ LL | type Assoc<'a> where Self: 'a;
| ^^^^^ -- | ^^^^^ --
help: add missing lifetime argument help: add missing lifetime argument
| |
LL | fn g(&self) -> Self::Assoc<'a> { LL | fn g(&self) -> Self::Assoc<'_> {
| ~~~~~~~~~ | ~~~~~~~~~
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View file

@ -36,7 +36,7 @@ LL | type Y<'a>;
| ^ -- | ^ --
help: add missing lifetime argument help: add missing lifetime argument
| |
LL | fn foo<'a>(arg: Box<dyn X<Y('a, 'a) = &'a ()>>) {} LL | fn foo<'a>(arg: Box<dyn X<Y('_, 'a) = &'a ()>>) {}
| +++ | +++
error[E0107]: this associated type takes 0 generic arguments but 1 generic argument was supplied error[E0107]: this associated type takes 0 generic arguments but 1 generic argument was supplied
@ -66,7 +66,7 @@ LL | type Y<'a>;
| ^ -- | ^ --
help: add missing lifetime argument help: add missing lifetime argument
| |
LL | fn bar<'a>(arg: Box<dyn X<Y('a) = ()>>) {} LL | fn bar<'a>(arg: Box<dyn X<Y('_) = ()>>) {}
| ++ | ++
error: aborting due to 6 previous errors error: aborting due to 6 previous errors

View file

@ -11,7 +11,7 @@ LL | type Item<'a>;
| ^^^^ -- | ^^^^ --
help: add missing lifetime argument help: add missing lifetime argument
| |
LL | fn next(&mut self) -> Option<Self::Item<'a>>; LL | fn next(&mut self) -> Option<Self::Item<'_>>;
| ~~~~~~~~ | ~~~~~~~~
error: aborting due to previous error error: aborting due to previous error

View file

@ -11,7 +11,7 @@ LL | type Y<'a, 'b>;
| ^ -- -- | ^ -- --
help: add missing lifetime arguments help: add missing lifetime arguments
| |
LL | fn foo<'c, 'd>(_arg: Box<dyn X<Y<'c, 'd> = (&'c u32, &'d u32)>>) {} LL | fn foo<'c, 'd>(_arg: Box<dyn X<Y<'_, '_> = (&'c u32, &'d u32)>>) {}
| ~~~~~~~~~ | ~~~~~~~~~
error[E0107]: this struct takes 3 lifetime arguments but 2 lifetime arguments were supplied error[E0107]: this struct takes 3 lifetime arguments but 2 lifetime arguments were supplied
@ -47,7 +47,7 @@ LL | struct Foo<'a, 'b, 'c> {
| ^^^ -- -- -- | ^^^ -- -- --
help: add missing lifetime arguments help: add missing lifetime arguments
| |
LL | fn f<'a>(_arg: Foo<'a, 'b, 'c>) {} LL | fn f<'a>(_arg: Foo<'a, 'a, 'a>) {}
| ++++++++ | ++++++++
error: aborting due to 3 previous errors error: aborting due to 3 previous errors

View file

@ -11,7 +11,7 @@ LL | type Y<'a>;
| ^ -- | ^ --
help: add missing lifetime argument help: add missing lifetime argument
| |
LL | fn f2<'a>(arg : Box<dyn X<Y<'a, 1> = &'a ()>>) {} LL | fn f2<'a>(arg : Box<dyn X<Y<'_, 1> = &'a ()>>) {}
| +++ | +++
error[E0107]: this associated type takes 0 generic arguments but 1 generic argument was supplied error[E0107]: this associated type takes 0 generic arguments but 1 generic argument was supplied

View file

@ -812,8 +812,8 @@ LL | trait GenericLifetimeLifetimeAT<'a, 'b> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ -- -- | ^^^^^^^^^^^^^^^^^^^^^^^^^ -- --
help: add missing lifetime argument help: add missing lifetime argument
| |
LL | type B = Box<dyn GenericLifetimeLifetimeAT<'static, 'b, AssocTy=()>>; LL | type B = Box<dyn GenericLifetimeLifetimeAT<'static, 'static, AssocTy=()>>;
| ++++ | +++++++++
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
--> $DIR/wrong-number-of-args.rs:287:26 --> $DIR/wrong-number-of-args.rs:287:26
@ -846,8 +846,8 @@ LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- -- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- --
help: add missing lifetime argument help: add missing lifetime argument
| |
LL | type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, 'b, AssocTy=()>>; LL | type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, 'static, AssocTy=()>>;
| ++++ | +++++++++
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
--> $DIR/wrong-number-of-args.rs:294:26 --> $DIR/wrong-number-of-args.rs:294:26
@ -880,8 +880,8 @@ LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- -- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- --
help: add missing lifetime argument help: add missing lifetime argument
| |
LL | type C = Box<dyn GenericLifetimeLifetimeTypeAT<'static, 'b, (), AssocTy=()>>; LL | type C = Box<dyn GenericLifetimeLifetimeTypeAT<'static, 'static, (), AssocTy=()>>;
| ++++ | +++++++++
error[E0107]: missing generics for struct `HashMap` error[E0107]: missing generics for struct `HashMap`
--> $DIR/wrong-number-of-args.rs:310:18 --> $DIR/wrong-number-of-args.rs:310:18

View file

@ -13,8 +13,8 @@ LL | fn early<'a, 'b>(self) -> (&'a u8, &'b u8) { loop {} }
| ^^^^^ -- -- | ^^^^^ -- --
help: add missing lifetime argument help: add missing lifetime argument
| |
LL | S.early::<'static, 'b>(); LL | S.early::<'static, 'static>();
| ++++ | +++++++++
error[E0107]: this associated function takes 2 lifetime arguments but 3 lifetime arguments were supplied error[E0107]: this associated function takes 2 lifetime arguments but 3 lifetime arguments were supplied
--> $DIR/method-call-lifetime-args-fail.rs:18:7 --> $DIR/method-call-lifetime-args-fail.rs:18:7
@ -213,8 +213,8 @@ LL | fn early<'a, 'b>(self) -> (&'a u8, &'b u8) { loop {} }
| ^^^^^ -- -- | ^^^^^ -- --
help: add missing lifetime argument help: add missing lifetime argument
| |
LL | S::early::<'static, 'b>(S); LL | S::early::<'static, 'static>(S);
| ++++ | +++++++++
error[E0107]: this associated function takes 2 lifetime arguments but 3 lifetime arguments were supplied error[E0107]: this associated function takes 2 lifetime arguments but 3 lifetime arguments were supplied
--> $DIR/method-call-lifetime-args-fail.rs:65:8 --> $DIR/method-call-lifetime-args-fail.rs:65:8

View file

@ -119,7 +119,7 @@ hir-stats HIR STATS
hir-stats Name Accumulated Size Count Item Size hir-stats Name Accumulated Size Count Item Size
hir-stats ---------------------------------------------------------------- hir-stats ----------------------------------------------------------------
hir-stats ForeignItemRef 24 ( 0.3%) 1 24 hir-stats ForeignItemRef 24 ( 0.3%) 1 24
hir-stats Lifetime 32 ( 0.3%) 1 32 hir-stats Lifetime 24 ( 0.3%) 1 24
hir-stats Mod 32 ( 0.3%) 1 32 hir-stats Mod 32 ( 0.3%) 1 32
hir-stats ExprField 40 ( 0.4%) 1 40 hir-stats ExprField 40 ( 0.4%) 1 40
hir-stats TraitItemRef 56 ( 0.6%) 2 28 hir-stats TraitItemRef 56 ( 0.6%) 2 28
@ -152,7 +152,7 @@ hir-stats - Struct 72 ( 0.8%) 1
hir-stats - Binding 216 ( 2.4%) 3 hir-stats - Binding 216 ( 2.4%) 3
hir-stats GenericParam 400 ( 4.4%) 5 80 hir-stats GenericParam 400 ( 4.4%) 5 80
hir-stats Generics 560 ( 6.1%) 10 56 hir-stats Generics 560 ( 6.1%) 10 56
hir-stats Ty 720 ( 7.8%) 15 48 hir-stats Ty 720 ( 7.9%) 15 48
hir-stats - Ptr 48 ( 0.5%) 1 hir-stats - Ptr 48 ( 0.5%) 1
hir-stats - Rptr 48 ( 0.5%) 1 hir-stats - Rptr 48 ( 0.5%) 1
hir-stats - Path 624 ( 6.8%) 13 hir-stats - Path 624 ( 6.8%) 13
@ -171,8 +171,8 @@ hir-stats - ForeignMod 80 ( 0.9%) 1
hir-stats - Impl 80 ( 0.9%) 1 hir-stats - Impl 80 ( 0.9%) 1
hir-stats - Fn 160 ( 1.7%) 2 hir-stats - Fn 160 ( 1.7%) 2
hir-stats - Use 400 ( 4.4%) 5 hir-stats - Use 400 ( 4.4%) 5
hir-stats Path 1_280 (13.9%) 32 40 hir-stats Path 1_280 (14.0%) 32 40
hir-stats PathSegment 1_920 (20.9%) 40 48 hir-stats PathSegment 1_920 (20.9%) 40 48
hir-stats ---------------------------------------------------------------- hir-stats ----------------------------------------------------------------
hir-stats Total 9_176 hir-stats Total 9_168
hir-stats hir-stats

View file

@ -2,20 +2,62 @@
// gate-test-anonymous_lifetime_in_impl_trait // gate-test-anonymous_lifetime_in_impl_trait
// Verify the behaviour of `feature(anonymous_lifetime_in_impl_trait)`. // Verify the behaviour of `feature(anonymous_lifetime_in_impl_trait)`.
fn f(_: impl Iterator<Item = &'_ ()>) {} mod elided {
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable fn f(_: impl Iterator<Item = &()>) {}
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable
fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() } fn g(mut x: impl Iterator<Item = &()>) -> Option<&()> { x.next() }
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable //~^ ERROR anonymous lifetimes in `impl Trait` are unstable
//~| ERROR missing lifetime specifier //~| ERROR missing lifetime specifier
// Anonymous lifetimes in async fn are already allowed. // Anonymous lifetimes in async fn are already allowed.
// This is understood as `fn foo<'_1>(_: impl Iterator<Item = &'_1 ()>) {}`. // This is understood as `fn foo<'_1>(_: impl Iterator<Item = &'_1 ()>) {}`.
async fn h(_: impl Iterator<Item = &'_ ()>) {} async fn h(_: impl Iterator<Item = &()>) {}
// Anonymous lifetimes in async fn are already allowed. // Anonymous lifetimes in async fn are already allowed.
// But that lifetime does not participate in resolution. // But that lifetime does not participate in resolution.
async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() } async fn i(mut x: impl Iterator<Item = &()>) -> Option<&()> { x.next() }
//~^ ERROR missing lifetime specifier //~^ ERROR missing lifetime specifier
}
mod underscore {
fn f(_: impl Iterator<Item = &'_ ()>) {}
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable
fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable
//~| ERROR missing lifetime specifier
// Anonymous lifetimes in async fn are already allowed.
// This is understood as `fn foo<'_1>(_: impl Iterator<Item = &'_1 ()>) {}`.
async fn h(_: impl Iterator<Item = &'_ ()>) {}
// Anonymous lifetimes in async fn are already allowed.
// But that lifetime does not participate in resolution.
async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
//~^ ERROR missing lifetime specifier
}
mod alone_in_path {
trait Foo<'a> { fn next(&mut self) -> Option<&'a ()>; }
fn f(_: impl Foo) {}
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable
fn g(mut x: impl Foo) -> Option<&()> { x.next() }
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable
//~| ERROR missing lifetime specifier
}
mod in_path {
trait Foo<'a, T> { fn next(&mut self) -> Option<&'a T>; }
fn f(_: impl Foo<()>) {}
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable
fn g(mut x: impl Foo<()>) -> Option<&()> { x.next() }
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable
//~| ERROR missing lifetime specifier
}
fn main() {} fn main() {}

View file

@ -1,52 +1,172 @@
error[E0106]: missing lifetime specifier error[E0106]: missing lifetime specifier
--> $DIR/impl-trait-missing-lifetime-gated.rs:8:50 --> $DIR/impl-trait-missing-lifetime-gated.rs:9:54
| |
LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() } LL | fn g(mut x: impl Iterator<Item = &()>) -> Option<&()> { x.next() }
| ^^ expected named lifetime parameter | ^ 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: 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 help: consider using the `'static` lifetime
| |
LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() } LL | fn g(mut x: impl Iterator<Item = &()>) -> Option<&'static ()> { x.next() }
| ~~~~~~~ | +++++++
error[E0106]: missing lifetime specifier error[E0106]: missing lifetime specifier
--> $DIR/impl-trait-missing-lifetime-gated.rs:18:56 --> $DIR/impl-trait-missing-lifetime-gated.rs:19:60
| |
LL | async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() } LL | async fn i(mut x: impl Iterator<Item = &()>) -> Option<&()> { x.next() }
| ^^ expected named lifetime parameter | ^ 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: 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 help: consider using the `'static` lifetime
| |
LL | async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() } LL | async fn i(mut x: impl Iterator<Item = &()>) -> Option<&'static ()> { x.next() }
| ~~~~~~~ | +++++++
error[E0106]: missing lifetime specifier
--> $DIR/impl-trait-missing-lifetime-gated.rs:27:58
|
LL | fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
| ^^ 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 g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
| ~~~~~~~
error[E0106]: missing lifetime specifier
--> $DIR/impl-trait-missing-lifetime-gated.rs:37:64
|
LL | async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
| ^^ 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 | async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
| ~~~~~~~
error[E0106]: missing lifetime specifier
--> $DIR/impl-trait-missing-lifetime-gated.rs:47:37
|
LL | fn g(mut x: impl Foo) -> Option<&()> { x.next() }
| ^ 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 g(mut x: impl Foo) -> Option<&'static ()> { x.next() }
| +++++++
error[E0106]: missing lifetime specifier
--> $DIR/impl-trait-missing-lifetime-gated.rs:58:41
|
LL | fn g(mut x: impl Foo<()>) -> Option<&()> { x.next() }
| ^ 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 g(mut x: impl Foo<()>) -> Option<&'static ()> { x.next() }
| +++++++
error[E0658]: anonymous lifetimes in `impl Trait` are unstable error[E0658]: anonymous lifetimes in `impl Trait` are unstable
--> $DIR/impl-trait-missing-lifetime-gated.rs:5:31 --> $DIR/impl-trait-missing-lifetime-gated.rs:6:35
| |
LL | fn f(_: impl Iterator<Item = &'_ ()>) {} LL | fn f(_: impl Iterator<Item = &()>) {}
| ^^ expected named lifetime parameter | ^ expected named lifetime parameter
| |
= help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
help: consider introducing a named lifetime parameter help: consider introducing a named lifetime parameter
| |
LL | fn f<'a>(_: impl Iterator<Item = &'_'a ()>) {} LL | fn f<'a>(_: impl Iterator<Item = &'a ()>) {}
| ++++ ++ | ++++ ++
error[E0658]: anonymous lifetimes in `impl Trait` are unstable error[E0658]: anonymous lifetimes in `impl Trait` are unstable
--> $DIR/impl-trait-missing-lifetime-gated.rs:8:31 --> $DIR/impl-trait-missing-lifetime-gated.rs:9:39
| |
LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() } LL | fn g(mut x: impl Iterator<Item = &()>) -> Option<&()> { x.next() }
| ^^ expected named lifetime parameter | ^ expected named lifetime parameter
| |
= help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
help: consider introducing a named lifetime parameter help: consider introducing a named lifetime parameter
| |
LL | fn g<'a>(x: impl Iterator<Item = &'_'a ()>) -> Option<&'_ ()> { x.next() } LL | fn g<'a>(mut x: impl Iterator<Item = &'a ()>) -> Option<&()> { x.next() }
| ++++ ++ | ++++ ++
error: aborting due to 4 previous errors error[E0658]: anonymous lifetimes in `impl Trait` are unstable
--> $DIR/impl-trait-missing-lifetime-gated.rs:24:35
|
LL | fn f(_: impl Iterator<Item = &'_ ()>) {}
| ^^ expected named lifetime parameter
|
= help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
help: consider introducing a named lifetime parameter
|
LL | fn f<'a>(_: impl Iterator<Item = &'a ()>) {}
| ++++ ~~
error[E0658]: anonymous lifetimes in `impl Trait` are unstable
--> $DIR/impl-trait-missing-lifetime-gated.rs:27:39
|
LL | fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
| ^^ expected named lifetime parameter
|
= help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
help: consider introducing a named lifetime parameter
|
LL | fn g<'a>(mut x: impl Iterator<Item = &'a ()>) -> Option<&'_ ()> { x.next() }
| ++++ ~~
error[E0658]: anonymous lifetimes in `impl Trait` are unstable
--> $DIR/impl-trait-missing-lifetime-gated.rs:44:18
|
LL | fn f(_: impl Foo) {}
| ^^^ expected named lifetime parameter
|
= help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
help: consider introducing a named lifetime parameter
|
LL | fn f<'a>(_: impl Foo<'a>) {}
| ++++ ++++
error[E0658]: anonymous lifetimes in `impl Trait` are unstable
--> $DIR/impl-trait-missing-lifetime-gated.rs:47:22
|
LL | fn g(mut x: impl Foo) -> Option<&()> { x.next() }
| ^^^ expected named lifetime parameter
|
= help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
help: consider introducing a named lifetime parameter
|
LL | fn g<'a>(mut x: impl Foo<'a>) -> Option<&()> { x.next() }
| ++++ ++++
error[E0658]: anonymous lifetimes in `impl Trait` are unstable
--> $DIR/impl-trait-missing-lifetime-gated.rs:55:22
|
LL | fn f(_: impl Foo<()>) {}
| ^ expected named lifetime parameter
|
= help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
help: consider introducing a named lifetime parameter
|
LL | fn f<'a>(_: impl Foo<'a, ()>) {}
| ++++ +++
error[E0658]: anonymous lifetimes in `impl Trait` are unstable
--> $DIR/impl-trait-missing-lifetime-gated.rs:58:26
|
LL | fn g(mut x: impl Foo<()>) -> Option<&()> { x.next() }
| ^ expected named lifetime parameter
|
= help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
help: consider introducing a named lifetime parameter
|
LL | fn g<'a>(mut x: impl Foo<'a, ()>) -> Option<&()> { x.next() }
| ++++ +++
error: aborting due to 14 previous errors
Some errors have detailed explanations: E0106, E0658. Some errors have detailed explanations: E0106, E0658.
For more information about an error, try `rustc --explain E0106`. For more information about an error, try `rustc --explain E0106`.

View file

@ -166,8 +166,8 @@ LL | pub union Qux<'t, 'k, I> {
| ^^^ -- -- | ^^^ -- --
help: add missing lifetime argument help: add missing lifetime argument
| |
LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'k, i32>>>>> = RefCell::new(HashMap::new()); LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
| ++++ | +++++++++
error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
--> $DIR/missing-lifetime-specifier.rs:39:44 --> $DIR/missing-lifetime-specifier.rs:39:44
@ -184,8 +184,8 @@ LL | pub union Qux<'t, 'k, I> {
| ^^^ -- -- | ^^^ -- --
help: add missing lifetime argument help: add missing lifetime argument
| |
LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'k, i32>>>>> = RefCell::new(HashMap::new()); LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
| ++++ | +++++++++
error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
--> $DIR/missing-lifetime-specifier.rs:39:44 --> $DIR/missing-lifetime-specifier.rs:39:44
@ -202,8 +202,8 @@ LL | pub union Qux<'t, 'k, I> {
| ^^^ -- -- | ^^^ -- --
help: add missing lifetime argument help: add missing lifetime argument
| |
LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'k, i32>>>>> = RefCell::new(HashMap::new()); LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
| ++++ | +++++++++
error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
--> $DIR/missing-lifetime-specifier.rs:39:44 --> $DIR/missing-lifetime-specifier.rs:39:44
@ -256,8 +256,8 @@ LL | trait Tar<'t, 'k, I> {}
| ^^^ -- -- | ^^^ -- --
help: add missing lifetime argument help: add missing lifetime argument
| |
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'k, i32>>>>> = RefCell::new(HashMap::new()); LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
| ++++ | +++++++++
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
--> $DIR/missing-lifetime-specifier.rs:47:45 --> $DIR/missing-lifetime-specifier.rs:47:45
@ -274,8 +274,8 @@ LL | trait Tar<'t, 'k, I> {}
| ^^^ -- -- | ^^^ -- --
help: add missing lifetime argument help: add missing lifetime argument
| |
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'k, i32>>>>> = RefCell::new(HashMap::new()); LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
| ++++ | +++++++++
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
--> $DIR/missing-lifetime-specifier.rs:47:45 --> $DIR/missing-lifetime-specifier.rs:47:45
@ -292,8 +292,8 @@ LL | trait Tar<'t, 'k, I> {}
| ^^^ -- -- | ^^^ -- --
help: add missing lifetime argument help: add missing lifetime argument
| |
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'k, i32>>>>> = RefCell::new(HashMap::new()); LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
| ++++ | +++++++++
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
--> $DIR/missing-lifetime-specifier.rs:47:45 --> $DIR/missing-lifetime-specifier.rs:47:45

View file

@ -10,8 +10,8 @@ use rustc_hir::lang_items;
use rustc_hir::FnRetTy::Return; use rustc_hir::FnRetTy::Return;
use rustc_hir::{ use rustc_hir::{
BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem, BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem,
ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, ParamName, PolyTraitRef, PredicateOrigin, TraitFn, TraitItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, PolyTraitRef, PredicateOrigin, TraitFn,
TraitItemKind, Ty, TyKind, WherePredicate, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
}; };
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter as middle_nested_filter; use rustc_middle::hir::nested_filter as middle_nested_filter;
@ -180,7 +180,7 @@ fn check_fn_inner<'tcx>(
_ => None, _ => None,
}); });
for bound in lifetimes { for bound in lifetimes {
if bound.name != LifetimeName::Static && !bound.is_elided() { if !bound.is_static() && !bound.is_elided() {
return; return;
} }
} }
@ -414,17 +414,13 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
fn record(&mut self, lifetime: &Option<Lifetime>) { fn record(&mut self, lifetime: &Option<Lifetime>) {
if let Some(ref lt) = *lifetime { if let Some(ref lt) = *lifetime {
if lt.name == LifetimeName::Static { if lt.is_static() {
self.lts.push(RefLt::Static); self.lts.push(RefLt::Static);
} else if let LifetimeName::Param(_, ParamName::Fresh) = lt.name { } else if lt.is_anonymous() {
// Fresh lifetimes generated should be ignored. // Fresh lifetimes generated should be ignored.
self.lts.push(RefLt::Unnamed); self.lts.push(RefLt::Unnamed);
} else if lt.is_elided() { } else if let LifetimeName::Param(def_id) = lt.res {
self.lts.push(RefLt::Unnamed);
} else if let LifetimeName::Param(def_id, _) = lt.name {
self.lts.push(RefLt::Named(def_id)); self.lts.push(RefLt::Named(def_id));
} else {
self.lts.push(RefLt::Unnamed);
} }
} else { } else {
self.lts.push(RefLt::Unnamed); self.lts.push(RefLt::Unnamed);
@ -472,7 +468,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
walk_item(self, item); walk_item(self, item);
self.lts.truncate(len); self.lts.truncate(len);
self.lts.extend(bounds.iter().filter_map(|bound| match bound { self.lts.extend(bounds.iter().filter_map(|bound| match bound {
GenericArg::Lifetime(l) => Some(if let LifetimeName::Param(def_id, _) = l.name { GenericArg::Lifetime(l) => Some(if let LifetimeName::Param(def_id) = l.res {
RefLt::Named(def_id) RefLt::Named(def_id)
} else { } else {
RefLt::Unnamed RefLt::Unnamed
@ -498,10 +494,8 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
} }
fn visit_generic_arg(&mut self, generic_arg: &'tcx GenericArg<'tcx>) { fn visit_generic_arg(&mut self, generic_arg: &'tcx GenericArg<'tcx>) {
if let GenericArg::Lifetime(l) = generic_arg if let GenericArg::Lifetime(l) = generic_arg && let LifetimeName::Param(def_id) = l.res {
&& let LifetimeName::Param(def_id, _) = l.name self.lifetime_generic_arg_spans.entry(def_id).or_insert(l.ident.span);
{
self.lifetime_generic_arg_spans.entry(def_id).or_insert(l.span);
} }
// Replace with `walk_generic_arg` if/when https://github.com/rust-lang/rust/pull/103692 lands. // Replace with `walk_generic_arg` if/when https://github.com/rust-lang/rust/pull/103692 lands.
// walk_generic_arg(self, generic_arg); // walk_generic_arg(self, generic_arg);
@ -577,7 +571,7 @@ where
// for lifetimes as parameters of generics // for lifetimes as parameters of generics
fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) { fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
self.map.remove(&lifetime.name.ident().name); self.map.remove(&lifetime.ident.name);
} }
fn visit_generic_param(&mut self, param: &'tcx GenericParam<'_>) { fn visit_generic_param(&mut self, param: &'tcx GenericParam<'_>) {
@ -601,7 +595,9 @@ fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>,
.params .params
.iter() .iter()
.filter_map(|par| match par.kind { .filter_map(|par| match par.kind {
GenericParamKind::Lifetime { .. } => Some((par.name.ident().name, par.span)), GenericParamKind::Lifetime {
kind: LifetimeParamKind::Explicit,
} => Some((par.name.ident().name, par.span)),
_ => None, _ => None,
}) })
.collect(); .collect();
@ -626,7 +622,9 @@ fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<'
.params .params
.iter() .iter()
.filter_map(|par| match par.kind { .filter_map(|par| match par.kind {
GenericParamKind::Lifetime { .. } => Some((par.name.ident().name, par.span)), GenericParamKind::Lifetime {
kind: LifetimeParamKind::Explicit,
} => Some((par.name.ident().name, par.span)),
_ => None, _ => None,
}) })
.collect(); .collect();
@ -653,7 +651,7 @@ struct BodyLifetimeChecker {
impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker { impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker {
// for lifetimes as parameters of generics // for lifetimes as parameters of generics
fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) { fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
if lifetime.name.ident().name != kw::UnderscoreLifetime && lifetime.name.ident().name != kw::StaticLifetime { if !lifetime.is_anonymous() && lifetime.ident.name != kw::StaticLifetime {
self.lifetimes_used_in_body = true; self.lifetimes_used_in_body = true;
} }
} }

View file

@ -118,7 +118,7 @@ fn future_trait_ref<'tcx>(
.iter() .iter()
.filter_map(|bound| { .filter_map(|bound| {
if let GenericArg::Lifetime(lt) = bound { if let GenericArg::Lifetime(lt) = bound {
Some(lt.name) Some(lt.res)
} else { } else {
None None
} }
@ -153,7 +153,7 @@ fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName])
.iter() .iter()
.filter_map(|ty| { .filter_map(|ty| {
if let TyKind::Rptr(lt, _) = ty.kind { if let TyKind::Rptr(lt, _) = ty.kind {
Some(lt.name) Some(lt.res)
} else { } else {
None None
} }

View file

@ -12,8 +12,8 @@ use rustc_hir::hir_id::HirIdMap;
use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::intravisit::{walk_expr, Visitor};
use rustc_hir::{ use rustc_hir::{
self as hir, AnonConst, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnRetTy, FnSig, GenericArg, self as hir, AnonConst, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnRetTy, FnSig, GenericArg,
ImplItemKind, ItemKind, Lifetime, LifetimeName, Mutability, Node, Param, ParamName, PatKind, QPath, TraitFn, ImplItemKind, ItemKind, Lifetime, Mutability, Node, Param, PatKind, QPath, TraitFn, TraitItem, TraitItemKind,
TraitItem, TraitItemKind, TyKind, Unsafety, TyKind, Unsafety,
}; };
use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::{Obligation, ObligationCause}; use rustc_infer::traits::{Obligation, ObligationCause};
@ -343,21 +343,16 @@ impl PtrArg<'_> {
} }
struct RefPrefix { struct RefPrefix {
lt: LifetimeName, lt: Lifetime,
mutability: Mutability, mutability: Mutability,
} }
impl fmt::Display for RefPrefix { impl fmt::Display for RefPrefix {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use fmt::Write; use fmt::Write;
f.write_char('&')?; f.write_char('&')?;
match self.lt { if !self.lt.is_anonymous() {
LifetimeName::Param(_, ParamName::Plain(name)) => { self.lt.ident.fmt(f)?;
name.fmt(f)?; f.write_char(' ')?;
f.write_char(' ')?;
},
LifetimeName::Infer => f.write_str("'_ ")?,
LifetimeName::Static => f.write_str("'static ")?,
_ => (),
} }
f.write_str(self.mutability.prefix_str()) f.write_str(self.mutability.prefix_str())
} }
@ -495,7 +490,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
ty_name: name.ident.name, ty_name: name.ident.name,
method_renames, method_renames,
ref_prefix: RefPrefix { ref_prefix: RefPrefix {
lt: lt.name, lt: lt.clone(),
mutability, mutability,
}, },
deref_ty, deref_ty,

View file

@ -31,10 +31,10 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m
return false; return false;
} }
let ltopt = if lt.name.is_anonymous() { let ltopt = if lt.is_anonymous() {
String::new() String::new()
} else { } else {
format!("{} ", lt.name.ident().as_str()) format!("{} ", lt.ident.as_str())
}; };
if mut_ty.mutbl == Mutability::Mut { if mut_ty.mutbl == Mutability::Mut {

View file

@ -7,7 +7,7 @@ use rustc_hir::def::Res;
use rustc_hir::HirIdMap; use rustc_hir::HirIdMap;
use rustc_hir::{ use rustc_hir::{
ArrayLen, BinOpKind, BindingAnnotation, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg, ArrayLen, BinOpKind, BindingAnnotation, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg,
GenericArgs, Guard, HirId, InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, GenericArgs, Guard, HirId, InlineAsmOperand, Let, Lifetime, LifetimeName, Pat, PatField, PatKind, Path,
PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding, PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding,
}; };
use rustc_lexer::{tokenize, TokenKind}; use rustc_lexer::{tokenize, TokenKind};
@ -337,7 +337,7 @@ impl HirEqInterExpr<'_, '_, '_> {
} }
fn eq_lifetime(left: &Lifetime, right: &Lifetime) -> bool { fn eq_lifetime(left: &Lifetime, right: &Lifetime) -> bool {
left.name == right.name left.res == right.res
} }
fn eq_pat_field(&mut self, left: &PatField<'_>, right: &PatField<'_>) -> bool { fn eq_pat_field(&mut self, left: &PatField<'_>, right: &PatField<'_>) -> bool {
@ -925,16 +925,10 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
} }
pub fn hash_lifetime(&mut self, lifetime: &Lifetime) { pub fn hash_lifetime(&mut self, lifetime: &Lifetime) {
std::mem::discriminant(&lifetime.name).hash(&mut self.s); lifetime.ident.name.hash(&mut self.s);
if let LifetimeName::Param(param_id, ref name) = lifetime.name { std::mem::discriminant(&lifetime.res).hash(&mut self.s);
std::mem::discriminant(name).hash(&mut self.s); if let LifetimeName::Param(param_id) = lifetime.res {
param_id.hash(&mut self.s); param_id.hash(&mut self.s);
match name {
ParamName::Plain(ref ident) => {
ident.name.hash(&mut self.s);
},
ParamName::Fresh | ParamName::Error => {},
}
} }
} }