From 32af719b07217ff89e61a2031500cee138599baa Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 11 May 2022 22:49:39 +0200 Subject: [PATCH] Always create parameters for functions-like types. --- compiler/rustc_ast_lowering/src/lib.rs | 60 ++++-- compiler/rustc_ast_lowering/src/path.rs | 51 ++--- compiler/rustc_hir/src/def.rs | 3 +- compiler/rustc_resolve/src/late.rs | 193 +++++++++++++----- .../rustc_resolve/src/late/diagnostics.rs | 15 +- compiler/rustc_resolve/src/late/lifetimes.rs | 4 +- compiler/rustc_typeck/src/astconv/mod.rs | 6 +- .../rustc_typeck/src/check/compare_method.rs | 66 +++--- .../generic-associated-types/issue-70304.rs | 2 +- .../issue-70304.stderr | 13 +- .../generic-associated-types/issue-95305.rs | 2 +- .../issue-95305.stderr | 12 +- .../parameter_number_and_kind_impl.stderr | 6 +- .../normalize-under-binder/issue-71955.stderr | 4 +- .../normalize-under-binder/issue-85455.rs | 4 +- .../normalize-under-binder/issue-85455.stderr | 16 +- .../impl-header-lifetime-elision/dyn-trait.rs | 4 + .../dyn-trait.stderr | 2 +- .../elided-lifetime-in-path-in-pat.rs | 13 ++ ...th-anon-regions-using-trait-objects.stderr | 4 +- 20 files changed, 303 insertions(+), 177 deletions(-) create mode 100644 src/test/ui/lifetimes/elided-lifetime-in-path-in-pat.rs diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 271ead78c5b..e8b92eaad5c 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -223,6 +223,12 @@ impl ResolverAstLoweringExt for ResolverAstLowering { } /// 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)> { 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. + #[tracing::instrument(level = "debug", skip(self))] fn lifetime_res_to_generic_param( &mut self, ident: Ident, @@ -787,11 +794,25 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// Register a binder to be ignored for lifetime capture. #[tracing::instrument(level = "debug", skip(self, f))] #[inline] - fn with_lifetime_binder(&mut self, binder: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { + fn with_lifetime_binder( + &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 { ctxt.binders_to_ignore.insert(binder); } - let ret = f(self); + let ret = f(self, generic_params); if let Some(ctxt) = &mut self.captured_lifetimes { ctxt.binders_to_ignore.remove(&binder); } @@ -1188,15 +1209,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let lifetime = self.lower_lifetime(®ion); hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx)) } - TyKind::BareFn(ref f) => self.with_lifetime_binder(t.id, |this| { - hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy { - generic_params: this.lower_generic_params(&f.generic_params), - unsafety: this.lower_unsafety(f.unsafety), - abi: this.lower_extern(f.ext), - decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None), - param_names: this.lower_fn_params_to_names(&f.decl), - })) - }), + TyKind::BareFn(ref f) => { + self.with_lifetime_binder(t.id, &f.generic_params, |this, generic_params| { + hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy { + generic_params, + unsafety: this.lower_unsafety(f.unsafety), + abi: this.lower_extern(f.ext), + decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None), + param_names: this.lower_fn_params_to_names(&f.decl), + })) + }) + } TyKind::Never => hir::TyKind::Never, TyKind::Tup(ref tys) => hir::TyKind::Tup( self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))), @@ -1963,13 +1986,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { p: &PolyTraitRef, itctx: ImplTraitContext, ) -> hir::PolyTraitRef<'hir> { - let bound_generic_params = self.lower_generic_params(&p.bound_generic_params); - - let trait_ref = self.with_lifetime_binder(p.trait_ref.ref_id, |this| { - this.lower_trait_ref(&p.trait_ref, itctx) - }); - - hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) } + self.with_lifetime_binder( + p.trait_ref.ref_id, + &p.bound_generic_params, + |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) } + }, + ) } fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> { diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index bd95b5850df..52ba5daf014 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -191,9 +191,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.lower_angle_bracketed_parameter_data(data, param_mode, itctx) } GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args { - ParenthesizedGenericArgs::Ok => { - self.lower_parenthesized_parameter_data(segment.id, data) - } + ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data), ParenthesizedGenericArgs::Err => { let mut err = struct_span_err!(self.sess, data.span, E0214, "{}", msg); err.span_label(data.span, "only `Fn` traits may use parentheses"); @@ -351,7 +349,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_parenthesized_parameter_data( &mut self, - id: NodeId, data: &ParenthesizedArgs, ) -> (GenericArgsCtor<'hir>, bool) { // Switch to `PassThrough` mode for anonymous lifetimes; this @@ -359,31 +356,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // a hidden lifetime parameter. This is needed for backwards // compatibility, even in contexts like an impl header where // we generally don't permit such things (see #51008). - self.with_lifetime_binder(id, |this| { - let ParenthesizedArgs { span, inputs, inputs_span, output } = data; - let inputs = this.arena.alloc_from_iter(inputs.iter().map(|ty| { - this.lower_ty_direct( - ty, - ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam), - ) - })); - let output_ty = match output { - FnRetTy::Ty(ty) => this - .lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)), - FnRetTy::Default(_) => this.arena.alloc(this.ty_tup(*span, &[])), - }; - let args = smallvec![GenericArg::Type(this.ty_tup(*inputs_span, inputs))]; - let binding = this.output_ty_binding(output_ty.span, output_ty); - ( - GenericArgsCtor { - args, - bindings: arena_vec![this; binding], - parenthesized: true, - span: data.inputs_span, - }, - false, - ) - }) + let ParenthesizedArgs { span, inputs, inputs_span, output } = data; + let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| { + self.lower_ty_direct(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam)) + })); + let output_ty = match output { + FnRetTy::Ty(ty) => { + self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)) + } + FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])), + }; + let args = smallvec![GenericArg::Type(self.ty_tup(*inputs_span, inputs))]; + let binding = self.output_ty_binding(output_ty.span, output_ty); + ( + GenericArgsCtor { + args, + bindings: arena_vec![self; binding], + parenthesized: true, + span: data.inputs_span, + }, + false, + ) } /// An associated type binding `Output = $ty`. diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index a111355c528..d0893cd09d8 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -722,8 +722,7 @@ pub enum LifetimeRes { /// Id of the introducing place. That can be: /// - an item's id, for the item's generic parameters; /// - a TraitRef's ref_id, identifying the `for<...>` binder; - /// - a BareFn type's id; - /// - a Path's id when this path has parenthesized generic args. + /// - a BareFn type's id. /// /// This information is used for impl-trait lifetime captures, to know when to or not to /// capture any given lifetime. diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index abccb94a906..08d6134237a 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -21,7 +21,6 @@ use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_hir::{PrimTy, TraitCandidate}; -use rustc_index::vec::Idx; use rustc_middle::ty::DefIdTree; use rustc_middle::{bug, span_bug}; use rustc_session::lint; @@ -240,9 +239,16 @@ enum LifetimeRibKind { /// Create a new anonymous lifetime parameter and reference it. /// /// If `report_in_path`, report an error when encountering lifetime elision in a path: - /// ```ignore - /// struct Foo<'a> { .. } - /// fn foo(x: Foo) {} + /// ```compile_fail + /// struct Foo<'a> { x: &'a () } + /// async fn foo(x: Foo) {} + /// ``` + /// + /// Note: the error should not trigger when the elided lifetime is in a pattern or + /// expression-position path: + /// ``` + /// struct Foo<'a> { x: &'a () } + /// async fn foo(Foo { x: _ }: Foo<'_>) {} /// ``` AnonymousCreateParameter { binder: NodeId, report_in_path: bool }, @@ -634,7 +640,10 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { |this| { this.visit_generic_params(&bare_fn.generic_params, false); 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.with_lifetime_rib( @@ -720,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. FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _) | 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 // they are not possible for foreign or bodiless functions. self.with_lifetime_rib( LifetimeRibKind::AnonymousPassThrough(fn_id, false), - |this| { - this.visit_fn_header(&sig.header); - this.visit_generics(generics); - walk_list!(this, visit_param, &sig.decl.inputs); - }, + |this| walk_list!(this, visit_param, &sig.decl.inputs), ); self.with_lifetime_rib( LifetimeRibKind::AnonymousPassThrough(fn_id, true), @@ -761,15 +768,18 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // 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( - if async_node_id.is_some() { - LifetimeRibKind::AnonymousCreateParameter { - binder: fn_id, - report_in_path: true, - } - } else { - LifetimeRibKind::AnonymousPassThrough(fn_id, false) - }, + rib, // Add each argument to the rib. |this| this.resolve_params(&declaration.inputs), ); @@ -937,19 +947,66 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { 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) { if let Some(ref args) = path_segment.args { match &**args { GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, path_span, args), - GenericArgs::Parenthesized(ref data) => { - self.with_lifetime_rib( - LifetimeRibKind::AnonymousPassThrough(path_segment.id, false), - |this| walk_list!(this, visit_ty, &data.inputs), - ); - self.with_lifetime_rib( - LifetimeRibKind::AnonymousPassThrough(path_segment.id, true), - |this| visit::walk_fn_ret_ty(this, &data.output), - ) + 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( + LifetimeRibKind::AnonymousCreateParameter { + binder, + report_in_path: false, + }, + |this| walk_list!(this, visit_ty, &p_args.inputs), + ); + self.with_lifetime_rib( + LifetimeRibKind::AnonymousPassThrough(binder, true), + |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 => {} + } + } } } } @@ -1474,7 +1531,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { continue; } - let mut should_lint = match source { + let missing = match source { PathSource::Trait(..) | PathSource::TraitItem(..) | PathSource::Type => true, PathSource::Expr(..) | PathSource::Pat @@ -1499,6 +1556,39 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { 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; + } + _ => {} + } + } + 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 @@ -1526,44 +1616,38 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { err.note("assuming a `'static` lifetime..."); err.emit(); should_lint = false; - for i in 0..expected_lifetimes { - let id = node_ids.start.plus(i); + + 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, .. } => { - let res = self.create_fresh_lifetime(node_ids.start, ident, binder); - self.record_lifetime_res(node_ids.start, res); - for i in 1..expected_lifetimes { - let id = node_ids.start.plus(i); + 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. - // `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, _) => { let res = LifetimeRes::Anonymous { binder, elided: true }; - self.record_lifetime_res(node_ids.start, res); - for i in 1..expected_lifetimes { - let id = node_ids.start.plus(i); + 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 i in 0..expected_lifetimes { - let id = node_ids.start.plus(i); + for id in node_ids { self.record_lifetime_res(id, res); } break; @@ -2235,7 +2319,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { fn resolve_impl_item(&mut self, item: &'ast AssocItem) { use crate::ResolutionError::*; match &item.kind { - AssocItemKind::Const(_default, _ty, _expr) => { + AssocItemKind::Const(_, ty, default) => { debug!("resolve_implementation AssocItemKind::Const"); // If this is a trait impl, ensure the const // exists in trait @@ -2248,14 +2332,17 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { |i, s, c| ConstNotMemberOfTrait(i, s, c), ); - // 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| { - visit::walk_assoc_item(this, item, AssocCtxt::Impl) - }); + self.visit_ty(ty); + 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, .. }) => { debug!("resolve_implementation AssocItemKind::Fn"); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 1a99bff610a..15f862e21d7 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2223,9 +2223,18 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { ] .contains(&Some(did)) { - let (span, span_type) = match &trait_ref.bound_generic_params { - [] => (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty), - [.., bound] => (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail), + let (span, span_type) = if let Some(bound) = + trait_ref.bound_generic_params.iter().rfind(|param| { + 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 .push(MissingLifetimeSpot::HigherRanked { span, span_type }); diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 447f4174c10..53f6870bdf5 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -755,7 +755,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let next_early_index = self.next_early_index(); let lifetime_span: Option = 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, }); let (span, span_type) = if let Some(span) = lifetime_span { diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 32bbfd7e332..9db051dc011 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -2920,13 +2920,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) { for br in referenced_regions.difference(&constrained_regions) { 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::BrAnon(_) | ty::BrEnv => "an anonymous lifetime".to_string(), }; 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 // in the return type but **also** be unconstrained is // if it only appears in "associated types" in the diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index acb2aa44ad5..95c82a7d2c3 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -628,24 +628,40 @@ fn compare_number_of_generics<'tcx>( let mut err_occurred = None; for (kind, trait_count, impl_count) in matchings { 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::>(); + 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_item = tcx.hir().expect_trait_item(def_id); - if trait_item.generics.params.is_empty() { - (Some(vec![trait_item.generics.span]), vec![]) - } else { - let arg_spans: Vec = - trait_item.generics.params.iter().map(|p| p.span).collect(); - let impl_trait_spans: Vec = trait_item - .generics - .params - .iter() - .filter_map(|p| match p.kind { - GenericParamKind::Type { synthetic: true, .. } => Some(p.span), - _ => None, - }) - .collect(); - (Some(arg_spans), impl_trait_spans) - } + let arg_spans: Vec = arg_spans(trait_.kind, trait_item.generics); + let impl_trait_spans: Vec = trait_item + .generics + .params + .iter() + .filter_map(|p| match p.kind { + GenericParamKind::Type { synthetic: true, .. } => Some(p.span), + _ => None, + }) + .collect(); + (Some(arg_spans), impl_trait_spans) } else { (trait_span.map(|s| vec![s]), vec![]) }; @@ -660,23 +676,7 @@ fn compare_number_of_generics<'tcx>( _ => None, }) .collect(); - let spans = if impl_item.generics.params.is_empty() { - 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::>() - }; + let spans = arg_spans(impl_.kind, impl_item.generics); let span = spans.first().copied(); let mut err = tcx.sess.struct_span_err_with_code( diff --git a/src/test/ui/generic-associated-types/issue-70304.rs b/src/test/ui/generic-associated-types/issue-70304.rs index 1c3d166a1af..c9fd7248a80 100644 --- a/src/test/ui/generic-associated-types/issue-70304.rs +++ b/src/test/ui/generic-associated-types/issue-70304.rs @@ -45,7 +45,7 @@ where } fn create_doc() -> impl Document = DocCursorImpl<'_>> { - //~^ ERROR: missing lifetime specifier + //~^ ERROR `'_` cannot be used here [E0637] //~| ERROR: missing lifetime specifier DocumentImpl {} } diff --git a/src/test/ui/generic-associated-types/issue-70304.stderr b/src/test/ui/generic-associated-types/issue-70304.stderr index 08efc82c886..b3881ccb099 100644 --- a/src/test/ui/generic-associated-types/issue-70304.stderr +++ b/src/test/ui/generic-associated-types/issue-70304.stderr @@ -1,14 +1,8 @@ -error[E0106]: missing lifetime specifier +error[E0637]: `'_` cannot be used here --> $DIR/issue-70304.rs:47:41 | LL | fn create_doc() -> impl Document = DocCursorImpl<'_>> { - | ^^ expected named lifetime parameter - | - = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime - | -LL | fn create_doc() -> impl Document = DocCursorImpl<'_>> { - | ~~~~~~~ + | ^^ `'_` is a reserved lifetime name error[E0106]: missing lifetime specifier --> $DIR/issue-70304.rs:47:61 @@ -24,4 +18,5 @@ LL | fn create_doc() -> impl Document = DocCursorImpl<'static>> { 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`. diff --git a/src/test/ui/generic-associated-types/issue-95305.rs b/src/test/ui/generic-associated-types/issue-95305.rs index 9ead347984b..2365daada11 100644 --- a/src/test/ui/generic-associated-types/issue-95305.rs +++ b/src/test/ui/generic-associated-types/issue-95305.rs @@ -9,7 +9,7 @@ trait Foo { } fn foo(x: &impl Foo = u32>) { } - //~^ ERROR missing lifetime specifier + //~^ ERROR `'_` cannot be used here [E0637] fn bar(x: &impl for<'a> Foo = &'_ u32>) { } //~^ ERROR missing lifetime specifier diff --git a/src/test/ui/generic-associated-types/issue-95305.stderr b/src/test/ui/generic-associated-types/issue-95305.stderr index 2b48378dc43..8624d880d4e 100644 --- a/src/test/ui/generic-associated-types/issue-95305.stderr +++ b/src/test/ui/generic-associated-types/issue-95305.stderr @@ -1,13 +1,8 @@ -error[E0106]: missing lifetime specifier +error[E0637]: `'_` cannot be used here --> $DIR/issue-95305.rs:11:26 | LL | fn foo(x: &impl Foo = u32>) { } - | ^^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | fn foo<'a>(x: &impl Foo = u32>) { } - | ++++ ~~ + | ^^ `'_` is a reserved lifetime name error[E0106]: missing lifetime specifier --> $DIR/issue-95305.rs:14:41 @@ -22,4 +17,5 @@ LL | fn bar(x: &impl for<'a> Foo = &'a u32>) { } 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`. diff --git a/src/test/ui/generic-associated-types/parameter_number_and_kind_impl.stderr b/src/test/ui/generic-associated-types/parameter_number_and_kind_impl.stderr index 76d39c88b61..1458bf0c4a4 100644 --- a/src/test/ui/generic-associated-types/parameter_number_and_kind_impl.stderr +++ b/src/test/ui/generic-associated-types/parameter_number_and_kind_impl.stderr @@ -8,7 +8,7 @@ LL | type A = u32; | ^ lifetimes do not match type in trait 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>; | -- -- @@ -16,7 +16,9 @@ LL | type B<'a, 'b>; | expected 0 type parameters ... LL | type B<'a, T> = Vec; - | ^ found 1 type parameter + | ^^ ^ + | | + | found 1 type parameter error[E0195]: lifetime parameters or bounds on type `C` do not match the trait declaration --> $DIR/parameter_number_and_kind_impl.rs:19:11 diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr index 1e2575116a8..0bfa7b3cc7c 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr @@ -23,7 +23,7 @@ error[E0308]: mismatched types LL | foo(bar, "string", |s| s.len() == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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,)>` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-71955.rs:45:24 @@ -61,7 +61,7 @@ error[E0308]: mismatched types LL | foo(baz, "string", |s| s.0.len() == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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<'_>,)>` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-71955.rs:48:24 diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs index fe319e6c851..172bf218c0d 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs @@ -6,8 +6,8 @@ trait SomeTrait<'a> { fn give_me_ice() { callee:: >::Associated>(); - //~^ ERROR the trait bound `T: SomeTrait<'_>` 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] + //~| ERROR the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied [E0277] } fn callee>() { diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr index 13b68b07240..ecca4b999e7 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr @@ -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 | LL | callee:: >::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` | -LL | fn give_me_ice>() { - | +++++++++++++++ +LL | fn give_me_ice 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 | LL | callee:: >::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` | -LL | fn give_me_ice>() { - | +++++++++++++++ +LL | fn give_me_ice SomeTrait<'r>>() { + | +++++++++++++++++++++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.rs b/src/test/ui/impl-header-lifetime-elision/dyn-trait.rs index c508c0ac9d5..359c08c98d1 100644 --- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.rs +++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.rs @@ -13,6 +13,10 @@ impl StaticTrait for Box { } trait NotStaticTrait { } impl NotStaticTrait for Box { } +// 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) { } diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr index 88c260b18cb..762698c4fc1 100644 --- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr +++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr @@ -1,5 +1,5 @@ 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) { | -- - `x` is a reference that is only valid in the function body diff --git a/src/test/ui/lifetimes/elided-lifetime-in-path-in-pat.rs b/src/test/ui/lifetimes/elided-lifetime-in-path-in-pat.rs new file mode 100644 index 00000000000..ff84d251149 --- /dev/null +++ b/src/test/ui/lifetimes/elided-lifetime-in-path-in-pat.rs @@ -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() {} diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr index cce0a31bfbb..d85ea6529f6 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr @@ -10,8 +10,8 @@ LL | y.push(z); | help: consider introducing a named lifetime parameter | -LL | fn foo<'a>(x:Box , y: Vec<&u8>, z: &u8) { - | ++++ ++ ++ +LL | fn foo<'a>(x:Box , y: Vec<&'a u8>, z: &'a u8) { + | ++++ ++ ++ error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:2:3