Auto merge of #98279 - cjgillot:all-fresh-nofn, r=petrochenkov

Create elided lifetime parameters for function-like types

Split from https://github.com/rust-lang/rust/pull/97720

This PR refactor lifetime generic parameters in bare function types and parenthesized traits to introduce the additional required lifetimes as fresh parameters in a `for<>` bound.

This PR does the same to lifetimes appearing in closure signatures, and as-if introducing `for<>` bounds on closures (without the associated change in semantics).

r? `@petrochenkov`
This commit is contained in:
bors 2022-06-22 10:48:58 +00:00
commit 10f4ce324b
28 changed files with 816 additions and 607 deletions

View File

@ -165,6 +165,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
if let Async::Yes { closure_id, .. } = asyncness { if let Async::Yes { closure_id, .. } = asyncness {
self.lower_expr_async_closure( self.lower_expr_async_closure(
capture_clause, capture_clause,
e.id,
closure_id, closure_id,
decl, decl,
body, body,
@ -173,6 +174,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
} else { } else {
self.lower_expr_closure( self.lower_expr_closure(
capture_clause, capture_clause,
e.id,
movability, movability,
decl, decl,
body, body,
@ -604,6 +606,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
// `static |_task_context| -> <ret_ty> { body }`: // `static |_task_context| -> <ret_ty> { body }`:
let generator_kind = hir::ExprKind::Closure { let generator_kind = hir::ExprKind::Closure {
capture_clause, capture_clause,
bound_generic_params: &[],
fn_decl, fn_decl,
body, body,
fn_decl_span: self.lower_span(span), fn_decl_span: self.lower_span(span),
@ -828,6 +831,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn lower_expr_closure( fn lower_expr_closure(
&mut self, &mut self,
capture_clause: CaptureBy, capture_clause: CaptureBy,
closure_id: NodeId,
movability: Movability, movability: Movability,
decl: &FnDecl, decl: &FnDecl,
body: &Expr, body: &Expr,
@ -848,16 +852,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
(body_id, generator_option) (body_id, generator_option)
}); });
self.with_lifetime_binder(closure_id, &[], |this, bound_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, FnDeclKind::Closure, None); let fn_decl = this.lower_fn_decl(decl, None, FnDeclKind::Closure, None);
hir::ExprKind::Closure { hir::ExprKind::Closure {
capture_clause, capture_clause,
bound_generic_params,
fn_decl, fn_decl,
body, body,
fn_decl_span: self.lower_span(fn_decl_span), fn_decl_span: this.lower_span(fn_decl_span),
movability: generator_option, movability: generator_option,
} }
})
} }
fn generator_movability_for_fn( fn generator_movability_for_fn(
@ -897,6 +904,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
&mut self, &mut self,
capture_clause: CaptureBy, capture_clause: CaptureBy,
closure_id: NodeId, closure_id: NodeId,
inner_closure_id: NodeId,
decl: &FnDecl, decl: &FnDecl,
body: &Expr, body: &Expr,
fn_decl_span: Span, fn_decl_span: Span,
@ -927,7 +935,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
if let FnRetTy::Ty(ty) = &decl.output { Some(ty.clone()) } else { None }; if let FnRetTy::Ty(ty) = &decl.output { Some(ty.clone()) } else { None };
let async_body = this.make_async_expr( let async_body = this.make_async_expr(
capture_clause, capture_clause,
closure_id, inner_closure_id,
async_ret_ty, async_ret_ty,
body.span, body.span,
hir::AsyncGeneratorKind::Closure, hir::AsyncGeneratorKind::Closure,
@ -938,18 +946,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
body_id body_id
}); });
self.with_lifetime_binder(closure_id, &[], |this, bound_generic_params| {
// We need to lower the declaration outside the new scope, because we // We need to lower the declaration outside the new scope, because we
// 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 = self.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None); let fn_decl = this.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None);
hir::ExprKind::Closure { hir::ExprKind::Closure {
capture_clause, capture_clause,
bound_generic_params,
fn_decl, fn_decl,
body, body,
fn_decl_span: self.lower_span(fn_decl_span), fn_decl_span: this.lower_span(fn_decl_span),
movability: None, movability: None,
} }
})
} }
/// Destructure the LHS of complex assignments. /// Destructure the LHS of complex assignments.

View File

@ -1386,16 +1386,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
let mut params: SmallVec<[hir::GenericParam<'hir>; 4]> = let mut params: SmallVec<[hir::GenericParam<'hir>; 4]> =
self.lower_generic_params_mut(&generics.params).collect(); self.lower_generic_params_mut(&generics.params).collect();
// Introduce extra lifetimes if late resolution tells us to.
let extra_lifetimes = self.resolver.take_extra_lifetime_params(parent_node_id);
params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| {
self.lifetime_res_to_generic_param(ident, node_id, res)
}));
let has_where_clause_predicates = !generics.where_clause.predicates.is_empty(); let has_where_clause_predicates = !generics.where_clause.predicates.is_empty();
let where_clause_span = self.lower_span(generics.where_clause.span); let where_clause_span = self.lower_span(generics.where_clause.span);
let span = self.lower_span(generics.span); let span = self.lower_span(generics.span);
let res = f(self); let res = f(self);
let extra_lifetimes = self.resolver.take_extra_lifetime_params(parent_node_id);
let impl_trait_defs = std::mem::take(&mut self.impl_trait_defs); let impl_trait_defs = std::mem::take(&mut self.impl_trait_defs);
params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| {
self.lifetime_res_to_generic_param(ident, node_id, res)
}));
params.extend(impl_trait_defs.into_iter()); params.extend(impl_trait_defs.into_iter());
let impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds); let impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds);

View File

@ -223,6 +223,12 @@ impl ResolverAstLoweringExt for ResolverAstLowering {
} }
/// Obtain the list of lifetimes parameters to add to an item. /// Obtain the list of lifetimes parameters to add to an item.
///
/// Extra lifetime parameters should only be added in places that can appear
/// as a `binder` in `LifetimeRes`.
///
/// The extra lifetimes that appear from the parenthesized `Fn`-trait desugaring
/// should appear at the enclosing `PolyTraitRef`.
fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> { fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> {
self.extra_lifetime_params_map.remove(&id).unwrap_or_default() self.extra_lifetime_params_map.remove(&id).unwrap_or_default()
} }
@ -721,6 +727,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
} }
/// Converts a lifetime into a new generic parameter. /// Converts a lifetime into a new generic parameter.
#[tracing::instrument(level = "debug", skip(self))]
fn lifetime_res_to_generic_param( fn lifetime_res_to_generic_param(
&mut self, &mut self,
ident: Ident, ident: Ident,
@ -731,7 +738,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
LifetimeRes::Param { .. } => { LifetimeRes::Param { .. } => {
(hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit) (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit)
} }
LifetimeRes::Fresh { .. } => (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided), LifetimeRes::Fresh { param, .. } => {
// Late resolution delegates to us the creation of the `LocalDefId`.
let _def_id = self.create_def(
self.current_hir_id_owner,
param,
DefPathData::LifetimeNs(kw::UnderscoreLifetime),
);
debug!(?_def_id);
(hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
}
LifetimeRes::Static | LifetimeRes::Error => return None, LifetimeRes::Static | LifetimeRes::Error => return None,
res => panic!( res => panic!(
"Unexpected lifetime resolution {:?} for {:?} at {:?}", "Unexpected lifetime resolution {:?} for {:?} at {:?}",
@ -777,11 +794,25 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
/// Register a binder to be ignored for lifetime capture. /// Register a binder to be ignored for lifetime capture.
#[tracing::instrument(level = "debug", skip(self, f))] #[tracing::instrument(level = "debug", skip(self, f))]
#[inline] #[inline]
fn with_lifetime_binder<T>(&mut self, binder: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { fn with_lifetime_binder<T>(
&mut self,
binder: NodeId,
generic_params: &[GenericParam],
f: impl FnOnce(&mut Self, &'hir [hir::GenericParam<'hir>]) -> T,
) -> T {
let mut generic_params: Vec<_> = self.lower_generic_params_mut(generic_params).collect();
let extra_lifetimes = self.resolver.take_extra_lifetime_params(binder);
debug!(?extra_lifetimes);
generic_params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| {
self.lifetime_res_to_generic_param(ident, node_id, res)
}));
let generic_params = self.arena.alloc_from_iter(generic_params);
debug!(?generic_params);
if let Some(ctxt) = &mut self.captured_lifetimes { if let Some(ctxt) = &mut self.captured_lifetimes {
ctxt.binders_to_ignore.insert(binder); ctxt.binders_to_ignore.insert(binder);
} }
let ret = f(self); let ret = f(self, generic_params);
if let Some(ctxt) = &mut self.captured_lifetimes { if let Some(ctxt) = &mut self.captured_lifetimes {
ctxt.binders_to_ignore.remove(&binder); ctxt.binders_to_ignore.remove(&binder);
} }
@ -1178,15 +1209,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let lifetime = self.lower_lifetime(&region); let lifetime = self.lower_lifetime(&region);
hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx)) hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx))
} }
TyKind::BareFn(ref f) => self.with_lifetime_binder(t.id, |this| { TyKind::BareFn(ref f) => {
self.with_lifetime_binder(t.id, &f.generic_params, |this, generic_params| {
hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy { hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy {
generic_params: this.lower_generic_params(&f.generic_params), generic_params,
unsafety: this.lower_unsafety(f.unsafety), unsafety: this.lower_unsafety(f.unsafety),
abi: this.lower_extern(f.ext), abi: this.lower_extern(f.ext),
decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None), decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
param_names: this.lower_fn_params_to_names(&f.decl), param_names: this.lower_fn_params_to_names(&f.decl),
})) }))
}), })
}
TyKind::Never => hir::TyKind::Never, TyKind::Never => hir::TyKind::Never,
TyKind::Tup(ref tys) => hir::TyKind::Tup( TyKind::Tup(ref tys) => hir::TyKind::Tup(
self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))), self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))),
@ -1814,8 +1847,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
} }
hir::LifetimeName::Param(param, p_name) hir::LifetimeName::Param(param, p_name)
} }
LifetimeRes::Fresh { mut param, binder } => { LifetimeRes::Fresh { param, binder } => {
debug_assert_eq!(ident.name, kw::UnderscoreLifetime); debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
let mut param = self.local_def_id(param);
if let Some(mut captured_lifetimes) = self.captured_lifetimes.take() { if let Some(mut captured_lifetimes) = self.captured_lifetimes.take() {
if !captured_lifetimes.binders_to_ignore.contains(&binder) { if !captured_lifetimes.binders_to_ignore.contains(&binder) {
match captured_lifetimes.captures.entry(param) { match captured_lifetimes.captures.entry(param) {
@ -1952,13 +1986,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
p: &PolyTraitRef, p: &PolyTraitRef,
itctx: ImplTraitContext, itctx: ImplTraitContext,
) -> hir::PolyTraitRef<'hir> { ) -> hir::PolyTraitRef<'hir> {
let bound_generic_params = self.lower_generic_params(&p.bound_generic_params); self.with_lifetime_binder(
p.trait_ref.ref_id,
let trait_ref = self.with_lifetime_binder(p.trait_ref.ref_id, |this| { &p.bound_generic_params,
this.lower_trait_ref(&p.trait_ref, itctx) |this, bound_generic_params| {
}); let trait_ref = this.lower_trait_ref(&p.trait_ref, itctx);
hir::PolyTraitRef { bound_generic_params, trait_ref, span: this.lower_span(p.span) }
hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) } },
)
} }
fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> { fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> {

View File

@ -191,9 +191,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.lower_angle_bracketed_parameter_data(data, param_mode, itctx) self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
} }
GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args { GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args {
ParenthesizedGenericArgs::Ok => { ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
self.lower_parenthesized_parameter_data(segment.id, data)
}
ParenthesizedGenericArgs::Err => { ParenthesizedGenericArgs::Err => {
let mut err = struct_span_err!(self.sess, data.span, E0214, "{}", msg); let mut err = struct_span_err!(self.sess, data.span, E0214, "{}", msg);
err.span_label(data.span, "only `Fn` traits may use parentheses"); err.span_label(data.span, "only `Fn` traits may use parentheses");
@ -351,7 +349,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_parenthesized_parameter_data( fn lower_parenthesized_parameter_data(
&mut self, &mut self,
id: NodeId,
data: &ParenthesizedArgs, data: &ParenthesizedArgs,
) -> (GenericArgsCtor<'hir>, bool) { ) -> (GenericArgsCtor<'hir>, bool) {
// Switch to `PassThrough` mode for anonymous lifetimes; this // Switch to `PassThrough` mode for anonymous lifetimes; this
@ -359,31 +356,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// a hidden lifetime parameter. This is needed for backwards // a hidden lifetime parameter. This is needed for backwards
// compatibility, even in contexts like an impl header where // compatibility, even in contexts like an impl header where
// we generally don't permit such things (see #51008). // we generally don't permit such things (see #51008).
self.with_lifetime_binder(id, |this| {
let ParenthesizedArgs { span, inputs, inputs_span, output } = data; let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
let inputs = this.arena.alloc_from_iter(inputs.iter().map(|ty| { let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| {
this.lower_ty_direct( self.lower_ty_direct(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
ty,
ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam),
)
})); }));
let output_ty = match output { let output_ty = match output {
FnRetTy::Ty(ty) => this FnRetTy::Ty(ty) => {
.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)), self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn))
FnRetTy::Default(_) => this.arena.alloc(this.ty_tup(*span, &[])), }
FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
}; };
let args = smallvec![GenericArg::Type(this.ty_tup(*inputs_span, inputs))]; let args = smallvec![GenericArg::Type(self.ty_tup(*inputs_span, inputs))];
let binding = this.output_ty_binding(output_ty.span, output_ty); let binding = self.output_ty_binding(output_ty.span, output_ty);
( (
GenericArgsCtor { GenericArgsCtor {
args, args,
bindings: arena_vec![this; binding], bindings: arena_vec![self; binding],
parenthesized: true, parenthesized: true,
span: data.inputs_span, span: data.inputs_span,
}, },
false, false,
) )
})
} }
/// An associated type binding `Output = $ty`. /// An associated type binding `Output = $ty`.

View File

@ -254,6 +254,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
/// *user* has a name for. In that case, we'll be able to map /// *user* has a name for. In that case, we'll be able to map
/// `fr` to a `Region<'tcx>`, and that region will be one of /// `fr` to a `Region<'tcx>`, and that region will be one of
/// named variants. /// named variants.
#[tracing::instrument(level = "trace", skip(self))]
fn give_name_from_error_region(&self, fr: RegionVid) -> Option<RegionName> { fn give_name_from_error_region(&self, fr: RegionVid) -> Option<RegionName> {
let error_region = self.to_error_region(fr)?; let error_region = self.to_error_region(fr)?;
@ -290,7 +291,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
if free_region.bound_region.is_named() { if free_region.bound_region.is_named() {
// A named region that is actually named. // A named region that is actually named.
Some(RegionName { name, source: RegionNameSource::NamedFreeRegion(span) }) Some(RegionName { name, source: RegionNameSource::NamedFreeRegion(span) })
} else { } else if let hir::IsAsync::Async = tcx.asyncness(self.mir_hir_id().owner) {
// If we spuriously thought that the region is named, we should let the // If we spuriously thought that the region is named, we should let the
// system generate a true name for error messages. Currently this can // system generate a true name for error messages. Currently this can
// happen if we have an elided name in an async fn for example: the // happen if we have an elided name in an async fn for example: the
@ -301,6 +302,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
name, name,
source: RegionNameSource::AnonRegionFromAsyncFn(span), source: RegionNameSource::AnonRegionFromAsyncFn(span),
}) })
} else {
None
} }
} }
@ -362,6 +365,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
/// | fn foo(x: &u32) { .. } /// | fn foo(x: &u32) { .. }
/// ------- fully elaborated type of `x` is `&'1 u32` /// ------- fully elaborated type of `x` is `&'1 u32`
/// ``` /// ```
#[tracing::instrument(level = "trace", skip(self))]
fn give_name_if_anonymous_region_appears_in_arguments( fn give_name_if_anonymous_region_appears_in_arguments(
&self, &self,
fr: RegionVid, fr: RegionVid,
@ -651,6 +655,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
/// | let x = Some(&22); /// | let x = Some(&22);
/// - fully elaborated type of `x` is `Option<&'1 u32>` /// - fully elaborated type of `x` is `Option<&'1 u32>`
/// ``` /// ```
#[tracing::instrument(level = "trace", skip(self))]
fn give_name_if_anonymous_region_appears_in_upvars(&self, fr: RegionVid) -> Option<RegionName> { fn give_name_if_anonymous_region_appears_in_upvars(&self, fr: RegionVid) -> Option<RegionName> {
let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?; let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?;
let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region( let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region(
@ -670,6 +675,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
/// must be a closure since, in a free fn, such an argument would /// must be a closure since, in a free fn, such an argument would
/// have to either also appear in an argument (if using elision) /// have to either also appear in an argument (if using elision)
/// or be early bound (named, not in argument). /// or be early bound (named, not in argument).
#[tracing::instrument(level = "trace", skip(self))]
fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Option<RegionName> { fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Option<RegionName> {
let tcx = self.infcx.tcx; let tcx = self.infcx.tcx;
let hir = tcx.hir(); let hir = tcx.hir();
@ -801,6 +807,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
} }
} }
#[tracing::instrument(level = "trace", skip(self))]
fn give_name_if_anonymous_region_appears_in_yield_ty( fn give_name_if_anonymous_region_appears_in_yield_ty(
&self, &self,
fr: RegionVid, fr: RegionVid,

View File

@ -722,8 +722,7 @@ pub enum LifetimeRes {
/// Id of the introducing place. That can be: /// Id of the introducing place. That can be:
/// - an item's id, for the item's generic parameters; /// - an item's id, for the item's generic parameters;
/// - a TraitRef's ref_id, identifying the `for<...>` binder; /// - a TraitRef's ref_id, identifying the `for<...>` binder;
/// - a BareFn type's id; /// - a BareFn type's id.
/// - a Path's id when this path has parenthesized generic args.
/// ///
/// This information is used for impl-trait lifetime captures, to know when to or not to /// This information is used for impl-trait lifetime captures, to know when to or not to
/// capture any given lifetime. /// capture any given lifetime.
@ -732,7 +731,9 @@ pub enum LifetimeRes {
/// Created a generic parameter for an anonymous lifetime. /// Created a generic parameter for an anonymous lifetime.
Fresh { Fresh {
/// Id of the generic parameter that introduced it. /// Id of the generic parameter that introduced it.
param: LocalDefId, ///
/// Creating the associated `LocalDefId` is the responsibility of lowering.
param: NodeId,
/// Id of the introducing place. See `Param`. /// Id of the introducing place. See `Param`.
binder: NodeId, binder: NodeId,
}, },

View File

@ -1932,6 +1932,7 @@ pub enum ExprKind<'hir> {
/// `Option<Movability>`. /// `Option<Movability>`.
Closure { Closure {
capture_clause: CaptureBy, capture_clause: CaptureBy,
bound_generic_params: &'hir [GenericParam<'hir>],
fn_decl: &'hir FnDecl<'hir>, fn_decl: &'hir FnDecl<'hir>,
body: BodyId, body: BodyId,
fn_decl_span: Span, fn_decl_span: Span,
@ -3480,7 +3481,7 @@ impl<'hir> Node<'hir> {
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
mod size_asserts { mod size_asserts {
rustc_data_structures::static_assert_size!(super::Block<'static>, 48); rustc_data_structures::static_assert_size!(super::Block<'static>, 48);
rustc_data_structures::static_assert_size!(super::Expr<'static>, 56); rustc_data_structures::static_assert_size!(super::Expr<'static>, 64);
rustc_data_structures::static_assert_size!(super::Pat<'static>, 88); rustc_data_structures::static_assert_size!(super::Pat<'static>, 88);
rustc_data_structures::static_assert_size!(super::QPath<'static>, 24); rustc_data_structures::static_assert_size!(super::QPath<'static>, 24);
rustc_data_structures::static_assert_size!(super::Ty<'static>, 72); rustc_data_structures::static_assert_size!(super::Ty<'static>, 72);

View File

@ -1169,12 +1169,16 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
walk_list!(visitor, visit_arm, arms); walk_list!(visitor, visit_arm, arms);
} }
ExprKind::Closure { ExprKind::Closure {
bound_generic_params,
ref fn_decl, ref fn_decl,
body, body,
capture_clause: _, capture_clause: _,
fn_decl_span: _, fn_decl_span: _,
movability: _, movability: _,
} => visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id), } => {
walk_list!(visitor, visit_generic_param, bound_generic_params);
visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id)
}
ExprKind::Block(ref block, ref opt_label) => { ExprKind::Block(ref block, ref opt_label) => {
walk_list!(visitor, visit_label, opt_label); walk_list!(visitor, visit_label, opt_label);
visitor.visit_block(block); visitor.visit_block(block);

View File

@ -1459,11 +1459,13 @@ impl<'a> State<'a> {
} }
hir::ExprKind::Closure { hir::ExprKind::Closure {
capture_clause, capture_clause,
bound_generic_params,
ref fn_decl, ref fn_decl,
body, body,
fn_decl_span: _, fn_decl_span: _,
movability: _, movability: _,
} => { } => {
self.print_formal_generic_params(bound_generic_params);
self.print_capture_clause(capture_clause); self.print_capture_clause(capture_clause);
self.print_closure_params(&fn_decl, body); self.print_closure_params(&fn_decl, body);

View File

@ -20,9 +20,7 @@ use rustc_errors::DiagnosticId;
use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS}; use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS};
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
use rustc_hir::definitions::DefPathData;
use rustc_hir::{PrimTy, TraitCandidate}; use rustc_hir::{PrimTy, TraitCandidate};
use rustc_index::vec::Idx;
use rustc_middle::ty::DefIdTree; use rustc_middle::ty::DefIdTree;
use rustc_middle::{bug, span_bug}; use rustc_middle::{bug, span_bug};
use rustc_session::lint; use rustc_session::lint;
@ -238,14 +236,21 @@ enum LifetimeRibKind {
/// `body_id` is an anonymous constant and `lifetime_ref` is non-static. /// `body_id` is an anonymous constant and `lifetime_ref` is non-static.
AnonConst, AnonConst,
/// For **Modern** cases, create a new anonymous region parameter /// Create a new anonymous lifetime parameter and reference it.
/// and reference that.
/// ///
/// For **Dyn Bound** cases, pass responsibility to /// If `report_in_path`, report an error when encountering lifetime elision in a path:
/// `resolve_lifetime` code. /// ```compile_fail
/// struct Foo<'a> { x: &'a () }
/// async fn foo(x: Foo) {}
/// ```
/// ///
/// For **Deprecated** cases, report an error. /// Note: the error should not trigger when the elided lifetime is in a pattern or
AnonymousCreateParameter(NodeId), /// expression-position path:
/// ```
/// struct Foo<'a> { x: &'a () }
/// async fn foo(Foo { x: _ }: Foo<'_>) {}
/// ```
AnonymousCreateParameter { binder: NodeId, report_in_path: bool },
/// Give a hard error when either `&` or `'_` is written. Used to /// Give a hard error when either `&` or `'_` is written. Used to
/// rule out things like `where T: Foo<'_>`. Does not imply an /// rule out things like `where T: Foo<'_>`. Does not imply an
@ -635,7 +640,10 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|this| { |this| {
this.visit_generic_params(&bare_fn.generic_params, false); this.visit_generic_params(&bare_fn.generic_params, false);
this.with_lifetime_rib( this.with_lifetime_rib(
LifetimeRibKind::AnonymousPassThrough(ty.id, false), LifetimeRibKind::AnonymousCreateParameter {
binder: ty.id,
report_in_path: false,
},
|this| walk_list!(this, visit_param, &bare_fn.decl.inputs), |this| walk_list!(this, visit_param, &bare_fn.decl.inputs),
); );
this.with_lifetime_rib( this.with_lifetime_rib(
@ -721,15 +729,13 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
// a body, or if there's no body for some other reason. // a body, or if there's no body for some other reason.
FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _) FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _)
| FnKind::Fn(_, _, sig, _, generics, None) => { | FnKind::Fn(_, _, sig, _, generics, None) => {
self.visit_fn_header(&sig.header);
self.visit_generics(generics);
// We don't need to deal with patterns in parameters, because // We don't need to deal with patterns in parameters, because
// they are not possible for foreign or bodiless functions. // they are not possible for foreign or bodiless functions.
self.with_lifetime_rib( self.with_lifetime_rib(
LifetimeRibKind::AnonymousPassThrough(fn_id, false), LifetimeRibKind::AnonymousPassThrough(fn_id, false),
|this| { |this| walk_list!(this, visit_param, &sig.decl.inputs),
this.visit_fn_header(&sig.header);
this.visit_generics(generics);
walk_list!(this, visit_param, &sig.decl.inputs);
},
); );
self.with_lifetime_rib( self.with_lifetime_rib(
LifetimeRibKind::AnonymousPassThrough(fn_id, true), LifetimeRibKind::AnonymousPassThrough(fn_id, true),
@ -746,36 +752,49 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
self.diagnostic_metadata.current_function = Some((fn_kind, sp)); self.diagnostic_metadata.current_function = Some((fn_kind, sp));
} }
debug!("(resolving function) entering function"); debug!("(resolving function) entering function");
let declaration = fn_kind.decl();
// Create a value rib for the function. // Create a value rib for the function.
self.with_rib(ValueNS, rib_kind, |this| { self.with_rib(ValueNS, rib_kind, |this| {
// Create a label rib for the function. // Create a label rib for the function.
this.with_label_rib(FnItemRibKind, |this| { this.with_label_rib(FnItemRibKind, |this| {
let async_node_id = fn_kind.header().and_then(|h| h.asyncness.opt_return_id()); match fn_kind {
FnKind::Fn(_, _, sig, _, generics, body) => {
if let FnKind::Fn(_, _, _, _, generics, _) = fn_kind {
this.visit_generics(generics); this.visit_generics(generics);
}
if let Some(async_node_id) = async_node_id { let declaration = &sig.decl;
// In `async fn`, argument-position elided lifetimes let async_node_id = sig.header.asyncness.opt_return_id();
// must be transformed into fresh generic parameters so that
// they can be applied to the opaque `impl Trait` return type. // Argument-position elided lifetimes must be transformed into fresh
// generic parameters. This is especially useful for `async fn`, where
// these fresh generic parameters can be applied to the opaque `impl Trait`
// return type.
let rib = if async_node_id.is_some() {
// Only emit a hard error for `async fn`, since this kind of
// elision has always been allowed in regular `fn`s.
LifetimeRibKind::AnonymousCreateParameter {
binder: fn_id,
report_in_path: true,
}
} else {
LifetimeRibKind::AnonymousPassThrough(fn_id, false)
};
this.with_lifetime_rib( this.with_lifetime_rib(
LifetimeRibKind::AnonymousCreateParameter(fn_id), rib,
|this| {
// Add each argument to the rib. // Add each argument to the rib.
this.resolve_params(&declaration.inputs) |this| this.resolve_params(&declaration.inputs),
},
); );
// Construct the list of in-scope lifetime parameters for async lowering. // Construct the list of in-scope lifetime parameters for async lowering.
// We include all lifetime parameters, either named or "Fresh". // We include all lifetime parameters, either named or "Fresh".
// The order of those parameters does not matter, as long as it is // The order of those parameters does not matter, as long as it is
// deterministic. // deterministic.
let mut extra_lifetime_params = if let Some(async_node_id) = async_node_id {
this.r.extra_lifetime_params_map.get(&fn_id).cloned().unwrap_or_default(); let mut extra_lifetime_params = this
.r
.extra_lifetime_params_map
.get(&fn_id)
.cloned()
.unwrap_or_default();
for rib in this.lifetime_ribs.iter().rev() { for rib in this.lifetime_ribs.iter().rev() {
extra_lifetime_params.extend( extra_lifetime_params.extend(
rib.bindings rib.bindings
@ -784,9 +803,11 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
); );
match rib.kind { match rib.kind {
LifetimeRibKind::Item => break, LifetimeRibKind::Item => break,
LifetimeRibKind::AnonymousCreateParameter(id) => { LifetimeRibKind::AnonymousCreateParameter {
binder, ..
} => {
if let Some(earlier_fresh) = if let Some(earlier_fresh) =
this.r.extra_lifetime_params_map.get(&id) this.r.extra_lifetime_params_map.get(&binder)
{ {
extra_lifetime_params.extend(earlier_fresh); extra_lifetime_params.extend(earlier_fresh);
} }
@ -794,23 +815,50 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
_ => {} _ => {}
} }
} }
this.r.extra_lifetime_params_map.insert(async_node_id, extra_lifetime_params); this.r
.extra_lifetime_params_map
.insert(async_node_id, extra_lifetime_params);
}
this.with_lifetime_rib( this.with_lifetime_rib(
LifetimeRibKind::AnonymousPassThrough(async_node_id, true), LifetimeRibKind::AnonymousPassThrough(
// For async fn, the return type appears inside a custom
// `impl Future` RPIT, so we override the binder's id.
async_node_id.unwrap_or(fn_id),
true,
),
|this| visit::walk_fn_ret_ty(this, &declaration.output), |this| visit::walk_fn_ret_ty(this, &declaration.output),
); );
} else {
// Add each argument to the rib. if let Some(body) = body {
// Ignore errors in function bodies if this is rustdoc
// Be sure not to set this until the function signature has been resolved.
let previous_state = replace(&mut this.in_func_body, true);
// Resolve the function body, potentially inside the body of an async closure
this.with_lifetime_rib( this.with_lifetime_rib(
LifetimeRibKind::AnonymousPassThrough(fn_id, false), LifetimeRibKind::AnonymousPassThrough(fn_id, false),
|this| this.visit_block(body),
);
debug!("(resolving function) leaving function");
this.in_func_body = previous_state;
}
}
FnKind::Closure(declaration, body) => {
// We do not have any explicit generic lifetime parameter.
// FIXME(rfc3216): Change when implementing `for<>` bounds on closures.
this.with_lifetime_rib(
LifetimeRibKind::AnonymousCreateParameter {
binder: fn_id,
report_in_path: false,
},
// Add each argument to the rib.
|this| this.resolve_params(&declaration.inputs), |this| this.resolve_params(&declaration.inputs),
); );
this.with_lifetime_rib( this.with_lifetime_rib(
LifetimeRibKind::AnonymousPassThrough(fn_id, true), LifetimeRibKind::AnonymousPassThrough(fn_id, true),
|this| visit::walk_fn_ret_ty(this, &declaration.output), |this| visit::walk_fn_ret_ty(this, &declaration.output),
); );
};
// Ignore errors in function bodies if this is rustdoc // Ignore errors in function bodies if this is rustdoc
// Be sure not to set this until the function signature has been resolved. // Be sure not to set this until the function signature has been resolved.
@ -818,14 +866,13 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
// Resolve the function body, potentially inside the body of an async closure // Resolve the function body, potentially inside the body of an async closure
this.with_lifetime_rib( this.with_lifetime_rib(
LifetimeRibKind::AnonymousPassThrough(fn_id, false), LifetimeRibKind::AnonymousPassThrough(fn_id, false),
|this| match fn_kind { |this| this.visit_expr(body),
FnKind::Fn(.., body) => walk_list!(this, visit_block, body),
FnKind::Closure(_, body) => this.visit_expr(body),
},
); );
debug!("(resolving function) leaving function"); debug!("(resolving function) leaving function");
this.in_func_body = previous_state; this.in_func_body = previous_state;
}
}
}) })
}); });
self.diagnostic_metadata.current_function = previous_value; self.diagnostic_metadata.current_function = previous_value;
@ -902,19 +949,66 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
self.diagnostic_metadata.currently_processing_generics = prev; self.diagnostic_metadata.currently_processing_generics = prev;
} }
fn visit_assoc_constraint(&mut self, constraint: &'ast AssocConstraint) {
self.visit_ident(constraint.ident);
if let Some(ref gen_args) = constraint.gen_args {
// Forbid anonymous lifetimes in GAT parameters until proper semantics are decided.
self.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
this.visit_generic_args(gen_args.span(), gen_args)
});
}
match constraint.kind {
AssocConstraintKind::Equality { ref term } => match term {
Term::Ty(ty) => self.visit_ty(ty),
Term::Const(c) => self.visit_anon_const(c),
},
AssocConstraintKind::Bound { ref bounds } => {
walk_list!(self, visit_param_bound, bounds, BoundKind::Bound);
}
}
}
fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegment) { fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegment) {
if let Some(ref args) = path_segment.args { if let Some(ref args) = path_segment.args {
match &**args { match &**args {
GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, path_span, args), GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, path_span, args),
GenericArgs::Parenthesized(ref data) => { GenericArgs::Parenthesized(p_args) => {
// Probe the lifetime ribs to know how to behave.
for rib in self.lifetime_ribs.iter().rev() {
match rib.kind {
// We are inside a `PolyTraitRef`. The lifetimes are
// to be intoduced in that (maybe implicit) `for<>` binder.
LifetimeRibKind::Generics {
binder,
kind: LifetimeBinderKind::PolyTrait,
..
} => {
self.with_lifetime_rib( self.with_lifetime_rib(
LifetimeRibKind::AnonymousPassThrough(path_segment.id, false), LifetimeRibKind::AnonymousCreateParameter {
|this| walk_list!(this, visit_ty, &data.inputs), binder,
report_in_path: false,
},
|this| walk_list!(this, visit_ty, &p_args.inputs),
); );
self.with_lifetime_rib( self.with_lifetime_rib(
LifetimeRibKind::AnonymousPassThrough(path_segment.id, true), LifetimeRibKind::AnonymousPassThrough(binder, true),
|this| visit::walk_fn_ret_ty(this, &data.output), |this| visit::walk_fn_ret_ty(this, &p_args.output),
) );
break;
}
// We have nowhere to introduce generics. Code is malformed,
// so use regular lifetime resolution to avoid spurious errors.
LifetimeRibKind::Item | LifetimeRibKind::Generics { .. } => {
visit::walk_generic_args(self, path_span, args);
break;
}
LifetimeRibKind::AnonymousPassThrough(..)
| LifetimeRibKind::AnonymousCreateParameter { .. }
| LifetimeRibKind::AnonymousReportError
| LifetimeRibKind::AnonConst
| LifetimeRibKind::ConstGeneric => {}
}
}
} }
} }
} }
@ -1243,13 +1337,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
for i in &mut indices { for i in &mut indices {
let rib = &self.lifetime_ribs[i]; let rib = &self.lifetime_ribs[i];
let normalized_ident = ident.normalize_to_macros_2_0(); let normalized_ident = ident.normalize_to_macros_2_0();
if let Some(&(_, region)) = rib.bindings.get(&normalized_ident) { if let Some(&(_, res)) = rib.bindings.get(&normalized_ident) {
self.record_lifetime_res(lifetime.id, region); self.record_lifetime_res(lifetime.id, res);
if let LifetimeRes::Param { param, .. } = region { if let LifetimeRes::Param { param, .. } = res {
match self.lifetime_uses.entry(param) { match self.lifetime_uses.entry(param) {
Entry::Vacant(v) => { Entry::Vacant(v) => {
debug!("First use of {:?} at {:?}", region, ident.span); debug!("First use of {:?} at {:?}", res, ident.span);
let use_set = self let use_set = self
.lifetime_ribs .lifetime_ribs
.iter() .iter()
@ -1264,17 +1358,19 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
} }
// An anonymous lifetime is legal here, go ahead. // An anonymous lifetime is legal here, go ahead.
LifetimeRibKind::AnonymousPassThrough(_, false) LifetimeRibKind::AnonymousPassThrough(_, false)
| LifetimeRibKind::AnonymousCreateParameter(_) => { | LifetimeRibKind::AnonymousCreateParameter { .. } => {
Some(LifetimeUseSet::One { use_span: ident.span, use_ctxt }) Some(LifetimeUseSet::One { use_span: ident.span, use_ctxt })
} }
_ => None, LifetimeRibKind::Generics { .. }
| LifetimeRibKind::ConstGeneric
| LifetimeRibKind::AnonConst => None,
}) })
.unwrap_or(LifetimeUseSet::Many); .unwrap_or(LifetimeUseSet::Many);
debug!(?use_ctxt, ?use_set); debug!(?use_ctxt, ?use_set);
v.insert(use_set); v.insert(use_set);
} }
Entry::Occupied(mut o) => { Entry::Occupied(mut o) => {
debug!("Many uses of {:?} at {:?}", region, ident.span); debug!("Many uses of {:?} at {:?}", res, ident.span);
*o.get_mut() = LifetimeUseSet::Many; *o.get_mut() = LifetimeUseSet::Many;
} }
} }
@ -1319,8 +1415,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
for i in (0..self.lifetime_ribs.len()).rev() { for i in (0..self.lifetime_ribs.len()).rev() {
let rib = &mut self.lifetime_ribs[i]; let rib = &mut self.lifetime_ribs[i];
match rib.kind { match rib.kind {
LifetimeRibKind::AnonymousCreateParameter(item_node_id) => { LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
self.create_fresh_lifetime(lifetime.id, lifetime.ident, item_node_id); let res = self.create_fresh_lifetime(lifetime.id, lifetime.ident, binder);
self.record_lifetime_res(lifetime.id, res);
return; return;
} }
LifetimeRibKind::AnonymousReportError => { LifetimeRibKind::AnonymousReportError => {
@ -1353,7 +1450,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
return; return;
} }
LifetimeRibKind::Item => break, LifetimeRibKind::Item => break,
_ => {} LifetimeRibKind::Generics { .. }
| LifetimeRibKind::ConstGeneric
| LifetimeRibKind::AnonConst => {}
} }
} }
// This resolution is wrong, it passes the work to HIR lifetime resolution. // This resolution is wrong, it passes the work to HIR lifetime resolution.
@ -1377,27 +1476,21 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
} }
#[tracing::instrument(level = "debug", skip(self))] #[tracing::instrument(level = "debug", skip(self))]
fn create_fresh_lifetime(&mut self, id: NodeId, ident: Ident, item_node_id: NodeId) { fn create_fresh_lifetime(&mut self, id: NodeId, ident: Ident, binder: NodeId) -> LifetimeRes {
debug_assert_eq!(ident.name, kw::UnderscoreLifetime); debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
debug!(?ident.span); debug!(?ident.span);
let item_def_id = self.r.local_def_id(item_node_id);
let def_node_id = self.r.next_node_id();
let def_id = self.r.create_def(
item_def_id,
def_node_id,
DefPathData::LifetimeNs(kw::UnderscoreLifetime),
self.parent_scope.expansion.to_expn_id(),
ident.span,
);
debug!(?def_id);
let region = LifetimeRes::Fresh { param: def_id, binder: item_node_id }; // Leave the responsibility to create the `LocalDefId` to lowering.
self.record_lifetime_res(id, region); let param = self.r.next_node_id();
self.r.extra_lifetime_params_map.entry(item_node_id).or_insert_with(Vec::new).push(( let res = LifetimeRes::Fresh { param, binder };
ident,
def_node_id, // Record the created lifetime parameter so lowering can pick it up and add it to HIR.
region, self.r
)); .extra_lifetime_params_map
.entry(binder)
.or_insert_with(Vec::new)
.push((ident, param, res));
res
} }
#[tracing::instrument(level = "debug", skip(self))] #[tracing::instrument(level = "debug", skip(self))]
@ -1447,52 +1540,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
| PathSource::Struct | PathSource::Struct
| PathSource::TupleStruct(..) => false, | PathSource::TupleStruct(..) => false,
}; };
let mut res = LifetimeRes::Error;
for rib in self.lifetime_ribs.iter().rev() {
match rib.kind {
// In create-parameter mode we error here because we don't want to support
// deprecated impl elision in new features like impl elision and `async fn`,
// both of which work using the `CreateParameter` mode:
//
// impl Foo for std::cell::Ref<u32> // note lack of '_
// async fn foo(_: std::cell::Ref<u32>) { ... }
LifetimeRibKind::AnonymousCreateParameter(_) => {
break;
}
// `PassThrough` is the normal case.
// `new_error_lifetime`, which would usually be used in the case of `ReportError`,
// is unsuitable here, as these can occur from missing lifetime parameters in a
// `PathSegment`, for which there is no associated `'_` or `&T` with no explicit
// lifetime. Instead, we simply create an implicit lifetime, which will be checked
// later, at which point a suitable error will be emitted.
LifetimeRibKind::AnonymousPassThrough(binder, _) => {
res = LifetimeRes::Anonymous { binder, elided: true };
break;
}
LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => {
// FIXME(cjgillot) This resolution is wrong, but this does not matter
// since these cases are erroneous anyway. Lifetime resolution should
// emit a "missing lifetime specifier" diagnostic.
res = LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true };
break;
}
_ => {}
}
}
let node_ids = self.r.next_node_ids(expected_lifetimes);
self.record_lifetime_res(
segment_id,
LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end },
);
for i in 0..expected_lifetimes {
let id = node_ids.start.plus(i);
self.record_lifetime_res(id, res);
}
if !missing {
continue;
}
let elided_lifetime_span = if segment.has_generic_args { let elided_lifetime_span = if segment.has_generic_args {
// If there are brackets, but not generic arguments, then use the opening bracket // If there are brackets, but not generic arguments, then use the opening bracket
@ -1503,7 +1550,59 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
// originating from macros, since the segment's span might be from a macro arg. // originating from macros, since the segment's span might be from a macro arg.
segment.ident.span.find_ancestor_inside(path_span).unwrap_or(path_span) segment.ident.span.find_ancestor_inside(path_span).unwrap_or(path_span)
}; };
if let LifetimeRes::Error = res { let ident = Ident::new(kw::UnderscoreLifetime, elided_lifetime_span);
let node_ids = self.r.next_node_ids(expected_lifetimes);
self.record_lifetime_res(
segment_id,
LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end },
);
if !missing {
// Do not create a parameter for patterns and expressions.
for rib in self.lifetime_ribs.iter().rev() {
match rib.kind {
LifetimeRibKind::AnonymousPassThrough(binder, _) => {
let res = LifetimeRes::Anonymous { binder, elided: true };
for id in node_ids {
self.record_lifetime_res(id, res);
}
break;
}
// `LifetimeRes::Error`, which would usually be used in the case of
// `ReportError`, is unsuitable here, as we don't emit an error yet. Instead,
// we simply resolve to an implicit lifetime, which will be checked later, at
// which point a suitable error will be emitted.
LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => {
// FIXME(cjgillot) This resolution is wrong, but this does not matter
// since these cases are erroneous anyway. Lifetime resolution should
// emit a "missing lifetime specifier" diagnostic.
let res =
LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true };
for id in node_ids {
self.record_lifetime_res(id, res);
}
break;
}
LifetimeRibKind::AnonymousCreateParameter { .. }
| LifetimeRibKind::Generics { .. }
| LifetimeRibKind::ConstGeneric
| LifetimeRibKind::AnonConst => {}
}
}
continue;
}
let mut should_lint = true;
for rib in self.lifetime_ribs.iter().rev() {
match rib.kind {
// In create-parameter mode we error here because we don't want to support
// deprecated impl elision in new features like impl elision and `async fn`,
// both of which work using the `CreateParameter` mode:
//
// impl Foo for std::cell::Ref<u32> // note lack of '_
// async fn foo(_: std::cell::Ref<u32>) { ... }
LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. } => {
let sess = self.r.session; let sess = self.r.session;
let mut err = rustc_errors::struct_span_err!( let mut err = rustc_errors::struct_span_err!(
sess, sess,
@ -1521,7 +1620,50 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
); );
err.note("assuming a `'static` lifetime..."); err.note("assuming a `'static` lifetime...");
err.emit(); err.emit();
} else { should_lint = false;
for id in node_ids {
self.record_lifetime_res(id, LifetimeRes::Error);
}
break;
}
// Do not create a parameter for patterns and expressions.
LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
for id in node_ids {
let res = self.create_fresh_lifetime(id, ident, binder);
self.record_lifetime_res(id, res);
}
break;
}
// `PassThrough` is the normal case.
LifetimeRibKind::AnonymousPassThrough(binder, _) => {
let res = LifetimeRes::Anonymous { binder, elided: true };
for id in node_ids {
self.record_lifetime_res(id, res);
}
break;
}
// `LifetimeRes::Error`, which would usually be used in the case of
// `ReportError`, is unsuitable here, as we don't emit an error yet. Instead,
// we simply resolve to an implicit lifetime, which will be checked later, at
// which point a suitable error will be emitted.
LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => {
// FIXME(cjgillot) This resolution is wrong, but this does not matter
// since these cases are erroneous anyway. Lifetime resolution should
// emit a "missing lifetime specifier" diagnostic.
let res = LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true };
for id in node_ids {
self.record_lifetime_res(id, res);
}
break;
}
LifetimeRibKind::Generics { .. }
| LifetimeRibKind::ConstGeneric
| LifetimeRibKind::AnonConst => {}
}
}
if should_lint {
self.r.lint_buffer.buffer_lint_with_diagnostic( self.r.lint_buffer.buffer_lint_with_diagnostic(
lint::builtin::ELIDED_LIFETIMES_IN_PATHS, lint::builtin::ELIDED_LIFETIMES_IN_PATHS,
segment_id, segment_id,
@ -1732,72 +1874,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|this| { |this| {
this.visit_generics(generics); this.visit_generics(generics);
walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits); walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits);
this.resolve_trait_items(items);
let walk_assoc_item =
|this: &mut Self,
generics: &Generics,
kind,
item: &'ast AssocItem| {
this.with_generic_param_rib(
&generics.params,
AssocItemRibKind,
LifetimeRibKind::Generics {
binder: item.id,
span: generics.span,
kind,
},
|this| {
visit::walk_assoc_item(this, item, AssocCtxt::Trait)
},
);
};
this.with_trait_items(items, |this| {
for item in items {
match &item.kind {
AssocItemKind::Const(_, ty, default) => {
this.visit_ty(ty);
// Only impose the restrictions of `ConstRibKind` for an
// actual constant expression in a provided default.
if let Some(expr) = default {
// We allow arbitrary const expressions inside of associated consts,
// even if they are potentially not const evaluatable.
//
// Type parameters can already be used and as associated consts are
// not used as part of the type system, this is far less surprising.
this.with_constant_rib(
IsRepeatExpr::No,
HasGenericParams::Yes,
None,
|this| this.visit_expr(expr),
);
}
}
AssocItemKind::Fn(box Fn { generics, .. }) => {
walk_assoc_item(
this,
generics,
LifetimeBinderKind::Function,
item,
);
}
AssocItemKind::TyAlias(box TyAlias {
generics,
..
}) => {
walk_assoc_item(
this,
generics,
LifetimeBinderKind::Item,
item,
);
}
AssocItemKind::MacCall(_) => {
panic!("unexpanded macro in resolve!")
}
};
}
});
}, },
); );
}, },
@ -2073,16 +2150,53 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
} }
/// When evaluating a `trait` use its associated types' idents for suggestions in E0412. /// When evaluating a `trait` use its associated types' idents for suggestions in E0412.
fn with_trait_items<T>( fn resolve_trait_items(&mut self, trait_items: &'ast [P<AssocItem>]) {
&mut self,
trait_items: &'ast [P<AssocItem>],
f: impl FnOnce(&mut Self) -> T,
) -> T {
let trait_assoc_items = let trait_assoc_items =
replace(&mut self.diagnostic_metadata.current_trait_assoc_items, Some(&trait_items)); replace(&mut self.diagnostic_metadata.current_trait_assoc_items, Some(&trait_items));
let result = f(self);
let walk_assoc_item =
|this: &mut Self, generics: &Generics, kind, item: &'ast AssocItem| {
this.with_generic_param_rib(
&generics.params,
AssocItemRibKind,
LifetimeRibKind::Generics { binder: item.id, span: generics.span, kind },
|this| visit::walk_assoc_item(this, item, AssocCtxt::Trait),
);
};
for item in trait_items {
match &item.kind {
AssocItemKind::Const(_, ty, default) => {
self.visit_ty(ty);
// Only impose the restrictions of `ConstRibKind` for an
// actual constant expression in a provided default.
if let Some(expr) = default {
// We allow arbitrary const expressions inside of associated consts,
// even if they are potentially not const evaluatable.
//
// Type parameters can already be used and as associated consts are
// not used as part of the type system, this is far less surprising.
self.with_constant_rib(
IsRepeatExpr::No,
HasGenericParams::Yes,
None,
|this| this.visit_expr(expr),
);
}
}
AssocItemKind::Fn(box Fn { generics, .. }) => {
walk_assoc_item(self, generics, LifetimeBinderKind::Function, item);
}
AssocItemKind::TyAlias(box TyAlias { generics, .. }) => {
walk_assoc_item(self, generics, LifetimeBinderKind::Item, item);
}
AssocItemKind::MacCall(_) => {
panic!("unexpanded macro in resolve!")
}
};
}
self.diagnostic_metadata.current_trait_assoc_items = trait_assoc_items; self.diagnostic_metadata.current_trait_assoc_items = trait_assoc_items;
result
} }
/// This is called to resolve a trait reference from an `impl` (i.e., `impl Trait for Foo`). /// This is called to resolve a trait reference from an `impl` (i.e., `impl Trait for Foo`).
@ -2140,12 +2254,28 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
) { ) {
debug!("resolve_implementation"); debug!("resolve_implementation");
// If applicable, create a rib for the type parameters. // If applicable, create a rib for the type parameters.
self.with_generic_param_rib(&generics.params, ItemRibKind(HasGenericParams::Yes), LifetimeRibKind::Generics { span: generics.span, binder: item_id, kind: LifetimeBinderKind::ImplBlock }, |this| { self.with_generic_param_rib(
&generics.params,
ItemRibKind(HasGenericParams::Yes),
LifetimeRibKind::Generics {
span: generics.span,
binder: item_id,
kind: LifetimeBinderKind::ImplBlock
},
|this| {
// Dummy self type for better errors if `Self` is used in the trait path. // Dummy self type for better errors if `Self` is used in the trait path.
this.with_self_rib(Res::SelfTy { trait_: None, alias_to: None }, |this| { this.with_self_rib(Res::SelfTy { trait_: None, alias_to: None }, |this| {
this.with_lifetime_rib(LifetimeRibKind::AnonymousCreateParameter(item_id), |this| { this.with_lifetime_rib(
LifetimeRibKind::AnonymousCreateParameter {
binder: item_id,
report_in_path: true
},
|this| {
// Resolve the trait reference, if necessary. // Resolve the trait reference, if necessary.
this.with_optional_trait_ref(opt_trait_reference.as_ref(), self_type, |this, trait_id| { this.with_optional_trait_ref(
opt_trait_reference.as_ref(),
self_type,
|this, trait_id| {
let item_def_id = this.r.local_def_id(item_id); let item_def_id = this.r.local_def_id(item_id);
// Register the trait definitions from here. // Register the trait definitions from here.
@ -2154,8 +2284,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
} }
let item_def_id = item_def_id.to_def_id(); let item_def_id = item_def_id.to_def_id();
let res = let res = Res::SelfTy {
Res::SelfTy { trait_: trait_id, alias_to: Some((item_def_id, false)) }; trait_: trait_id,
alias_to: Some((item_def_id, false)),
};
this.with_self_rib(res, |this| { this.with_self_rib(res, |this| {
if let Some(trait_ref) = opt_trait_reference.as_ref() { if let Some(trait_ref) = opt_trait_reference.as_ref() {
// Resolve type arguments in the trait path. // Resolve type arguments in the trait path.
@ -2173,13 +2305,30 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| { this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| {
debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)"); debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)");
for item in impl_items { for item in impl_items {
this.resolve_impl_item(&**item);
}
});
});
},
);
});
},
);
},
);
});
},
);
}
fn resolve_impl_item(&mut self, item: &'ast AssocItem) {
use crate::ResolutionError::*; use crate::ResolutionError::*;
match &item.kind { match &item.kind {
AssocItemKind::Const(_default, _ty, _expr) => { AssocItemKind::Const(_, ty, default) => {
debug!("resolve_implementation AssocItemKind::Const"); debug!("resolve_implementation AssocItemKind::Const");
// If this is a trait impl, ensure the const // If this is a trait impl, ensure the const
// exists in trait // exists in trait
this.check_trait_item( self.check_trait_item(
item.id, item.id,
item.ident, item.ident,
&item.kind, &item.kind,
@ -2188,31 +2337,29 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|i, s, c| ConstNotMemberOfTrait(i, s, c), |i, s, c| ConstNotMemberOfTrait(i, s, c),
); );
self.visit_ty(ty);
if let Some(expr) = default {
// We allow arbitrary const expressions inside of associated consts, // We allow arbitrary const expressions inside of associated consts,
// even if they are potentially not const evaluatable. // even if they are potentially not const evaluatable.
// //
// Type parameters can already be used and as associated consts are // Type parameters can already be used and as associated consts are
// not used as part of the type system, this is far less surprising. // not used as part of the type system, this is far less surprising.
this.with_constant_rib( self.with_constant_rib(IsRepeatExpr::No, HasGenericParams::Yes, None, |this| {
IsRepeatExpr::No, this.visit_expr(expr)
HasGenericParams::Yes, });
None, }
|this| {
visit::walk_assoc_item(
this,
item,
AssocCtxt::Impl,
)
},
);
} }
AssocItemKind::Fn(box Fn { generics, .. }) => { AssocItemKind::Fn(box Fn { generics, .. }) => {
debug!("resolve_implementation AssocItemKind::Fn"); debug!("resolve_implementation AssocItemKind::Fn");
// We also need a new scope for the impl item type parameters. // We also need a new scope for the impl item type parameters.
this.with_generic_param_rib( self.with_generic_param_rib(
&generics.params, &generics.params,
AssocItemRibKind, AssocItemRibKind,
LifetimeRibKind::Generics { binder: item.id, span: generics.span, kind: LifetimeBinderKind::Function }, LifetimeRibKind::Generics {
binder: item.id,
span: generics.span,
kind: LifetimeBinderKind::Function,
},
|this| { |this| {
// If this is a trait impl, ensure the method // If this is a trait impl, ensure the method
// exists in trait // exists in trait
@ -2225,23 +2372,21 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|i, s, c| MethodNotMemberOfTrait(i, s, c), |i, s, c| MethodNotMemberOfTrait(i, s, c),
); );
visit::walk_assoc_item( visit::walk_assoc_item(this, item, AssocCtxt::Impl)
this,
item,
AssocCtxt::Impl,
)
}, },
); );
} }
AssocItemKind::TyAlias(box TyAlias { AssocItemKind::TyAlias(box TyAlias { generics, .. }) => {
generics, ..
}) => {
debug!("resolve_implementation AssocItemKind::TyAlias"); debug!("resolve_implementation AssocItemKind::TyAlias");
// We also need a new scope for the impl item type parameters. // We also need a new scope for the impl item type parameters.
this.with_generic_param_rib( self.with_generic_param_rib(
&generics.params, &generics.params,
AssocItemRibKind, AssocItemRibKind,
LifetimeRibKind::Generics { binder: item.id, span: generics.span, kind: LifetimeBinderKind::Item }, LifetimeRibKind::Generics {
binder: item.id,
span: generics.span,
kind: LifetimeBinderKind::Item,
},
|this| { |this| {
// If this is a trait impl, ensure the type // If this is a trait impl, ensure the type
// exists in trait // exists in trait
@ -2254,11 +2399,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|i, s, c| TypeNotMemberOfTrait(i, s, c), |i, s, c| TypeNotMemberOfTrait(i, s, c),
); );
visit::walk_assoc_item( visit::walk_assoc_item(this, item, AssocCtxt::Impl)
this,
item,
AssocCtxt::Impl,
)
}, },
); );
} }
@ -2267,16 +2408,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
} }
} }
} }
});
});
},
);
});
});
});
});
});
}
fn check_trait_item<F>( fn check_trait_item<F>(
&mut self, &mut self,

View File

@ -2242,9 +2242,18 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
] ]
.contains(&Some(did)) .contains(&Some(did))
{ {
let (span, span_type) = match &trait_ref.bound_generic_params { let (span, span_type) = if let Some(bound) =
[] => (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty), trait_ref.bound_generic_params.iter().rfind(|param| {
[.., bound] => (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail), matches!(
param.kind,
hir::GenericParamKind::Lifetime {
kind: hir::LifetimeParamKind::Explicit
}
)
}) {
(bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail)
} else {
(trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty)
}; };
self.missing_named_lifetime_spots self.missing_named_lifetime_spots
.push(MissingLifetimeSpot::HigherRanked { span, span_type }); .push(MissingLifetimeSpot::HigherRanked { span, span_type });

View File

@ -29,8 +29,6 @@ use std::cell::Cell;
use std::fmt; use std::fmt;
use std::mem::take; use std::mem::take;
use tracing::{debug, span, Level};
trait RegionExt { trait RegionExt {
fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region); fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region);
@ -572,41 +570,38 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}); });
} }
fn visit_fn( fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
&mut self, if let hir::ExprKind::Closure { bound_generic_params, .. } = e.kind {
fk: intravisit::FnKind<'tcx>, let next_early_index = self.next_early_index();
fd: &'tcx hir::FnDecl<'tcx>, let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) =
b: hir::BodyId, bound_generic_params
s: rustc_span::Span, .iter()
hir_id: hir::HirId, .filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
) { .enumerate()
let name = match fk { .map(|(late_bound_idx, param)| {
intravisit::FnKind::ItemFn(id, _, _) => id.name, let pair = Region::late(late_bound_idx as u32, self.tcx.hir(), param);
intravisit::FnKind::Method(id, _) => id.name, let r = late_region_as_bound_region(self.tcx, &pair.1);
intravisit::FnKind::Closure => sym::closure, (pair, r)
}; })
let name = name.as_str(); .unzip();
let span = span!(Level::DEBUG, "visit_fn", name); self.map.late_bound_vars.insert(e.hir_id, binders);
let _enter = span.enter();
match fk {
// Any `Binders` are handled elsewhere
intravisit::FnKind::ItemFn(..) | intravisit::FnKind::Method(..) => {
intravisit::walk_fn(self, fk, fd, b, s, hir_id)
}
intravisit::FnKind::Closure => {
self.map.late_bound_vars.insert(hir_id, vec![]);
let scope = Scope::Binder { let scope = Scope::Binder {
hir_id, hir_id: e.hir_id,
lifetimes: FxIndexMap::default(), lifetimes,
next_early_index: self.next_early_index(),
s: self.scope, s: self.scope,
next_early_index,
opaque_type_parent: false, opaque_type_parent: false,
scope_type: BinderScopeType::Normal, scope_type: BinderScopeType::Normal,
allow_late_bound: true, allow_late_bound: true,
where_bound_origin: None, where_bound_origin: None,
}; };
self.with(scope, move |this| intravisit::walk_fn(this, fk, fd, b, s, hir_id)); self.with(scope, |this| {
} // a closure has no bounds, so everything
// contained within is scoped within its binder.
intravisit::walk_expr(this, e)
});
} else {
intravisit::walk_expr(self, e)
} }
} }
@ -755,7 +750,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
let next_early_index = self.next_early_index(); let next_early_index = self.next_early_index();
let lifetime_span: Option<Span> = let lifetime_span: Option<Span> =
c.generic_params.iter().rev().find_map(|param| match param.kind { c.generic_params.iter().rev().find_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => Some(param.span), GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit } => {
Some(param.span)
}
_ => None, _ => None,
}); });
let (span, span_type) = if let Some(span) = lifetime_span { let (span, span_type) = if let Some(span) = lifetime_span {

View File

@ -2920,13 +2920,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
) { ) {
for br in referenced_regions.difference(&constrained_regions) { for br in referenced_regions.difference(&constrained_regions) {
let br_name = match *br { let br_name = match *br {
ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) | ty::BrEnv => {
"an anonymous lifetime".to_string()
}
ty::BrNamed(_, name) => format!("lifetime `{}`", name), ty::BrNamed(_, name) => format!("lifetime `{}`", name),
ty::BrAnon(_) | ty::BrEnv => "an anonymous lifetime".to_string(),
}; };
let mut err = generate_err(&br_name); let mut err = generate_err(&br_name);
if let ty::BrAnon(_) = *br { if let ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) = *br {
// The only way for an anonymous lifetime to wind up // The only way for an anonymous lifetime to wind up
// in the return type but **also** be unconstrained is // in the return type but **also** be unconstrained is
// if it only appears in "associated types" in the // if it only appears in "associated types" in the

View File

@ -628,13 +628,30 @@ fn compare_number_of_generics<'tcx>(
let mut err_occurred = None; let mut err_occurred = None;
for (kind, trait_count, impl_count) in matchings { for (kind, trait_count, impl_count) in matchings {
if impl_count != trait_count { if impl_count != trait_count {
let arg_spans = |kind: ty::AssocKind, generics: &hir::Generics<'_>| {
let mut spans = generics
.params
.iter()
.filter(|p| match p.kind {
hir::GenericParamKind::Lifetime {
kind: hir::LifetimeParamKind::Elided,
} => {
// A fn can have an arbitrary number of extra elided lifetimes for the
// same signature.
!matches!(kind, ty::AssocKind::Fn)
}
_ => true,
})
.map(|p| p.span)
.collect::<Vec<Span>>();
if spans.is_empty() {
spans = vec![generics.span]
}
spans
};
let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() { let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() {
let trait_item = tcx.hir().expect_trait_item(def_id); let trait_item = tcx.hir().expect_trait_item(def_id);
if trait_item.generics.params.is_empty() { let arg_spans: Vec<Span> = arg_spans(trait_.kind, trait_item.generics);
(Some(vec![trait_item.generics.span]), vec![])
} else {
let arg_spans: Vec<Span> =
trait_item.generics.params.iter().map(|p| p.span).collect();
let impl_trait_spans: Vec<Span> = trait_item let impl_trait_spans: Vec<Span> = trait_item
.generics .generics
.params .params
@ -645,7 +662,6 @@ fn compare_number_of_generics<'tcx>(
}) })
.collect(); .collect();
(Some(arg_spans), impl_trait_spans) (Some(arg_spans), impl_trait_spans)
}
} else { } else {
(trait_span.map(|s| vec![s]), vec![]) (trait_span.map(|s| vec![s]), vec![])
}; };
@ -660,23 +676,7 @@ fn compare_number_of_generics<'tcx>(
_ => None, _ => None,
}) })
.collect(); .collect();
let spans = if impl_item.generics.params.is_empty() { let spans = arg_spans(impl_.kind, impl_item.generics);
vec![impl_item.generics.span]
} else {
impl_item
.generics
.params
.iter()
.filter(|p| {
matches!(
p.kind,
hir::GenericParamKind::Type { .. }
| hir::GenericParamKind::Const { .. }
)
})
.map(|p| p.span)
.collect::<Vec<Span>>()
};
let span = spans.first().copied(); let span = spans.first().copied();
let mut err = tcx.sess.struct_span_err_with_code( let mut err = tcx.sess.struct_span_err_with_code(

View File

@ -222,10 +222,15 @@ impl<'tcx> Clean<'tcx, Option<Lifetime>> for ty::Region<'tcx> {
match **self { match **self {
ty::ReStatic => Some(Lifetime::statik()), ty::ReStatic => Some(Lifetime::statik()),
ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) => { ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) => {
Some(Lifetime(name)) if name != kw::UnderscoreLifetime { Some(Lifetime(name)) } else { None }
}
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(..)
@ -530,29 +535,25 @@ fn clean_generic_param<'tcx>(
GenericParamDef { name, kind } GenericParamDef { name, kind }
} }
impl<'tcx> Clean<'tcx, Generics> for hir::Generics<'tcx> { /// Synthetic type-parameters are inserted after normal ones.
fn clean(&self, cx: &mut DocContext<'tcx>) -> Generics { /// In order for normal parameters to be able to refer to synthetic ones,
// Synthetic type-parameters are inserted after normal ones. /// scans them first.
// In order for normal parameters to be able to refer to synthetic ones, fn is_impl_trait(param: &hir::GenericParam<'_>) -> bool {
// scans them first.
fn is_impl_trait(param: &hir::GenericParam<'_>) -> bool {
match param.kind { match param.kind {
hir::GenericParamKind::Type { synthetic, .. } => synthetic, hir::GenericParamKind::Type { synthetic, .. } => synthetic,
_ => false, _ => false,
} }
} }
/// This can happen for `async fn`, e.g. `async fn f<'_>(&'_ self)`.
///
/// See [`lifetime_to_generic_param`] in [`rustc_ast_lowering`] for more information.
///
/// [`lifetime_to_generic_param`]: rustc_ast_lowering::LoweringContext::lifetime_to_generic_param
fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
matches!(
param.kind,
hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided }
)
}
/// This can happen for `async fn`, e.g. `async fn f<'_>(&'_ self)`.
///
/// See `lifetime_to_generic_param` in `rustc_ast_lowering` for more information.
fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
matches!(param.kind, hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided })
}
impl<'tcx> Clean<'tcx, Generics> for hir::Generics<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> Generics {
let impl_trait_params = self let impl_trait_params = self
.params .params
.iter() .iter()
@ -991,6 +992,7 @@ impl<'tcx> Clean<'tcx, PolyTrait> for hir::PolyTraitRef<'tcx> {
generic_params: self generic_params: self
.bound_generic_params .bound_generic_params
.iter() .iter()
.filter(|p| !is_elided_lifetime(p))
.map(|x| clean_generic_param(cx, None, x)) .map(|x| clean_generic_param(cx, None, x))
.collect(), .collect(),
} }
@ -1865,8 +1867,12 @@ impl<'tcx> Clean<'tcx, BareFunctionDecl> for hir::BareFnTy<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> BareFunctionDecl { fn clean(&self, cx: &mut DocContext<'tcx>) -> BareFunctionDecl {
let (generic_params, decl) = enter_impl_trait(cx, |cx| { let (generic_params, decl) = enter_impl_trait(cx, |cx| {
// NOTE: generics must be cleaned before args // NOTE: generics must be cleaned before args
let generic_params = let generic_params = self
self.generic_params.iter().map(|x| clean_generic_param(cx, None, x)).collect(); .generic_params
.iter()
.filter(|p| !is_elided_lifetime(p))
.map(|x| clean_generic_param(cx, None, x))
.collect();
let args = clean_args_from_types_and_names(cx, self.decl.inputs, self.param_names); let args = clean_args_from_types_and_names(cx, self.decl.inputs, self.param_names);
let decl = clean_fn_decl_with_args(cx, self.decl, args); let decl = clean_fn_decl_with_args(cx, self.decl, args);
(generic_params, decl) (generic_params, decl)

View File

@ -84,12 +84,9 @@ pub(crate) fn substs_to_args<'tcx>(
let mut ret_val = let mut ret_val =
Vec::with_capacity(substs.len().saturating_sub(if skip_first { 1 } else { 0 })); Vec::with_capacity(substs.len().saturating_sub(if skip_first { 1 } else { 0 }));
ret_val.extend(substs.iter().filter_map(|kind| match kind.unpack() { ret_val.extend(substs.iter().filter_map(|kind| match kind.unpack() {
GenericArgKind::Lifetime(lt) => match *lt { GenericArgKind::Lifetime(lt) => {
ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrAnon(_), .. }) => { Some(GenericArg::Lifetime(lt.clean(cx).unwrap_or(Lifetime::elided())))
Some(GenericArg::Lifetime(Lifetime::elided()))
} }
_ => lt.clean(cx).map(GenericArg::Lifetime),
},
GenericArgKind::Type(_) if skip_first => { GenericArgKind::Type(_) if skip_first => {
skip_first = false; skip_first = false;
None None

View File

@ -45,7 +45,7 @@ where
} }
fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'_>> { fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'_>> {
//~^ ERROR: missing lifetime specifier //~^ ERROR `'_` cannot be used here [E0637]
//~| ERROR: missing lifetime specifier //~| ERROR: missing lifetime specifier
DocumentImpl {} DocumentImpl {}
} }

View File

@ -1,14 +1,8 @@
error[E0106]: missing lifetime specifier error[E0637]: `'_` cannot be used here
--> $DIR/issue-70304.rs:47:41 --> $DIR/issue-70304.rs:47:41
| |
LL | fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'_>> { LL | fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'_>> {
| ^^ expected named lifetime parameter | ^^ `'_` is a reserved lifetime name
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime
|
LL | fn create_doc() -> impl Document<Cursor<'static> = DocCursorImpl<'_>> {
| ~~~~~~~
error[E0106]: missing lifetime specifier error[E0106]: missing lifetime specifier
--> $DIR/issue-70304.rs:47:61 --> $DIR/issue-70304.rs:47:61
@ -24,4 +18,5 @@ LL | fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'static>> {
error: aborting due to 2 previous errors error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0106`. Some errors have detailed explanations: E0106, E0637.
For more information about an error, try `rustc --explain E0106`.

View File

@ -9,7 +9,7 @@ trait Foo {
} }
fn foo(x: &impl Foo<Item<'_> = u32>) { } fn foo(x: &impl Foo<Item<'_> = u32>) { }
//~^ ERROR missing lifetime specifier //~^ ERROR `'_` cannot be used here [E0637]
fn bar(x: &impl for<'a> Foo<Item<'a> = &'_ u32>) { } fn bar(x: &impl for<'a> Foo<Item<'a> = &'_ u32>) { }
//~^ ERROR missing lifetime specifier //~^ ERROR missing lifetime specifier

View File

@ -1,13 +1,8 @@
error[E0106]: missing lifetime specifier error[E0637]: `'_` cannot be used here
--> $DIR/issue-95305.rs:11:26 --> $DIR/issue-95305.rs:11:26
| |
LL | fn foo(x: &impl Foo<Item<'_> = u32>) { } LL | fn foo(x: &impl Foo<Item<'_> = u32>) { }
| ^^ expected named lifetime parameter | ^^ `'_` is a reserved lifetime name
|
help: consider introducing a named lifetime parameter
|
LL | fn foo<'a>(x: &impl Foo<Item<'a> = u32>) { }
| ++++ ~~
error[E0106]: missing lifetime specifier error[E0106]: missing lifetime specifier
--> $DIR/issue-95305.rs:14:41 --> $DIR/issue-95305.rs:14:41
@ -22,4 +17,5 @@ LL | fn bar(x: &impl for<'a> Foo<Item<'a> = &'a u32>) { }
error: aborting due to 2 previous errors error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0106`. Some errors have detailed explanations: E0106, E0637.
For more information about an error, try `rustc --explain E0106`.

View File

@ -8,7 +8,7 @@ LL | type A = u32;
| ^ lifetimes do not match type in trait | ^ lifetimes do not match type in trait
error[E0049]: type `B` has 1 type parameter but its trait declaration has 0 type parameters error[E0049]: type `B` has 1 type parameter but its trait declaration has 0 type parameters
--> $DIR/parameter_number_and_kind_impl.rs:17:16 --> $DIR/parameter_number_and_kind_impl.rs:17:12
| |
LL | type B<'a, 'b>; LL | type B<'a, 'b>;
| -- -- | -- --
@ -16,7 +16,9 @@ LL | type B<'a, 'b>;
| expected 0 type parameters | expected 0 type parameters
... ...
LL | type B<'a, T> = Vec<T>; LL | type B<'a, T> = Vec<T>;
| ^ found 1 type parameter | ^^ ^
| |
| found 1 type parameter
error[E0195]: lifetime parameters or bounds on type `C` do not match the trait declaration error[E0195]: lifetime parameters or bounds on type `C` do not match the trait declaration
--> $DIR/parameter_number_and_kind_impl.rs:19:11 --> $DIR/parameter_number_and_kind_impl.rs:19:11

View File

@ -23,7 +23,7 @@ error[E0308]: mismatched types
LL | foo(bar, "string", |s| s.len() == 5); LL | foo(bar, "string", |s| s.len() == 5);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
| |
= note: expected trait `FnOnce<(&&str,)>` = note: expected trait `for<'r, 's> FnOnce<(&'r &'s str,)>`
found trait `for<'r> FnOnce<(&'r &str,)>` found trait `for<'r> FnOnce<(&'r &str,)>`
note: this closure does not fulfill the lifetime requirements note: this closure does not fulfill the lifetime requirements
--> $DIR/issue-71955.rs:45:24 --> $DIR/issue-71955.rs:45:24
@ -61,7 +61,7 @@ error[E0308]: mismatched types
LL | foo(baz, "string", |s| s.0.len() == 5); LL | foo(baz, "string", |s| s.0.len() == 5);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
| |
= note: expected trait `FnOnce<(&Wrapper<'_>,)>` = note: expected trait `for<'r, 's> FnOnce<(&'r Wrapper<'s>,)>`
found trait `for<'r> FnOnce<(&'r Wrapper<'_>,)>` found trait `for<'r> FnOnce<(&'r Wrapper<'_>,)>`
note: this closure does not fulfill the lifetime requirements note: this closure does not fulfill the lifetime requirements
--> $DIR/issue-71955.rs:48:24 --> $DIR/issue-71955.rs:48:24

View File

@ -6,8 +6,8 @@ trait SomeTrait<'a> {
fn give_me_ice<T>() { fn give_me_ice<T>() {
callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>(); callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
//~^ ERROR the trait bound `T: SomeTrait<'_>` is not satisfied [E0277] //~^ ERROR the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied [E0277]
//~| ERROR the trait bound `T: SomeTrait<'_>` is not satisfied [E0277] //~| ERROR the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied [E0277]
} }
fn callee<T: Fn<(&'static (),)>>() { fn callee<T: Fn<(&'static (),)>>() {

View File

@ -1,24 +1,24 @@
error[E0277]: the trait bound `T: SomeTrait<'_>` is not satisfied error[E0277]: the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied
--> $DIR/issue-85455.rs:8:5 --> $DIR/issue-85455.rs:8:5
| |
LL | callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>(); LL | callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `SomeTrait<'_>` is not implemented for `T` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'r> SomeTrait<'r>` is not implemented for `T`
| |
help: consider restricting type parameter `T` help: consider restricting type parameter `T`
| |
LL | fn give_me_ice<T: SomeTrait<'_>>() { LL | fn give_me_ice<T: for<'r> SomeTrait<'r>>() {
| +++++++++++++++ | +++++++++++++++++++++++
error[E0277]: the trait bound `T: SomeTrait<'_>` is not satisfied error[E0277]: the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied
--> $DIR/issue-85455.rs:8:14 --> $DIR/issue-85455.rs:8:14
| |
LL | callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>(); LL | callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `SomeTrait<'_>` is not implemented for `T` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'r> SomeTrait<'r>` is not implemented for `T`
| |
help: consider restricting type parameter `T` help: consider restricting type parameter `T`
| |
LL | fn give_me_ice<T: SomeTrait<'_>>() { LL | fn give_me_ice<T: for<'r> SomeTrait<'r>>() {
| +++++++++++++++ | +++++++++++++++++++++++
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View File

@ -13,6 +13,10 @@ impl StaticTrait for Box<dyn Debug> { }
trait NotStaticTrait { } trait NotStaticTrait { }
impl NotStaticTrait for Box<dyn Debug + '_> { } impl NotStaticTrait for Box<dyn Debug + '_> { }
// Check that we don't err when the trait has a lifetime parameter.
trait TraitWithLifetime<'a> { }
impl NotStaticTrait for &dyn TraitWithLifetime<'_> { }
fn static_val<T: StaticTrait>(_: T) { fn static_val<T: StaticTrait>(_: T) {
} }

View File

@ -1,5 +1,5 @@
error[E0521]: borrowed data escapes outside of function error[E0521]: borrowed data escapes outside of function
--> $DIR/dyn-trait.rs:20:5 --> $DIR/dyn-trait.rs:24:5
| |
LL | fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) { LL | fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) {
| -- - `x` is a reference that is only valid in the function body | -- - `x` is a reference that is only valid in the function body

View File

@ -0,0 +1,13 @@
// check-pass
struct Foo<'a> {
x: &'a (),
}
// The lifetime in pattern-position `Foo` is elided.
// Verify that lowering does not create an independent lifetime parameter for it.
fn foo<'a>(Foo { x }: Foo<'a>) {
*x
}
fn main() {}

View File

@ -10,7 +10,7 @@ LL | y.push(z);
| |
help: consider introducing a named lifetime parameter help: consider introducing a named lifetime parameter
| |
LL | fn foo<'a>(x:Box<dyn Fn(&'a u8, &'a u8)> , y: Vec<&u8>, z: &u8) { LL | fn foo<'a>(x:Box<dyn Fn(&u8, &u8)> , y: Vec<&'a u8>, z: &'a u8) {
| ++++ ++ ++ | ++++ ++ ++
error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable