diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 7cd360623ec42..d4b41aad08ca4 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1835,7 +1835,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { debug!(?self.captured_lifetimes); let name = match res { LifetimeRes::Param { mut param, binder } => { - debug_assert_ne!(ident.name, kw::UnderscoreLifetime); let p_name = ParamName::Plain(ident); if let Some(mut captured_lifetimes) = self.captured_lifetimes.take() { if !captured_lifetimes.binders_to_ignore.contains(&binder) { diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index d0893cd09d8db..c0d5d2bc46d0d 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -713,7 +713,7 @@ impl Res { } /// Resolution for a lifetime appearing in a type. -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum LifetimeRes { /// Successfully linked the lifetime to a generic parameter. Param { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index e739ed678d8be..9b5fd4ea6d133 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -21,6 +21,7 @@ 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_middle::middle::resolve_lifetime::Set1; use rustc_middle::ty::DefIdTree; use rustc_middle::{bug, span_bug}; use rustc_session::lint; @@ -43,6 +44,10 @@ type IdentMap = FxHashMap; /// Map from the name in a pattern to its binding mode. type BindingMap = IdentMap; +use diagnostics::{ + ElisionFnParameter, LifetimeElisionCandidate, MissingLifetime, MissingLifetimeKind, +}; + #[derive(Copy, Clone, Debug)] struct BindingInfo { span: Span, @@ -258,7 +263,13 @@ enum LifetimeRibKind { AnonymousReportError, /// Pass responsibility to `resolve_lifetime` code for all cases. - AnonymousPassThrough(NodeId, /* in_fn_return */ bool), + AnonymousPassThrough(NodeId), + + /// Replace all anonymous lifetimes by provided lifetime. + Elided(LifetimeRes), + + /// Signal we cannot find which should be the anonymous lifetime. + ElisionFailure, } #[derive(Copy, Clone, Debug)] @@ -522,6 +533,10 @@ struct DiagnosticMetadata<'ast> { /// When processing impl trait currently_processing_impl_trait: Option<(TraitRef, Ty)>, + + /// Accumulate the errors due to missed lifetime elision, + /// and report them all at once for each function. + current_elision_failures: Vec, } struct LateResolutionVisitor<'a, 'b, 'ast> { @@ -540,6 +555,13 @@ struct LateResolutionVisitor<'a, 'b, 'ast> { /// The current set of local scopes for lifetimes. lifetime_ribs: Vec, + /// We are looking for lifetimes in an elision context. + /// The set contains all the resolutions that we encountered so far. + /// They will be used to determine the correct lifetime for the fn return type. + /// The `LifetimeElisionCandidate` is used for diagnostics, to suggest introducing named + /// lifetimes. + lifetime_elision_candidates: Option>, + /// The trait that the current context can refer to. current_trait_ref: Option<(Module<'a>, TraitRef)>, @@ -580,7 +602,9 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { fn visit_anon_const(&mut self, constant: &'ast AnonConst) { // We deal with repeat expressions explicitly in `resolve_expr`. self.with_lifetime_rib(LifetimeRibKind::AnonConst, |this| { - this.resolve_anon_const(constant, IsRepeatExpr::No); + this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| { + this.resolve_anon_const(constant, IsRepeatExpr::No); + }) }) } fn visit_expr(&mut self, expr: &'ast Expr) { @@ -607,8 +631,10 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { TyKind::Rptr(None, _) => { // Elided lifetime in reference: we resolve as if there was some lifetime `'_` with // NodeId `ty.id`. + // This span will be used in case of elision failure. let span = self.r.session.source_map().next_point(ty.span.shrink_to_lo()); self.resolve_elided_lifetime(ty.id, span); + visit::walk_ty(self, ty); } TyKind::Path(ref qself, ref path) => { self.diagnostic_metadata.current_type_path = Some(ty); @@ -634,8 +660,8 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { }, |this| this.visit_path(&path, ty.id), ); - self.diagnostic_metadata.current_type_path = prev_ty; - return; + } else { + visit::walk_ty(self, ty) } } TyKind::ImplicitSelf => { @@ -649,9 +675,16 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { ) .map_or(Res::Err, |d| d.res()); self.r.record_partial_res(ty.id, PartialRes::new(res)); + visit::walk_ty(self, ty) + } + TyKind::ImplTrait(..) => { + let candidates = self.lifetime_elision_candidates.take(); + visit::walk_ty(self, ty); + self.lifetime_elision_candidates = candidates; } TyKind::TraitObject(ref bounds, ..) => { self.diagnostic_metadata.current_trait_object = Some(&bounds[..]); + visit::walk_ty(self, ty) } TyKind::BareFn(ref bare_fn) => { let span = ty.span.shrink_to_lo().to(bare_fn.decl_span.shrink_to_lo()); @@ -665,25 +698,20 @@ 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::AnonymousCreateParameter { - binder: ty.id, - report_in_path: false, - }, - |this| walk_list!(this, visit_param, &bare_fn.decl.inputs), - ); - this.with_lifetime_rib( - LifetimeRibKind::AnonymousPassThrough(ty.id, true), - |this| this.visit_fn_ret_ty(&bare_fn.decl.output), + this.resolve_fn_signature( + ty.id, + None, + false, + // We don't need to deal with patterns in parameters, because + // they are not possible for foreign or bodiless functions. + bare_fn.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)), + &bare_fn.decl.output, ); }, - ); - self.diagnostic_metadata.current_trait_object = prev; - return; + ) } - _ => (), + _ => visit::walk_ty(self, ty), } - visit::walk_ty(self, ty); self.diagnostic_metadata.current_trait_object = prev; self.diagnostic_metadata.current_type_path = prev_ty; } @@ -757,18 +785,12 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { | 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::AnonymousCreateParameter { - binder: fn_id, - report_in_path: false, - }, - |this| walk_list!(this, visit_param, &sig.decl.inputs), - ); - self.with_lifetime_rib( - LifetimeRibKind::AnonymousPassThrough(fn_id, true), - |this| this.visit_fn_ret_ty(&sig.decl.output), + self.resolve_fn_signature( + fn_id, + None, + sig.decl.has_self(), + sig.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)), + &sig.decl.output, ); return; } @@ -793,19 +815,15 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { let declaration = &sig.decl; let async_node_id = sig.header.asyncness.opt_return_id(); - // 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. - this.with_lifetime_rib( - LifetimeRibKind::AnonymousCreateParameter { - binder: fn_id, - // Only emit a hard error for `async fn`, since this kind of - // elision has always been allowed in regular `fn`s. - report_in_path: async_node_id.is_some(), - }, - // Add each argument to the rib. - |this| this.resolve_params(&declaration.inputs), + this.resolve_fn_signature( + fn_id, + async_node_id, + declaration.has_self(), + declaration + .inputs + .iter() + .map(|Param { pat, ty, .. }| (Some(&**pat), &**ty)), + &declaration.output, ); // Construct the list of in-scope lifetime parameters for async lowering. @@ -844,23 +862,13 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { .insert(async_node_id, extra_lifetime_params); } - this.with_lifetime_rib( - 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), - ); - 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( - LifetimeRibKind::AnonymousPassThrough(fn_id, false), + LifetimeRibKind::AnonymousPassThrough(fn_id), |this| this.visit_block(body), ); @@ -888,7 +896,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { this.with_lifetime_rib( match binder { ClosureBinder::NotPresent => { - LifetimeRibKind::AnonymousPassThrough(fn_id, true) + LifetimeRibKind::AnonymousPassThrough(fn_id) } ClosureBinder::For { .. } => LifetimeRibKind::AnonymousReportError, }, @@ -900,7 +908,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { let previous_state = replace(&mut this.in_func_body, true); // Resolve the function body, potentially inside the body of an async closure this.with_lifetime_rib( - LifetimeRibKind::AnonymousPassThrough(fn_id, false), + LifetimeRibKind::AnonymousPassThrough(fn_id), |this| this.visit_expr(body), ); @@ -1030,16 +1038,12 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { 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), + self.resolve_fn_signature( + binder, + None, + false, + p_args.inputs.iter().map(|ty| (None, &**ty)), + &p_args.output, ); break; } @@ -1052,6 +1056,8 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { LifetimeRibKind::AnonymousPassThrough(..) | LifetimeRibKind::AnonymousCreateParameter { .. } | LifetimeRibKind::AnonymousReportError + | LifetimeRibKind::Elided(_) + | LifetimeRibKind::ElisionFailure | LifetimeRibKind::AnonConst | LifetimeRibKind::ConstGeneric => {} } @@ -1156,6 +1162,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { }, label_ribs: Vec::new(), lifetime_ribs: Vec::new(), + lifetime_elision_candidates: None, current_trait_ref: None, diagnostic_metadata: Box::new(DiagnosticMetadata::default()), // errors at module scope should always be reported @@ -1362,7 +1369,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { work: impl FnOnce(&mut Self) -> T, ) -> T { self.lifetime_ribs.push(LifetimeRib::new(kind)); + let outer_elision_candidates = self.lifetime_elision_candidates.take(); let ret = work(self); + self.lifetime_elision_candidates = outer_elision_candidates; self.lifetime_ribs.pop(); ret } @@ -1372,7 +1381,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let ident = lifetime.ident; if ident.name == kw::StaticLifetime { - self.record_lifetime_res(lifetime.id, LifetimeRes::Static); + self.record_lifetime_res( + lifetime.id, + LifetimeRes::Static, + LifetimeElisionCandidate::Named, + ); return; } @@ -1385,7 +1398,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let rib = &self.lifetime_ribs[i]; let normalized_ident = ident.normalize_to_macros_2_0(); if let Some(&(_, res)) = rib.bindings.get(&normalized_ident) { - self.record_lifetime_res(lifetime.id, res); + self.record_lifetime_res(lifetime.id, res, LifetimeElisionCandidate::Named); if let LifetimeRes::Param { param, .. } = res { match self.lifetime_uses.entry(param) { @@ -1399,15 +1412,20 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Do not suggest eliding a lifetime where an anonymous // lifetime would be illegal. LifetimeRibKind::Item - | LifetimeRibKind::AnonymousPassThrough(_, true) - | LifetimeRibKind::AnonymousReportError => { - Some(LifetimeUseSet::Many) - } + | LifetimeRibKind::AnonymousReportError + | LifetimeRibKind::ElisionFailure => Some(LifetimeUseSet::Many), // An anonymous lifetime is legal here, go ahead. - LifetimeRibKind::AnonymousPassThrough(_, false) + LifetimeRibKind::AnonymousPassThrough(_) | LifetimeRibKind::AnonymousCreateParameter { .. } => { Some(LifetimeUseSet::One { use_span: ident.span, use_ctxt }) } + // Only report if eliding the lifetime would have the same + // semantics. + LifetimeRibKind::Elided(r) => Some(if res == r { + LifetimeUseSet::One { use_span: ident.span, use_ctxt } + } else { + LifetimeUseSet::Many + }), LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstGeneric | LifetimeRibKind::AnonConst => None, @@ -1429,12 +1447,20 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { LifetimeRibKind::Item => break, LifetimeRibKind::ConstGeneric => { self.emit_non_static_lt_in_const_generic_error(lifetime); - self.r.lifetimes_res_map.insert(lifetime.id, LifetimeRes::Error); + self.record_lifetime_res( + lifetime.id, + LifetimeRes::Error, + LifetimeElisionCandidate::Ignore, + ); return; } LifetimeRibKind::AnonConst => { self.maybe_emit_forbidden_non_static_lifetime_error(lifetime); - self.r.lifetimes_res_map.insert(lifetime.id, LifetimeRes::Error); + self.record_lifetime_res( + lifetime.id, + LifetimeRes::Error, + LifetimeElisionCandidate::Ignore, + ); return; } _ => {} @@ -1452,19 +1478,31 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } self.emit_undeclared_lifetime_error(lifetime, outer_res); - self.record_lifetime_res(lifetime.id, LifetimeRes::Error); + self.record_lifetime_res(lifetime.id, LifetimeRes::Error, LifetimeElisionCandidate::Named); } #[tracing::instrument(level = "debug", skip(self))] fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) { debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime); + let missing_lifetime = MissingLifetime { + id: lifetime.id, + span: lifetime.ident.span, + kind: if elided { + MissingLifetimeKind::Ampersand + } else { + MissingLifetimeKind::Underscore + }, + count: 1, + }; + let elision_candidate = LifetimeElisionCandidate::Missing(missing_lifetime); for i in (0..self.lifetime_ribs.len()).rev() { let rib = &mut self.lifetime_ribs[i]; + debug!(?rib.kind); match rib.kind { LifetimeRibKind::AnonymousCreateParameter { binder, .. } => { let res = self.create_fresh_lifetime(lifetime.id, lifetime.ident, binder); - self.record_lifetime_res(lifetime.id, res); + self.record_lifetime_res(lifetime.id, res, elision_candidate); return; } LifetimeRibKind::AnonymousReportError => { @@ -1486,39 +1524,46 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { .span_label(lifetime.ident.span, note) .emit(); - self.record_lifetime_res(lifetime.id, LifetimeRes::Error); + self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate); return; } - LifetimeRibKind::AnonymousPassThrough(node_id, _) => { + LifetimeRibKind::AnonymousPassThrough(node_id) => { self.record_lifetime_res( lifetime.id, LifetimeRes::Anonymous { binder: node_id, elided }, + elision_candidate, ); return; } + LifetimeRibKind::Elided(res) => { + self.record_lifetime_res(lifetime.id, res, elision_candidate); + return; + } + LifetimeRibKind::ElisionFailure => { + self.diagnostic_metadata.current_elision_failures.push(missing_lifetime); + self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate); + return; + } LifetimeRibKind::Item => break, LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstGeneric | LifetimeRibKind::AnonConst => {} } } - // This resolution is wrong, it passes the work to HIR lifetime resolution. - // We cannot use `LifetimeRes::Error` because we do not emit a diagnostic. - self.record_lifetime_res( - lifetime.id, - LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided }, - ); + self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate); + self.report_missing_lifetime_specifiers(vec![missing_lifetime], None); } #[tracing::instrument(level = "debug", skip(self))] fn resolve_elided_lifetime(&mut self, anchor_id: NodeId, span: Span) { let id = self.r.next_node_id(); + let lt = Lifetime { id, ident: Ident::new(kw::UnderscoreLifetime, span) }; + self.record_lifetime_res( anchor_id, LifetimeRes::ElidedAnchor { start: id, end: NodeId::from_u32(id.as_u32() + 1) }, + LifetimeElisionCandidate::Ignore, ); - - let lt = Lifetime { id, ident: Ident::new(kw::UnderscoreLifetime, span) }; self.resolve_anonymous_lifetime(<, true); } @@ -1603,16 +1648,17 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.record_lifetime_res( segment_id, LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end }, + LifetimeElisionCandidate::Ignore, ); 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, _) => { + LifetimeRibKind::AnonymousPassThrough(binder) => { let res = LifetimeRes::Anonymous { binder, elided: true }; for id in node_ids { - self.record_lifetime_res(id, res); + self.record_lifetime_res(id, res, LifetimeElisionCandidate::Named); } break; } @@ -1627,11 +1673,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let res = LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true }; for id in node_ids { - self.record_lifetime_res(id, res); + self.record_lifetime_res(id, res, LifetimeElisionCandidate::Named); } break; } LifetimeRibKind::AnonymousCreateParameter { .. } + | LifetimeRibKind::Elided(_) + | LifetimeRibKind::ElisionFailure | LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstGeneric | LifetimeRibKind::AnonConst => {} @@ -1640,6 +1688,16 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { continue; } + let missing_lifetime = MissingLifetime { + id: node_ids.start, + span: elided_lifetime_span, + kind: if segment.has_generic_args { + MissingLifetimeKind::Comma + } else { + MissingLifetimeKind::Brackets + }, + count: expected_lifetimes, + }; let mut should_lint = true; for rib in self.lifetime_ribs.iter().rev() { match rib.kind { @@ -1670,23 +1728,60 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { should_lint = false; for id in node_ids { - self.record_lifetime_res(id, LifetimeRes::Error); + self.record_lifetime_res( + id, + LifetimeRes::Error, + LifetimeElisionCandidate::Named, + ); } break; } // Do not create a parameter for patterns and expressions. LifetimeRibKind::AnonymousCreateParameter { binder, .. } => { + // Group all suggestions into the first record. + let mut candidate = LifetimeElisionCandidate::Missing(missing_lifetime); for id in node_ids { let res = self.create_fresh_lifetime(id, ident, binder); - self.record_lifetime_res(id, res); + self.record_lifetime_res( + id, + res, + replace(&mut candidate, LifetimeElisionCandidate::Named), + ); } break; } // `PassThrough` is the normal case. - LifetimeRibKind::AnonymousPassThrough(binder, _) => { + LifetimeRibKind::AnonymousPassThrough(binder) => { let res = LifetimeRes::Anonymous { binder, elided: true }; + let mut candidate = LifetimeElisionCandidate::Missing(missing_lifetime); for id in node_ids { - self.record_lifetime_res(id, res); + self.record_lifetime_res( + id, + res, + replace(&mut candidate, LifetimeElisionCandidate::Ignore), + ); + } + break; + } + LifetimeRibKind::Elided(res) => { + let mut candidate = LifetimeElisionCandidate::Missing(missing_lifetime); + for id in node_ids { + self.record_lifetime_res( + id, + res, + replace(&mut candidate, LifetimeElisionCandidate::Ignore), + ); + } + break; + } + LifetimeRibKind::ElisionFailure => { + self.diagnostic_metadata.current_elision_failures.push(missing_lifetime); + for id in node_ids { + self.record_lifetime_res( + id, + LifetimeRes::Error, + LifetimeElisionCandidate::Ignore, + ); } break; } @@ -1695,13 +1790,14 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // 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); + self.record_lifetime_res( + id, + LifetimeRes::Error, + LifetimeElisionCandidate::Ignore, + ); } + self.report_missing_lifetime_specifiers(vec![missing_lifetime], None); break; } LifetimeRibKind::Generics { .. } @@ -1728,13 +1824,223 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } #[tracing::instrument(level = "debug", skip(self))] - fn record_lifetime_res(&mut self, id: NodeId, res: LifetimeRes) { + fn record_lifetime_res( + &mut self, + id: NodeId, + res: LifetimeRes, + candidate: LifetimeElisionCandidate, + ) { if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) { panic!( "lifetime {:?} resolved multiple times ({:?} before, {:?} now)", id, prev_res, res ) } + match res { + LifetimeRes::Param { .. } + | LifetimeRes::Fresh { .. } + | LifetimeRes::Anonymous { .. } + | LifetimeRes::Static => { + if let Some(ref mut candidates) = self.lifetime_elision_candidates { + candidates.insert(res, candidate); + } + } + LifetimeRes::Error | LifetimeRes::ElidedAnchor { .. } => {} + } + } + + #[tracing::instrument(level = "debug", skip(self))] + fn record_lifetime_param(&mut self, id: NodeId, res: LifetimeRes) { + if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) { + panic!( + "lifetime parameter {:?} resolved multiple times ({:?} before, {:?} now)", + id, prev_res, res + ) + } + } + + /// Perform resolution of a function signature, accounting for lifetime elision. + #[tracing::instrument(level = "debug", skip(self, inputs))] + fn resolve_fn_signature( + &mut self, + fn_id: NodeId, + async_node_id: Option, + has_self: bool, + inputs: impl Iterator, &'ast Ty)> + Clone, + output_ty: &'ast FnRetTy, + ) { + // Add each argument to the rib. + let parameter_rib = LifetimeRibKind::AnonymousCreateParameter { + binder: fn_id, + report_in_path: async_node_id.is_some(), + }; + let elision_lifetime = + self.with_lifetime_rib(parameter_rib, |this| this.resolve_fn_params(has_self, inputs)); + debug!(?elision_lifetime); + + let outer_failures = take(&mut self.diagnostic_metadata.current_elision_failures); + let output_rib = if let Ok(res) = elision_lifetime.as_ref() { + LifetimeRibKind::Elided(*res) + } else { + LifetimeRibKind::ElisionFailure + }; + self.with_lifetime_rib(output_rib, |this| visit::walk_fn_ret_ty(this, &output_ty)); + let elision_failures = + replace(&mut self.diagnostic_metadata.current_elision_failures, outer_failures); + if !elision_failures.is_empty() { + let Err(failure_info) = elision_lifetime else { bug!() }; + self.report_missing_lifetime_specifiers(elision_failures, Some(failure_info)); + } + } + + /// Resolve inside function parameters and parameter types. + /// Returns the lifetime for elision in fn return type, + /// or diagnostic information in case of elision failure. + fn resolve_fn_params( + &mut self, + has_self: bool, + inputs: impl Iterator, &'ast Ty)>, + ) -> Result, Vec)> { + let outer_candidates = + replace(&mut self.lifetime_elision_candidates, Some(Default::default())); + + let mut elision_lifetime = None; + let mut lifetime_count = 0; + let mut parameter_info = Vec::new(); + + let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())]; + for (index, (pat, ty)) in inputs.enumerate() { + debug!(?pat, ?ty); + if let Some(pat) = pat { + self.resolve_pattern(pat, PatternSource::FnParam, &mut bindings); + } + self.visit_ty(ty); + + if let Some(ref candidates) = self.lifetime_elision_candidates { + let new_count = candidates.len(); + let local_count = new_count - lifetime_count; + if local_count != 0 { + parameter_info.push(ElisionFnParameter { + index, + ident: if let Some(pat) = pat && let PatKind::Ident(_, ident, _) = pat.kind { + Some(ident) + } else { + None + }, + lifetime_count: local_count, + span: ty.span, + }); + } + lifetime_count = new_count; + } + + // Handle `self` specially. + if index == 0 && has_self { + let self_lifetime = self.find_lifetime_for_self(ty); + if let Set1::One(lifetime) = self_lifetime { + elision_lifetime = Some(lifetime); + self.lifetime_elision_candidates = None; + } else { + self.lifetime_elision_candidates = Some(Default::default()); + lifetime_count = 0; + } + } + debug!("(resolving function / closure) recorded parameter"); + } + + let all_candidates = replace(&mut self.lifetime_elision_candidates, outer_candidates); + debug!(?all_candidates); + + if let Some(res) = elision_lifetime { + return Ok(res); + } + + // We do not have a `self` candidate, look at the full list. + let all_candidates = all_candidates.unwrap(); + if all_candidates.len() == 1 { + Ok(*all_candidates.first().unwrap().0) + } else { + let all_candidates = all_candidates + .into_iter() + .filter_map(|(_, candidate)| match candidate { + LifetimeElisionCandidate::Ignore | LifetimeElisionCandidate::Named => None, + LifetimeElisionCandidate::Missing(missing) => Some(missing), + }) + .collect(); + Err((all_candidates, parameter_info)) + } + } + + /// List all the lifetimes that appear in the provided type. + fn find_lifetime_for_self(&self, ty: &'ast Ty) -> Set1 { + struct SelfVisitor<'r, 'a> { + r: &'r Resolver<'a>, + impl_self: Option, + lifetime: Set1, + } + + impl SelfVisitor<'_, '_> { + // Look for `self: &'a Self` - also desugared from `&'a self`, + // and if that matches, use it for elision and return early. + fn is_self_ty(&self, ty: &Ty) -> bool { + match ty.kind { + TyKind::ImplicitSelf => true, + TyKind::Path(None, _) => { + let path_res = self.r.partial_res_map[&ty.id].base_res(); + if let Res::SelfTy { .. } = path_res { + return true; + } + Some(path_res) == self.impl_self + } + _ => false, + } + } + } + + impl<'a> Visitor<'a> for SelfVisitor<'_, '_> { + fn visit_ty(&mut self, ty: &'a Ty) { + trace!("SelfVisitor considering ty={:?}", ty); + if let TyKind::Rptr(lt, ref mt) = ty.kind && self.is_self_ty(&mt.ty) { + let lt_id = if let Some(lt) = lt { + lt.id + } else { + let res = self.r.lifetimes_res_map[&ty.id]; + let LifetimeRes::ElidedAnchor { start, .. } = res else { bug!() }; + start + }; + let lt_res = self.r.lifetimes_res_map[<_id]; + trace!("SelfVisitor inserting res={:?}", lt_res); + self.lifetime.insert(lt_res); + } + visit::walk_ty(self, ty) + } + } + + let impl_self = self + .diagnostic_metadata + .current_self_type + .as_ref() + .and_then(|ty| { + if let TyKind::Path(None, _) = ty.kind { + self.r.partial_res_map.get(&ty.id) + } else { + None + } + }) + .map(|res| res.base_res()) + .filter(|res| { + // Permit the types that unambiguously always + // result in the same type constructor being used + // (it can't differ between `Self` and `self`). + matches!( + res, + Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, _,) | Res::PrimTy(_) + ) + }); + let mut visitor = SelfVisitor { r: self.r, impl_self, lifetime: Set1::Empty }; + visitor.visit_ty(ty); + trace!("SelfVisitor found={:?}", visitor.lifetime); + visitor.lifetime } /// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved @@ -1959,22 +2265,29 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ItemKind::Static(ref ty, _, ref expr) | ItemKind::Const(_, ref ty, ref expr) => { self.with_item_rib(|this| { - this.visit_ty(ty); - if let Some(expr) = expr { - let constant_item_kind = match item.kind { - ItemKind::Const(..) => ConstantItemKind::Const, - ItemKind::Static(..) => ConstantItemKind::Static, - _ => unreachable!(), - }; - // We already forbid generic params because of the above item rib, - // so it doesn't matter whether this is a trivial constant. - this.with_constant_rib( - IsRepeatExpr::No, - HasGenericParams::Yes, - Some((item.ident, constant_item_kind)), - |this| this.visit_expr(expr), - ); - } + this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| { + this.visit_ty(ty); + }); + this.with_lifetime_rib( + LifetimeRibKind::AnonymousPassThrough(item.id), + |this| { + if let Some(expr) = expr { + let constant_item_kind = match item.kind { + ItemKind::Const(..) => ConstantItemKind::Const, + ItemKind::Static(..) => ConstantItemKind::Static, + _ => unreachable!(), + }; + // We already forbid generic params because of the above item rib, + // so it doesn't matter whether this is a trivial constant. + this.with_constant_rib( + IsRepeatExpr::No, + HasGenericParams::Yes, + Some((item.ident, constant_item_kind)), + |this| this.visit_expr(expr), + ); + } + }, + ); }); } @@ -2045,7 +2358,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { { diagnostics::signal_lifetime_shadowing(self.r.session, original, param.ident); // Record lifetime res, so lowering knows there is something fishy. - self.record_lifetime_res(param.id, LifetimeRes::Error); + self.record_lifetime_param(param.id, LifetimeRes::Error); continue; } @@ -2056,7 +2369,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.report_error(param.ident.span, err); if let GenericParamKind::Lifetime = param.kind { // Record lifetime res, so lowering knows there is something fishy. - self.record_lifetime_res(param.id, LifetimeRes::Error); + self.record_lifetime_param(param.id, LifetimeRes::Error); continue; } } @@ -2075,7 +2388,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { .span_label(param.ident.span, "`'_` is a reserved lifetime name") .emit(); // Record lifetime res, so lowering knows there is something fishy. - self.record_lifetime_res(param.id, LifetimeRes::Error); + self.record_lifetime_param(param.id, LifetimeRes::Error); continue; } @@ -2090,7 +2403,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { .span_label(param.ident.span, "'static is a reserved lifetime name") .emit(); // Record lifetime res, so lowering knows there is something fishy. - self.record_lifetime_res(param.id, LifetimeRes::Error); + self.record_lifetime_param(param.id, LifetimeRes::Error); continue; } @@ -2102,7 +2415,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { GenericParamKind::Const { .. } => (&mut function_value_rib, DefKind::ConstParam), GenericParamKind::Lifetime => { let res = LifetimeRes::Param { param: def_id, binder }; - self.record_lifetime_res(param.id, res); + self.record_lifetime_param(param.id, res); function_lifetime_rib.bindings.insert(ident, (param.id, res)); continue; } @@ -2125,7 +2438,14 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.ribs[TypeNS].pop(); self.ribs[ValueNS].pop(); - self.lifetime_ribs.pop(); + let function_lifetime_rib = self.lifetime_ribs.pop().unwrap(); + + // Do not account for the parameters we just bound for function lifetime elision. + if let Some(ref mut candidates) = self.lifetime_elision_candidates { + for (_, res) in function_lifetime_rib.bindings.values() { + candidates.remove(res); + } + } if let LifetimeBinderKind::BareFnType | LifetimeBinderKind::WhereBound @@ -2223,20 +2543,26 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // // 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), + self.with_lifetime_rib( + LifetimeRibKind::AnonymousPassThrough(item.id), + |this| { + this.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::TyAlias(box TyAlias { generics, .. }) => self + .with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { + walk_assoc_item(this, generics, LifetimeBinderKind::Item, item) + }), AssocItemKind::MacCall(_) => { panic!("unexpanded macro in resolve!") } @@ -2307,7 +2633,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { LifetimeRibKind::Generics { span: generics.span, binder: item_id, - kind: LifetimeBinderKind::ImplBlock + kind: LifetimeBinderKind::ImplBlock, }, |this| { // Dummy self type for better errors if `Self` is used in the trait path. @@ -2327,7 +2653,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Register the trait definitions from here. if let Some(trait_id) = trait_id { - this.r.trait_impls.entry(trait_id).or_default().push(item_def_id); + this.r + .trait_impls + .entry(trait_id) + .or_default() + .push(item_def_id); } let item_def_id = item_def_id.to_def_id(); @@ -2346,21 +2676,17 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { this.visit_generics(generics); // Resolve the items within the impl. - this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(item_id,false), - |this| { - this.with_current_self_type(self_type, |this| { - this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| { - debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)"); - for item in impl_items { - this.resolve_impl_item(&**item); - } - }); - }); - }, - ); + this.with_current_self_type(self_type, |this| { + this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| { + debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)"); + for item in impl_items { + this.resolve_impl_item(&**item); + } + }); + }); }); }, - ); + ) }, ); }); @@ -2391,9 +2717,17 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // // 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) - }); + self.with_lifetime_rib( + LifetimeRibKind::AnonymousPassThrough(item.id), + |this| { + this.with_constant_rib( + IsRepeatExpr::No, + HasGenericParams::Yes, + None, + |this| this.visit_expr(expr), + ) + }, + ); } } AssocItemKind::Fn(box Fn { generics, .. }) => { @@ -2435,18 +2769,20 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { kind: LifetimeBinderKind::Item, }, |this| { - // If this is a trait impl, ensure the type - // exists in trait - this.check_trait_item( - item.id, - item.ident, - &item.kind, - TypeNS, - item.span, - |i, s, c| TypeNotMemberOfTrait(i, s, c), - ); + this.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { + // If this is a trait impl, ensure the type + // exists in trait + this.check_trait_item( + item.id, + item.ident, + &item.kind, + TypeNS, + item.span, + |i, s, c| TypeNotMemberOfTrait(i, s, c), + ); - visit::walk_assoc_item(this, item, AssocCtxt::Impl) + visit::walk_assoc_item(this, item, AssocCtxt::Impl) + }); }, ); } @@ -3581,7 +3917,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ExprKind::Repeat(ref elem, ref ct) => { self.visit_expr(elem); self.with_lifetime_rib(LifetimeRibKind::AnonConst, |this| { - this.resolve_anon_const(ct, IsRepeatExpr::Yes) + this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| { + this.resolve_anon_const(ct, IsRepeatExpr::Yes) + }) }); } ExprKind::ConstBlock(ref ct) => { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index e428bae479bc2..f979403e09735 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1,7 +1,6 @@ use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion}; -use crate::late::lifetimes::{ElisionFailureInfo, LifetimeContext}; use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind}; -use crate::late::{LifetimeBinderKind, LifetimeRibKind, LifetimeUseSet}; +use crate::late::{LifetimeBinderKind, LifetimeRes, LifetimeRibKind, LifetimeUseSet}; use crate::path_names_to_string; use crate::{Module, ModuleKind, ModuleOrUniformRoot}; use crate::{PathResult, PathSource, Segment}; @@ -9,10 +8,10 @@ use crate::{PathResult, PathSource, Segment}; use rustc_ast::visit::{FnCtxt, FnKind, LifetimeCtxt}; use rustc_ast::{ self as ast, AssocItemKind, Expr, ExprKind, GenericParam, GenericParamKind, Item, ItemKind, - NodeId, Path, Ty, TyKind, + NodeId, Path, Ty, TyKind, DUMMY_NODE_ID, }; use rustc_ast_pretty::pprust::path_segment_to_string; -use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, @@ -20,7 +19,7 @@ use rustc_errors::{ use rustc_hir as hir; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind}; -use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::PrimTy; use rustc_session::lint; use rustc_session::parse::feature_err; @@ -29,7 +28,7 @@ use rustc_span::edition::Edition; use rustc_span::hygiene::MacroKind; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{BytePos, Span, DUMMY_SP}; +use rustc_span::{BytePos, Span}; use std::iter; use std::ops::Deref; @@ -59,45 +58,6 @@ impl AssocSuggestion { } } -pub(crate) enum MissingLifetimeSpot<'tcx> { - Generics(&'tcx hir::Generics<'tcx>), - HigherRanked { span: Span, span_type: ForLifetimeSpanType }, - Static, -} - -pub(crate) enum ForLifetimeSpanType { - BoundEmpty, - BoundTail, - TypeEmpty, - TypeTail, - ClosureEmpty, - ClosureTail, -} - -impl ForLifetimeSpanType { - pub(crate) fn descr(&self) -> &'static str { - match self { - Self::BoundEmpty | Self::BoundTail => "bound", - Self::TypeEmpty | Self::TypeTail => "type", - Self::ClosureEmpty | Self::ClosureTail => "closure", - } - } - - pub(crate) fn suggestion(&self, sugg: impl std::fmt::Display) -> String { - match self { - Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg), - Self::ClosureEmpty => format!("for<{}>", sugg), - Self::BoundTail | Self::TypeTail | Self::ClosureTail => format!(", {}", sugg), - } - } -} - -impl<'tcx> Into> for &&'tcx hir::Generics<'tcx> { - fn into(self) -> MissingLifetimeSpot<'tcx> { - MissingLifetimeSpot::Generics(self) - } -} - fn is_self_type(path: &[Segment], namespace: Namespace) -> bool { namespace == TypeNS && path.len() == 1 && path[0].ident.name == kw::SelfUpper } @@ -122,6 +82,56 @@ fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, Str (variant_path_string, enum_path_string) } +/// Description of an elided lifetime. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] +pub(super) struct MissingLifetime { + /// Used to overwrite the resolution with the suggestion, to avoid cascasing errors. + pub id: NodeId, + /// Where to suggest adding the lifetime. + pub span: Span, + /// How the lifetime was introduced, to have the correct space and comma. + pub kind: MissingLifetimeKind, + /// Number of elided lifetimes, used for elision in path. + pub count: usize, +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] +pub(super) enum MissingLifetimeKind { + /// An explicit `'_`. + Underscore, + /// An elided lifetime `&' ty`. + Ampersand, + /// An elided lifetime in brackets with written brackets. + Comma, + /// An elided lifetime with elided brackets. + Brackets, +} + +/// Description of the lifetimes appearing in a function parameter. +/// This is used to provide a literal explanation to the elision failure. +#[derive(Clone, Debug)] +pub(super) struct ElisionFnParameter { + /// The index of the argument in the original definition. + pub index: usize, + /// The name of the argument if it's a simple ident. + pub ident: Option, + /// The number of lifetimes in the parameter. + pub lifetime_count: usize, + /// The span of the parameter. + pub span: Span, +} + +/// Description of lifetimes that appear as candidates for elision. +/// This is used to suggest introducing an explicit lifetime. +#[derive(Debug)] +pub(super) enum LifetimeElisionCandidate { + /// This is not a real lifetime. + Ignore, + /// There is a named lifetime, we won't suggest anything. + Named, + Missing(MissingLifetime), +} + impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { fn def_span(&self, def_id: DefId) -> Option { match def_id.krate { @@ -2003,18 +2013,35 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { err.span_label(lifetime_ref.ident.span, "undeclared lifetime"); err }; - let mut suggest_note = true; + self.suggest_introducing_lifetime( + &mut err, + Some(lifetime_ref.ident.name.as_str()), + |err, _, span, message, suggestion| { + err.span_suggestion(span, message, suggestion, Applicability::MaybeIncorrect); + true + }, + ); + err.emit(); + } + fn suggest_introducing_lifetime( + &self, + err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, + name: Option<&str>, + suggest: impl Fn(&mut DiagnosticBuilder<'_, ErrorGuaranteed>, bool, Span, &str, String) -> bool, + ) { + let mut suggest_note = true; for rib in self.lifetime_ribs.iter().rev() { + let mut should_continue = true; match rib.kind { LifetimeRibKind::Generics { binder: _, span, kind } => { - if !span.can_be_used_for_suggestions() && suggest_note { + if !span.can_be_used_for_suggestions() && suggest_note && let Some(name) = name { suggest_note = false; // Avoid displaying the same help multiple times. err.span_label( span, &format!( "lifetime `{}` is missing in item created through this procedural macro", - lifetime_ref.ident, + name, ), ); continue; @@ -2030,46 +2057,42 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { let sugg = format!( "{}<{}>{}", if higher_ranked { "for" } else { "" }, - lifetime_ref.ident, + name.unwrap_or("'a"), if higher_ranked { " " } else { "" }, ); (span, sugg) } else { let span = self.r.session.source_map().span_through_char(span, '<').shrink_to_hi(); - let sugg = format!("{}, ", lifetime_ref.ident); + let sugg = format!("{}, ", name.unwrap_or("'a")); (span, sugg) }; if higher_ranked { - err.span_suggestion( - span, - &format!( - "consider making the {} lifetime-generic with a new `{}` lifetime", - kind.descr(), - lifetime_ref - ), - sugg, - Applicability::MaybeIncorrect, + let message = format!( + "consider making the {} lifetime-generic with a new `{}` lifetime", + kind.descr(), + name.unwrap_or("'a"), ); + should_continue = suggest(err, true, span, &message, sugg); err.note_once( "for more information on higher-ranked polymorphism, visit \ https://doc.rust-lang.org/nomicon/hrtb.html", ); + } else if let Some(name) = name { + let message = format!("consider introducing lifetime `{}` here", name); + should_continue = suggest(err, false, span, &message, sugg); } else { - err.span_suggestion( - span, - &format!("consider introducing lifetime `{}` here", lifetime_ref.ident), - sugg, - Applicability::MaybeIncorrect, - ); + let message = format!("consider introducing a named lifetime parameter"); + should_continue = suggest(err, false, span, &message, sugg); } } LifetimeRibKind::Item => break, _ => {} } + if !should_continue { + break; + } } - - err.emit(); } pub(crate) fn emit_non_static_lt_in_const_generic_error(&self, lifetime_ref: &ast::Lifetime) { @@ -2105,552 +2128,209 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { .emit(); } } -} -/// Report lifetime/lifetime shadowing as an error. -pub fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) { - let mut err = struct_span_err!( - sess, - shadower.span, - E0496, - "lifetime name `{}` shadows a lifetime name that is already in scope", - orig.name, - ); - err.span_label(orig.span, "first declared here"); - err.span_label(shadower.span, format!("lifetime `{}` already in scope", orig.name)); - err.emit(); -} - -/// Shadowing involving a label is only a warning for historical reasons. -//FIXME: make this a proper lint. -pub fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) { - let name = shadower.name; - let shadower = shadower.span; - let mut err = sess.struct_span_warn( - shadower, - &format!("label name `{}` shadows a label name that is already in scope", name), - ); - err.span_label(orig, "first declared here"); - err.span_label(shadower, format!("label `{}` already in scope", name)); - err.emit(); -} - -impl<'tcx> LifetimeContext<'_, 'tcx> { pub(crate) fn report_missing_lifetime_specifiers( - &self, - spans: Vec, - count: usize, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - struct_span_err!( - self.tcx.sess, + &mut self, + lifetime_refs: Vec, + function_param_lifetimes: Option<(Vec, Vec)>, + ) -> ErrorGuaranteed { + let num_lifetimes: usize = lifetime_refs.iter().map(|lt| lt.count).sum(); + let spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect(); + + let mut err = struct_span_err!( + self.r.session, spans, E0106, "missing lifetime specifier{}", - pluralize!(count) - ) + pluralize!(num_lifetimes) + ); + self.add_missing_lifetime_specifiers_label( + &mut err, + lifetime_refs, + function_param_lifetimes, + ); + err.emit() } - /// Returns whether to add `'static` lifetime to the suggested lifetime list. - pub(crate) fn report_elision_failure( - &self, - diag: &mut Diagnostic, - params: &[ElisionFailureInfo], - ) -> bool { - let mut m = String::new(); - let len = params.len(); + pub(crate) fn add_missing_lifetime_specifiers_label( + &mut self, + err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, + lifetime_refs: Vec, + function_param_lifetimes: Option<(Vec, Vec)>, + ) { + for < in &lifetime_refs { + err.span_label( + lt.span, + format!( + "expected {} lifetime parameter{}", + if lt.count == 1 { "named".to_string() } else { lt.count.to_string() }, + pluralize!(lt.count), + ), + ); + } - let elided_params: Vec<_> = - params.iter().cloned().filter(|info| info.lifetime_count > 0).collect(); + let mut in_scope_lifetimes: Vec<_> = self + .lifetime_ribs + .iter() + .rev() + .take_while(|rib| !matches!(rib.kind, LifetimeRibKind::Item)) + .flat_map(|rib| rib.bindings.iter()) + .map(|(&ident, &res)| (ident, res)) + .filter(|(ident, _)| ident.name != kw::UnderscoreLifetime) + .collect(); + debug!(?in_scope_lifetimes); - let elided_len = elided_params.len(); + debug!(?function_param_lifetimes); + if let Some((param_lifetimes, params)) = &function_param_lifetimes { + let elided_len = param_lifetimes.len(); + let num_params = params.len(); - for (i, info) in elided_params.into_iter().enumerate() { - let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } = - info; + let mut m = String::new(); - diag.span_label(span, ""); - let help_name = if let Some(ident) = - parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident()) - { - format!("`{}`", ident) - } else { - format!("argument {}", index + 1) - }; + for (i, info) in params.iter().enumerate() { + let ElisionFnParameter { ident, index, lifetime_count, span } = *info; + debug_assert_ne!(lifetime_count, 0); - m.push_str( - &(if n == 1 { - help_name + err.span_label(span, ""); + + if i != 0 { + if i + 1 < num_params { + m.push_str(", "); + } else if num_params == 2 { + m.push_str(" or "); + } else { + m.push_str(", or "); + } + } + + let help_name = if let Some(ident) = ident { + format!("`{}`", ident) } else { - format!( - "one of {}'s {} {}lifetimes", - help_name, - n, - if have_bound_regions { "free " } else { "" } - ) - })[..], - ); + format!("argument {}", index + 1) + }; - if elided_len == 2 && i == 0 { - m.push_str(" or "); - } else if i + 2 == elided_len { - m.push_str(", or "); - } else if i != elided_len - 1 { - m.push_str(", "); + if lifetime_count == 1 { + m.push_str(&help_name[..]) + } else { + m.push_str(&format!("one of {}'s {} lifetimes", help_name, lifetime_count)[..]) + } } - } - if len == 0 { - diag.help( - "this function's return type contains a borrowed value, \ + if num_params == 0 { + err.help( + "this function's return type contains a borrowed value, \ but there is no value for it to be borrowed from", - ); - true - } else if elided_len == 0 { - diag.help( - "this function's return type contains a borrowed value with \ + ); + if in_scope_lifetimes.is_empty() { + in_scope_lifetimes = vec![( + Ident::with_dummy_span(kw::StaticLifetime), + (DUMMY_NODE_ID, LifetimeRes::Static), + )]; + } + } else if elided_len == 0 { + err.help( + "this function's return type contains a borrowed value with \ an elided lifetime, but the lifetime cannot be derived from \ the arguments", - ); - true - } else if elided_len == 1 { - diag.help(&format!( - "this function's return type contains a borrowed value, \ + ); + if in_scope_lifetimes.is_empty() { + in_scope_lifetimes = vec![( + Ident::with_dummy_span(kw::StaticLifetime), + (DUMMY_NODE_ID, LifetimeRes::Static), + )]; + } + } else if num_params == 1 { + err.help(&format!( + "this function's return type contains a borrowed value, \ but the signature does not say which {} it is borrowed from", - m - )); - false - } else { - diag.help(&format!( - "this function's return type contains a borrowed value, \ + m + )); + } else { + err.help(&format!( + "this function's return type contains a borrowed value, \ but the signature does not say whether it is borrowed from {}", - m - )); - false + m + )); + } } - } - pub(crate) fn is_trait_ref_fn_scope( - &mut self, - trait_ref: &'tcx hir::PolyTraitRef<'tcx>, - ) -> bool { - if let def::Res::Def(_, did) = trait_ref.trait_ref.path.res { - if [ - self.tcx.lang_items().fn_once_trait(), - self.tcx.lang_items().fn_trait(), - self.tcx.lang_items().fn_mut_trait(), - ] - .contains(&Some(did)) - { - 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 }); - return true; - } + let existing_name = match &in_scope_lifetimes[..] { + [] => Symbol::intern("'a"), + [(existing, _)] => existing.name, + _ => Symbol::intern("'lifetime"), }; - false - } - - pub(crate) fn add_missing_lifetime_specifiers_label( - &self, - err: &mut Diagnostic, - mut spans_with_counts: Vec<(Span, usize)>, - in_scope_lifetimes: FxIndexSet, - params: Option<&[ElisionFailureInfo]>, - ) { - let (mut lifetime_names, lifetime_spans): (FxHashSet<_>, Vec<_>) = in_scope_lifetimes - .iter() - .filter_map(|def_id| { - let name = self.tcx.item_name(def_id.to_def_id()); - let span = self.tcx.def_ident_span(def_id.to_def_id())?; - Some((name, span)) - }) - .filter(|&(n, _)| n != kw::UnderscoreLifetime) - .unzip(); - if let Some(params) = params { - // If there's no lifetime available, suggest `'static`. - if self.report_elision_failure(err, params) && lifetime_names.is_empty() { - lifetime_names.insert(kw::StaticLifetime); + let mut spans_suggs: Vec<_> = Vec::new(); + let build_sugg = |lt: MissingLifetime| match lt.kind { + MissingLifetimeKind::Underscore => { + debug_assert_eq!(lt.count, 1); + (lt.span, existing_name.to_string()) } - } - let params = params.unwrap_or(&[]); - - let snippets: Vec> = spans_with_counts - .iter() - .map(|(span, _)| self.tcx.sess.source_map().span_to_snippet(*span).ok()) - .collect(); - - // Empty generics are marked with a span of "<", but since from now on - // that information is in the snippets it can be removed from the spans. - for ((span, _), snippet) in spans_with_counts.iter_mut().zip(&snippets) { - if snippet.as_deref() == Some("<") { - *span = span.shrink_to_hi(); + MissingLifetimeKind::Ampersand => { + debug_assert_eq!(lt.count, 1); + (lt.span.shrink_to_hi(), format!("{} ", existing_name)) } + MissingLifetimeKind::Comma => { + let sugg: String = std::iter::repeat([existing_name.as_str(), ", "]) + .take(lt.count) + .flatten() + .collect(); + (lt.span.shrink_to_hi(), sugg) + } + MissingLifetimeKind::Brackets => { + let sugg: String = std::iter::once("<") + .chain( + std::iter::repeat(existing_name.as_str()).take(lt.count).intersperse(", "), + ) + .chain([">"]) + .collect(); + (lt.span.shrink_to_hi(), sugg) + } + }; + for < in &lifetime_refs { + spans_suggs.push(build_sugg(lt)); } - - for &(span, count) in &spans_with_counts { - err.span_label( - span, - format!( - "expected {} lifetime parameter{}", - if count == 1 { "named".to_string() } else { count.to_string() }, - pluralize!(count), - ), - ); - } - - let suggest_existing = - |err: &mut Diagnostic, - name: Symbol, - formatters: Vec String>>>| { - if let Some(MissingLifetimeSpot::HigherRanked { span: for_span, span_type }) = - self.missing_named_lifetime_spots.iter().rev().next() - { - // When we have `struct S<'a>(&'a dyn Fn(&X) -> &X);` we want to not only suggest - // using `'a`, but also introduce the concept of HRLTs by suggesting - // `struct S<'a>(&'a dyn for<'b> Fn(&X) -> &'b X);`. (#72404) - let mut introduce_suggestion = vec![]; - - let a_to_z_repeat_n = |n| { - (b'a'..=b'z').map(move |c| { - let mut s = '\''.to_string(); - s.extend(std::iter::repeat(char::from(c)).take(n)); - s - }) - }; - - // If all single char lifetime names are present, we wrap around and double the chars. - let lt_name = (1..) - .flat_map(a_to_z_repeat_n) - .map(|lt| Symbol::intern(<)) - .find(|lt| !lifetime_names.contains(lt)) - .unwrap(); - let msg = format!( - "consider making the {} lifetime-generic with a new `{}` lifetime", - span_type.descr(), - lt_name, - ); - err.note( - "for more information on higher-ranked polymorphism, visit \ - https://doc.rust-lang.org/nomicon/hrtb.html", - ); - let for_sugg = span_type.suggestion(<_name); - for param in params { - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span) - { - if snippet.starts_with('&') && !snippet.starts_with("&'") { - introduce_suggestion - .push((param.span, format!("&{} {}", lt_name, &snippet[1..]))); - } else if let Some(stripped) = snippet.strip_prefix("&'_ ") { - introduce_suggestion - .push((param.span, format!("&{} {}", lt_name, stripped))); - } - } + debug!(?spans_suggs); + match in_scope_lifetimes.len() { + 0 => { + if let Some((param_lifetimes, _)) = function_param_lifetimes { + for lt in param_lifetimes { + spans_suggs.push(build_sugg(lt)) } - introduce_suggestion.push((*for_span, for_sugg)); - for ((span, _), formatter) in spans_with_counts.iter().zip(formatters.iter()) { - if let Some(formatter) = formatter { - introduce_suggestion.push((*span, formatter(lt_name))); - } - } - err.multipart_suggestion_verbose( - &msg, - introduce_suggestion, - Applicability::MaybeIncorrect, - ); } - - let spans_suggs: Vec<_> = formatters - .into_iter() - .zip(spans_with_counts.iter()) - .filter_map(|(formatter, (span, _))| { - if let Some(formatter) = formatter { - Some((*span, formatter(name))) - } else { - None - } - }) - .collect(); - if spans_suggs.is_empty() { - // If all the spans come from macros, we cannot extract snippets and then - // `formatters` only contains None and `spans_suggs` is empty. - return; - } - err.multipart_suggestion_verbose( - &format!( - "consider using the `{}` lifetime", - lifetime_names.iter().next().unwrap() - ), - spans_suggs, - Applicability::MaybeIncorrect, - ); - }; - let suggest_new = |err: &mut Diagnostic, suggs: Vec>| { - for missing in self.missing_named_lifetime_spots.iter().rev() { - let mut introduce_suggestion = vec![]; - let msg; - let should_break; - introduce_suggestion.push(match missing { - MissingLifetimeSpot::Generics(generics) => { - if generics.span == DUMMY_SP { - // Account for malformed generics in the HIR. This shouldn't happen, - // but if we make a mistake elsewhere, mainly by keeping something in - // `missing_named_lifetime_spots` that we shouldn't, like associated - // `const`s or making a mistake in the AST lowering we would provide - // nonsensical suggestions. Guard against that by skipping these. - // (#74264) - continue; - } - msg = "consider introducing a named lifetime parameter".to_string(); - should_break = true; - if let Some(param) = generics.params.iter().find(|p| { - !matches!( - p.kind, - hir::GenericParamKind::Type { synthetic: true, .. } - | hir::GenericParamKind::Lifetime { - kind: hir::LifetimeParamKind::Elided - } - ) - }) { - (param.span.shrink_to_lo(), "'a, ".to_string()) - } else { - (generics.span, "<'a>".to_string()) - } - } - MissingLifetimeSpot::HigherRanked { span, span_type } => { - msg = format!( - "consider making the {} lifetime-generic with a new `'a` lifetime", - span_type.descr(), - ); - should_break = false; - err.note( - "for more information on higher-ranked polymorphism, visit \ - https://doc.rust-lang.org/nomicon/hrtb.html", - ); - (*span, span_type.suggestion("'a")) - } - MissingLifetimeSpot::Static => { - let mut spans_suggs = Vec::new(); - for ((span, count), snippet) in - spans_with_counts.iter().copied().zip(snippets.iter()) - { - let (span, sugg) = match snippet.as_deref() { - Some("&") => (span.shrink_to_hi(), "'static ".to_owned()), - Some("'_") => (span, "'static".to_owned()), - Some(snippet) if !snippet.ends_with('>') => { - if snippet == "" { - ( - span, - std::iter::repeat("'static") - .take(count) - .collect::>() - .join(", "), - ) - } else if snippet == "<" || snippet == "(" { - ( - span.shrink_to_hi(), - std::iter::repeat("'static") - .take(count) - .collect::>() - .join(", "), - ) - } else { - ( - span.shrink_to_hi(), - format!( - "<{}>", - std::iter::repeat("'static") - .take(count) - .collect::>() - .join(", "), - ), - ) - } - } - _ => continue, - }; - spans_suggs.push((span, sugg.to_string())); - } + self.suggest_introducing_lifetime( + err, + None, + |err, higher_ranked, span, message, intro_sugg| { err.multipart_suggestion_verbose( - "consider using the `'static` lifetime", - spans_suggs, + message, + std::iter::once((span, intro_sugg)) + .chain(spans_suggs.clone()) + .collect(), Applicability::MaybeIncorrect, ); - continue; - } - }); - - struct Lifetime(Span, String); - impl Lifetime { - fn is_unnamed(&self) -> bool { - self.1.starts_with('&') && !self.1.starts_with("&'") - } - fn is_underscore(&self) -> bool { - self.1.starts_with("&'_ ") - } - fn is_named(&self) -> bool { - self.1.starts_with("&'") - } - fn suggestion(&self, sugg: String) -> Option<(Span, String)> { - Some( - match ( - self.is_unnamed(), - self.is_underscore(), - self.is_named(), - sugg.starts_with('&'), - ) { - (true, _, _, false) => (self.span_unnamed_borrow(), sugg), - (true, _, _, true) => { - (self.span_unnamed_borrow(), sugg[1..].to_string()) - } - (_, true, _, false) => { - (self.span_underscore_borrow(), sugg.trim().to_string()) - } - (_, true, _, true) => { - (self.span_underscore_borrow(), sugg[1..].trim().to_string()) - } - (_, _, true, false) => { - (self.span_named_borrow(), sugg.trim().to_string()) - } - (_, _, true, true) => { - (self.span_named_borrow(), sugg[1..].trim().to_string()) - } - _ => return None, - }, - ) - } - fn span_unnamed_borrow(&self) -> Span { - let lo = self.0.lo() + BytePos(1); - self.0.with_lo(lo).with_hi(lo) - } - fn span_named_borrow(&self) -> Span { - let lo = self.0.lo() + BytePos(1); - self.0.with_lo(lo) - } - fn span_underscore_borrow(&self) -> Span { - let lo = self.0.lo() + BytePos(1); - let hi = lo + BytePos(2); - self.0.with_lo(lo).with_hi(hi) - } - } - - for param in params { - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span) { - if let Some((span, sugg)) = - Lifetime(param.span, snippet).suggestion("'a ".to_string()) - { - introduce_suggestion.push((span, sugg)); - } - } - } - for (span, sugg) in spans_with_counts.iter().copied().zip(suggs.iter()).filter_map( - |((span, _), sugg)| match &sugg { - Some(sugg) => Some((span, sugg.to_string())), - _ => None, + higher_ranked }, - ) { - let (span, sugg) = self - .tcx - .sess - .source_map() - .span_to_snippet(span) - .ok() - .and_then(|snippet| Lifetime(span, snippet).suggestion(sugg.clone())) - .unwrap_or((span, sugg)); - introduce_suggestion.push((span, sugg.to_string())); - } + ); + } + 1 => { err.multipart_suggestion_verbose( - &msg, - introduce_suggestion, + &format!("consider using the `{}` lifetime", existing_name), + spans_suggs, Applicability::MaybeIncorrect, ); - if should_break { - break; - } - } - }; - let lifetime_names: Vec<_> = lifetime_names.iter().collect(); - match &lifetime_names[..] { - [name] => { - let mut suggs: Vec String>>> = Vec::new(); - for (snippet, (_, count)) in snippets.iter().zip(spans_with_counts.iter().copied()) - { - suggs.push(match snippet.as_deref() { - Some("&") => Some(Box::new(|name| format!("&{} ", name))), - Some("'_") => Some(Box::new(|n| n.to_string())), - Some("") => Some(Box::new(move |n| format!("{}, ", n).repeat(count))), - Some("<") => Some(Box::new(move |n| { - std::iter::repeat(n) - .take(count) - .map(|n| n.to_string()) - .collect::>() - .join(", ") - })), - Some(snippet) if !snippet.ends_with('>') => Some(Box::new(move |name| { - format!( - "{}<{}>", - snippet, - std::iter::repeat(name.to_string()) - .take(count) - .collect::>() - .join(", ") - ) - })), - _ => None, - }); + // Record as using the suggested resolution. + let (_, (_, res)) = in_scope_lifetimes[0]; + for < in &lifetime_refs { + self.r.lifetimes_res_map.insert(lt.id, res); } - suggest_existing(err, **name, suggs); } - [] => { - let mut suggs = Vec::new(); - for (snippet, (_, count)) in - snippets.iter().cloned().zip(spans_with_counts.iter().copied()) - { - suggs.push(match snippet.as_deref() { - Some("&") => Some("&'a ".to_string()), - Some("'_") => Some("'a".to_string()), - Some("") => { - Some(std::iter::repeat("'a, ").take(count).collect::>().join("")) - } - Some("<") => { - Some(std::iter::repeat("'a").take(count).collect::>().join(", ")) - } - Some(snippet) => Some(format!( - "{}<{}>", - snippet, - std::iter::repeat("'a").take(count).collect::>().join(", "), - )), - None => None, - }); - } - suggest_new(err, suggs); - } - lts if lts.len() > 1 => { + _ => { + let lifetime_spans: Vec<_> = + in_scope_lifetimes.iter().map(|(ident, _)| ident.span).collect(); err.span_note(lifetime_spans, "these named lifetimes are available to use"); - let mut spans_suggs: Vec<_> = Vec::new(); - for ((span, _), snippet) in spans_with_counts.iter().copied().zip(snippets.iter()) { - match snippet.as_deref() { - Some("") => spans_suggs.push((span, "'lifetime, ".to_string())), - Some("&") => spans_suggs - .push((span.with_lo(span.lo() + BytePos(1)), "'lifetime ".to_string())), - _ => {} - } - } - if spans_suggs.len() > 0 { // This happens when we have `Foo` where we point at the space before `T`, // but this can be confusing so we give a suggestion with placeholders. @@ -2661,7 +2341,34 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { ); } } - _ => unreachable!(), } } } + +/// Report lifetime/lifetime shadowing as an error. +pub fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) { + let mut err = struct_span_err!( + sess, + shadower.span, + E0496, + "lifetime name `{}` shadows a lifetime name that is already in scope", + orig.name, + ); + err.span_label(orig.span, "first declared here"); + err.span_label(shadower.span, format!("lifetime `{}` already in scope", orig.name)); + err.emit(); +} + +/// Shadowing involving a label is only a warning for historical reasons. +//FIXME: make this a proper lint. +pub fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) { + let name = shadower.name; + let shadower = shadower.span; + let mut err = sess.struct_span_warn( + shadower, + &format!("label name `{}` shadows a label name that is already in scope", name), + ); + err.span_label(orig, "first declared here"); + err.span_label(shadower, format!("label `{}` already in scope", name)); + err.emit(); +} diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 0eb11cd3e9fad..a7fd7c427c759 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -1,12 +1,12 @@ // ignore-tidy-filelength -//! Name resolution for lifetimes. +//! Resolution of early vs late bound lifetimes. //! -//! Name resolution for lifetimes follows *much* simpler rules than the -//! full resolve. For example, lifetime names are never exported or -//! used between functions, and they operate in a purely top-down -//! way. Therefore, we break lifetime name resolution into a separate pass. +//! Name resolution for lifetimes is performed on the AST and embedded into HIR. From this +//! information, typechecking needs to transform the lifetime parameters into bound lifetimes. +//! Lifetimes can be early-bound or late-bound. Construction of typechecking terms needs to visit +//! the types in HIR to identify late-bound lifetimes and assign their Debruijn indices. This file +//! is also responsible for assigning their semantics to implicit lifetimes in trait objects. -use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot}; use rustc_ast::walk_list; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::struct_span_err; @@ -14,13 +14,12 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefIdMap, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node}; -use rustc_hir::{GenericParamKind, HirIdMap, LifetimeParamKind}; +use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeName, Node}; +use rustc_middle::bug; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_lifetime::*; use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt}; -use rustc_middle::{bug, span_bug}; use rustc_span::def_id::DefId; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; @@ -152,10 +151,6 @@ pub(crate) struct LifetimeContext<'a, 'tcx> { /// Cache for cross-crate per-definition object lifetime defaults. xcrate_object_lifetime_defaults: DefIdMap>, - - /// When encountering an undefined named lifetime, we will suggest introducing it in these - /// places. - pub(crate) missing_named_lifetime_spots: Vec>, } #[derive(Debug)] @@ -323,23 +318,12 @@ enum Elide { /// Always use this one lifetime. Exact(Region), /// Less or more than one lifetime were found, error on unspecified. - Error(Vec), + Error, /// Forbid lifetime elision inside of a larger scope where it would be /// permitted. For example, in let position impl trait. Forbid, } -#[derive(Clone, Debug)] -pub(crate) struct ElisionFailureInfo { - /// Where we can find the argument pattern. - pub(crate) parent: Option, - /// The index of the argument in the original definition. - pub(crate) index: usize, - pub(crate) lifetime_count: usize, - pub(crate) have_bound_regions: bool, - pub(crate) span: Span, -} - type ScopeRef<'a> = &'a Scope<'a>; const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root; @@ -421,7 +405,6 @@ fn do_resolve( scope: ROOT_SCOPE, trait_definition_only, xcrate_object_lifetime_defaults: Default::default(), - missing_named_lifetime_spots: vec![], }; visitor.visit_item(item); @@ -644,40 +627,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { where_bound_origin: None, }; - if let &hir::ClosureBinder::For { span, .. } = binder { - let last_lt = bound_generic_params - .iter() - .filter(|p| { - matches!( - p, - GenericParam { - kind: GenericParamKind::Lifetime { - kind: LifetimeParamKind::Explicit - }, - .. - } - ) - }) - .last(); - let (span, span_type) = match last_lt { - Some(GenericParam { span: last_sp, .. }) => { - (last_sp.shrink_to_hi(), ForLifetimeSpanType::ClosureTail) - } - None => (span, ForLifetimeSpanType::ClosureEmpty), - }; - self.missing_named_lifetime_spots - .push(MissingLifetimeSpot::HigherRanked { span, span_type }); - } - self.with(scope, |this| { // a closure has no bounds, so everything // contained within is scoped within its binder. intravisit::walk_expr(this, e) }); - - if let hir::ClosureBinder::For { .. } = binder { - self.missing_named_lifetime_spots.pop(); - } } else { intravisit::walk_expr(self, e) } @@ -694,11 +648,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } match item.kind { hir::ItemKind::Fn(_, ref generics, _) => { - self.missing_named_lifetime_spots.push(generics.into()); self.visit_early_late(None, item.hir_id(), generics, |this| { intravisit::walk_item(this, item); }); - self.missing_named_lifetime_spots.pop(); } hir::ItemKind::ExternCrate(_) @@ -761,8 +713,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { | hir::ItemKind::Trait(_, _, ref generics, ..) | hir::ItemKind::TraitAlias(ref generics, ..) | hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => { - self.missing_named_lifetime_spots.push(generics.into()); - // These kinds of items have only early-bound lifetime parameters. let mut index = if sub_items_have_self_param(&item.kind) { 1 // Self comes before lifetimes @@ -800,7 +750,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { intravisit::walk_item(this, item); }); }); - self.missing_named_lifetime_spots.pop(); } } } @@ -826,20 +775,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { match ty.kind { hir::TyKind::BareFn(ref c) => { 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 { kind: hir::LifetimeParamKind::Explicit } => { - Some(param.span) - } - _ => None, - }); - let (span, span_type) = if let Some(span) = lifetime_span { - (span.shrink_to_hi(), ForLifetimeSpanType::TypeTail) - } else { - (ty.span.shrink_to_lo(), ForLifetimeSpanType::TypeEmpty) - }; - self.missing_named_lifetime_spots - .push(MissingLifetimeSpot::HigherRanked { span, span_type }); let (lifetimes, binders): (FxIndexMap, Vec<_>) = c .generic_params .iter() @@ -867,7 +802,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // contained within is scoped within its binder. intravisit::walk_ty(this, ty); }); - self.missing_named_lifetime_spots.pop(); } hir::TyKind::TraitObject(bounds, ref lifetime, _) => { debug!(?bounds, ?lifetime, "TraitObject"); @@ -878,11 +812,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } }); match lifetime.name { - LifetimeName::Implicit => { - // For types like `dyn Foo`, we should - // generate a special form of elided. - span_bug!(ty.span, "object-lifetime-default expected, not implicit",); - } LifetimeName::ImplicitObjectLifetimeDefault => { // If the user does not write *anything*, we // use the object lifetime defaulting @@ -890,7 +819,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // `Box`. self.resolve_object_lifetime_default(lifetime) } - LifetimeName::Underscore => { + LifetimeName::Implicit | LifetimeName::Underscore => { // If the user writes `'_`, we use the *ordinary* elision // rules. So the `'_` in e.g., `Box` will be // resolved the same as the `'_` in `&'_ Foo`. @@ -1010,10 +939,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let mut elision = None; let mut lifetimes = FxIndexMap::default(); let mut non_lifetime_count = 0; + debug!(?generics.params); for param in generics.params { match param.kind { GenericParamKind::Lifetime { .. } => { let (def_id, reg) = Region::early(self.tcx.hir(), &mut index, ¶m); + lifetimes.insert(def_id, reg); if let hir::ParamName::Plain(Ident { name: kw::UnderscoreLifetime, .. @@ -1022,8 +953,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // Pick the elided lifetime "definition" if one exists // and use it to make an elision scope. elision = Some(reg); - } else { - lifetimes.insert(def_id, reg); } } GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { @@ -1088,7 +1017,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { use self::hir::TraitItemKind::*; match trait_item.kind { Fn(_, _) => { - self.missing_named_lifetime_spots.push((&trait_item.generics).into()); let tcx = self.tcx; self.visit_early_late( Some(tcx.hir().get_parent_item(trait_item.hir_id())), @@ -1096,10 +1024,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { &trait_item.generics, |this| intravisit::walk_trait_item(this, trait_item), ); - self.missing_named_lifetime_spots.pop(); } Type(bounds, ref ty) => { - self.missing_named_lifetime_spots.push((&trait_item.generics).into()); let generics = &trait_item.generics; let mut index = self.next_early_index(); debug!("visit_ty: index = {}", index); @@ -1140,14 +1066,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } }) }); - self.missing_named_lifetime_spots.pop(); } Const(_, _) => { // Only methods and types support generics. assert!(trait_item.generics.params.is_empty()); - self.missing_named_lifetime_spots.push(MissingLifetimeSpot::Static); intravisit::walk_trait_item(self, trait_item); - self.missing_named_lifetime_spots.pop(); } } } @@ -1156,7 +1079,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { use self::hir::ImplItemKind::*; match impl_item.kind { Fn(..) => { - self.missing_named_lifetime_spots.push((&impl_item.generics).into()); let tcx = self.tcx; self.visit_early_late( Some(tcx.hir().get_parent_item(impl_item.hir_id())), @@ -1164,11 +1086,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { &impl_item.generics, |this| intravisit::walk_impl_item(this, impl_item), ); - self.missing_named_lifetime_spots.pop(); } TyAlias(ref ty) => { let generics = &impl_item.generics; - self.missing_named_lifetime_spots.push(generics.into()); let mut index = self.next_early_index(); let mut non_lifetime_count = 0; debug!("visit_ty: index = {}", index); @@ -1203,14 +1123,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { this.visit_ty(ty); }) }); - self.missing_named_lifetime_spots.pop(); } Const(_, _) => { // Only methods and types support generics. assert!(impl_item.generics.params.is_empty()); - self.missing_named_lifetime_spots.push(MissingLifetimeSpot::Static); intravisit::walk_impl_item(self, impl_item); - self.missing_named_lifetime_spots.pop(); } } } @@ -1393,8 +1310,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { ) { debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref); - let should_pop_missing_lt = self.is_trait_ref_fn_scope(trait_ref); - let next_early_index = self.next_early_index(); let (mut binders, scope_type) = self.poly_trait_ref_binder_info(); @@ -1435,10 +1350,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { walk_list!(this, visit_generic_param, trait_ref.bound_generic_params); this.visit_trait_ref(&trait_ref.trait_ref); }); - - if should_pop_missing_lt { - self.missing_named_lifetime_spots.pop(); - } } } @@ -1584,14 +1495,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { { let LifetimeContext { tcx, map, .. } = self; let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults); - let missing_named_lifetime_spots = take(&mut self.missing_named_lifetime_spots); let mut this = LifetimeContext { tcx: *tcx, map, scope: &wrap_scope, trait_definition_only: self.trait_definition_only, xcrate_object_lifetime_defaults, - missing_named_lifetime_spots, }; let span = tracing::debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope)); { @@ -1599,7 +1508,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { f(&mut this); } self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults; - self.missing_named_lifetime_spots = this.missing_named_lifetime_spots; } /// Visits self by adding a scope and handling recursive walk over the contents with `walk`. @@ -2202,24 +2110,20 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let mut assoc_item_kind = None; let mut impl_self = None; let parent = self.tcx.hir().get_parent_node(output.hir_id); - let body = match self.tcx.hir().get(parent) { + match self.tcx.hir().get(parent) { // `fn` definitions and methods. - Node::Item(&hir::Item { kind: hir::ItemKind::Fn(.., body), .. }) => Some(body), + Node::Item(&hir::Item { kind: hir::ItemKind::Fn(..), .. }) => {} - Node::TraitItem(&hir::TraitItem { kind: hir::TraitItemKind::Fn(_, ref m), .. }) => { + Node::TraitItem(&hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) => { if let hir::ItemKind::Trait(.., ref trait_items) = self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind { assoc_item_kind = trait_items.iter().find(|ti| ti.id.hir_id() == parent).map(|ti| ti.kind); } - match *m { - hir::TraitFn::Required(_) => None, - hir::TraitFn::Provided(body) => Some(body), - } } - Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body), .. }) => { + Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, _), .. }) => { if let hir::ItemKind::Impl(hir::Impl { ref self_ty, ref items, .. }) = self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind { @@ -2227,13 +2131,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { assoc_item_kind = items.iter().find(|ii| ii.id.hir_id() == parent).map(|ii| ii.kind); } - Some(body) } // Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds). - Node::ForeignItem(_) | Node::Ty(_) | Node::TraitRef(_) => None, + Node::ForeignItem(_) | Node::Ty(_) | Node::TraitRef(_) => {}, - Node::TypeBinding(_) if let Node::TraitRef(_) = self.tcx.hir().get(self.tcx.hir().get_parent_node(parent)) => None, + Node::TypeBinding(_) if let Node::TraitRef(_) = self.tcx.hir().get(self.tcx.hir().get_parent_node(parent)) => {}, // Everything else (only closures?) doesn't // actually enjoy elision in return types. @@ -2320,42 +2223,29 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { // have that lifetime. let mut possible_implied_output_region = None; let mut lifetime_count = 0; - let arg_lifetimes = inputs - .iter() - .enumerate() - .skip(has_self as usize) - .map(|(i, input)| { - let mut gather = GatherLifetimes { - map: self.map, - outer_index: ty::INNERMOST, - have_bound_regions: false, - lifetimes: Default::default(), - }; - gather.visit_ty(input); - - lifetime_count += gather.lifetimes.len(); + for input in inputs.iter().skip(has_self as usize) { + let mut gather = GatherLifetimes { + map: self.map, + outer_index: ty::INNERMOST, + have_bound_regions: false, + lifetimes: Default::default(), + }; + gather.visit_ty(input); - if lifetime_count == 1 && gather.lifetimes.len() == 1 { - // there's a chance that the unique lifetime of this - // iteration will be the appropriate lifetime for output - // parameters, so lets store it. - possible_implied_output_region = gather.lifetimes.iter().cloned().next(); - } + lifetime_count += gather.lifetimes.len(); - ElisionFailureInfo { - parent: body, - index: i, - lifetime_count: gather.lifetimes.len(), - have_bound_regions: gather.have_bound_regions, - span: input.span, - } - }) - .collect(); + if lifetime_count == 1 && gather.lifetimes.len() == 1 { + // there's a chance that the unique lifetime of this + // iteration will be the appropriate lifetime for output + // parameters, so lets store it. + possible_implied_output_region = gather.lifetimes.iter().cloned().next(); + } + } let elide = if lifetime_count == 1 { Elide::Exact(possible_implied_output_region.unwrap()) } else { - Elide::Error(arg_lifetimes) + Elide::Error }; debug!(?elide); @@ -2487,17 +2377,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let mut late_depth = 0; let mut scope = self.scope; - let mut in_scope_lifetimes = FxIndexSet::default(); - let error = loop { + loop { match *scope { // Do not assign any resolution, it will be inferred. Scope::Body { .. } => return, - Scope::Root => break None, + Scope::Root => break, - Scope::Binder { s, ref lifetimes, scope_type, .. } => { - // collect named lifetimes for suggestions - in_scope_lifetimes.extend(lifetimes.keys().copied()); + Scope::Binder { s, scope_type, .. } => { match scope_type { BinderScopeType::Normal => late_depth += 1, BinderScopeType::Concatenating => {} @@ -2526,27 +2413,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { return; } - Scope::Elision { elide: Elide::Error(ref e), ref s, .. } => { - let mut scope = s; - loop { - match scope { - Scope::Binder { ref lifetimes, s, .. } => { - // Collect named lifetimes for suggestions. - in_scope_lifetimes.extend(lifetimes.keys().copied()); - scope = s; - } - Scope::ObjectLifetimeDefault { ref s, .. } - | Scope::Elision { ref s, .. } - | Scope::TraitRefBoundary { ref s, .. } => { - scope = s; - } - _ => break, - } - } - break Some(&e[..]); - } - - Scope::Elision { elide: Elide::Forbid, .. } => break None, + Scope::Elision { elide: Elide::Error, .. } + | Scope::Elision { elide: Elide::Forbid, .. } => break, Scope::ObjectLifetimeDefault { s, .. } | Scope::Supertrait { s, .. } @@ -2554,26 +2422,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { scope = s; } } - }; - - let mut spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect(); - spans.sort(); - let mut spans_dedup = spans.clone(); - spans_dedup.dedup(); - let spans_with_counts: Vec<_> = spans_dedup - .into_iter() - .map(|sp| (sp, spans.iter().filter(|nsp| *nsp == &sp).count())) - .collect(); - - let mut err = self.report_missing_lifetime_specifiers(spans.clone(), lifetime_refs.len()); + } - self.add_missing_lifetime_specifiers_label( - &mut err, - spans_with_counts, - in_scope_lifetimes, - error, - ); - err.emit(); + for lt in lifetime_refs { + self.tcx.sess.delay_span_bug(lt.span, "Missing lifetime specifier"); + } } fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 2fcbe1d4c14a5..6945306a69189 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -11,6 +11,7 @@ #![feature(drain_filter)] #![feature(if_let_guard)] #![cfg_attr(bootstrap, feature(let_chains))] +#![feature(iter_intersperse)] #![feature(let_else)] #![feature(never_type)] #![recursion_limit = "256"] diff --git a/src/test/ui/associated-type-bounds/elision.rs b/src/test/ui/associated-type-bounds/elision.rs new file mode 100644 index 0000000000000..4a533939931b2 --- /dev/null +++ b/src/test/ui/associated-type-bounds/elision.rs @@ -0,0 +1,9 @@ +#![feature(associated_type_bounds)] +#![feature(anonymous_lifetime_in_impl_trait)] + +// The same thing should happen for constaints in dyn trait. +fn f(x: &mut dyn Iterator>) -> Option<&'_ ()> { x.next() } +//~^ ERROR missing lifetime specifier +//~| ERROR mismatched types + +fn main() {} diff --git a/src/test/ui/associated-type-bounds/elision.stderr b/src/test/ui/associated-type-bounds/elision.stderr new file mode 100644 index 0000000000000..ea30246274965 --- /dev/null +++ b/src/test/ui/associated-type-bounds/elision.stderr @@ -0,0 +1,28 @@ +error[E0106]: missing lifetime specifier + --> $DIR/elision.rs:5:70 + | +LL | fn f(x: &mut dyn Iterator>) -> Option<&'_ ()> { x.next() } + | ------------------------------------------------ ^^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say which one of `x`'s 2 lifetimes it is borrowed from +help: consider introducing a named lifetime parameter + | +LL | fn f<'a>(x: &'a mut dyn Iterator>) -> Option<&'a ()> { x.next() } + | ++++ ++ ~~ ~~ + +error[E0308]: mismatched types + --> $DIR/elision.rs:5:79 + | +LL | fn f(x: &mut dyn Iterator>) -> Option<&'_ ()> { x.next() } + | ----------------------------- -------------- ^^^^^^^^ expected `&()`, found type parameter `impl Iterator` + | | | + | | expected `Option<&'static ()>` because of return type + | this type parameter + | + = note: expected enum `Option<&'static ()>` + found enum `Option>` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0106, E0308. +For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr b/src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr index e8e07997c721d..4de4afb6e9246 100644 --- a/src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr +++ b/src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr @@ -5,15 +5,10 @@ LL | fn elision &i32>() { | ^ 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 - = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html -help: consider making the bound lifetime-generic with a new `'a` lifetime - | -LL | fn elision Fn() -> &'a i32>() { - | +++++++ ~~~ help: consider using the `'static` lifetime | LL | fn elision &'static i32>() { - | ~~~~~~~~ + | +++++++ error: aborting due to previous error diff --git a/src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr b/src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr index c75e732b7ca4c..7753d186504f8 100644 --- a/src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr +++ b/src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr @@ -5,15 +5,10 @@ LL | fn elision(_: fn() -> &i32) { | ^ 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 - = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html -help: consider making the type lifetime-generic with a new `'a` lifetime - | -LL | fn elision(_: for<'a> fn() -> &'a i32) { - | +++++++ ~~~ help: consider using the `'static` lifetime | LL | fn elision(_: fn() -> &'static i32) { - | ~~~~~~~~ + | +++++++ error: aborting due to previous error diff --git a/src/test/ui/async-await/issues/issue-63388-2.rs b/src/test/ui/async-await/issues/issue-63388-2.rs index 458bc9faeaf27..90b59f96e5f55 100644 --- a/src/test/ui/async-await/issues/issue-63388-2.rs +++ b/src/test/ui/async-await/issues/issue-63388-2.rs @@ -11,6 +11,7 @@ impl Xyz { foo: &dyn Foo, bar: &'a dyn Foo ) -> &dyn Foo //~ ERROR missing lifetime specifier { + //~^ ERROR explicit lifetime required in the type of `foo` [E0621] foo } } diff --git a/src/test/ui/async-await/issues/issue-63388-2.stderr b/src/test/ui/async-await/issues/issue-63388-2.stderr index 24fd3845b4e04..e515f227c7ef6 100644 --- a/src/test/ui/async-await/issues/issue-63388-2.stderr +++ b/src/test/ui/async-await/issues/issue-63388-2.stderr @@ -10,8 +10,21 @@ LL | ) -> &dyn Foo help: consider using the `'a` lifetime | LL | ) -> &'a dyn Foo - | ~~~ + | ++ -error: aborting due to previous error +error[E0621]: explicit lifetime required in the type of `foo` + --> $DIR/issue-63388-2.rs:13:5 + | +LL | foo: &dyn Foo, bar: &'a dyn Foo + | -------- help: add explicit lifetime `'a` to the type of `foo`: `&'a (dyn Foo + 'a)` +LL | ) -> &dyn Foo +LL | / { +LL | | +LL | | foo +LL | | } + | |_____^ lifetime `'a` required + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0106`. +Some errors have detailed explanations: E0106, E0621. +For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/c-variadic/variadic-ffi-6.stderr b/src/test/ui/c-variadic/variadic-ffi-6.stderr index bb15cc000a46b..4c7792d965019 100644 --- a/src/test/ui/c-variadic/variadic-ffi-6.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-6.stderr @@ -4,11 +4,11 @@ error[E0106]: missing lifetime specifier LL | ) -> &usize { | ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments + = 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 | ) -> &'static usize { - | ~~~~~~~~ + | +++++++ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0106.stderr b/src/test/ui/error-codes/E0106.stderr index fbd77d9670091..d11a24f776855 100644 --- a/src/test/ui/error-codes/E0106.stderr +++ b/src/test/ui/error-codes/E0106.stderr @@ -23,6 +23,17 @@ LL | A(u8), LL ~ B(&'a bool), | +error[E0106]: missing lifetime specifier + --> $DIR/E0106.rs:10:14 + | +LL | type MyStr = &str; + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type MyStr<'a> = &'a str; + | ++++ ++ + error[E0106]: missing lifetime specifier --> $DIR/E0106.rs:17:10 | @@ -50,17 +61,6 @@ LL | LL ~ buzz: Buzz<'a, 'a>, | -error[E0106]: missing lifetime specifier - --> $DIR/E0106.rs:10:14 - | -LL | type MyStr = &str; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type MyStr<'a> = &'a str; - | ++++ ++ - error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/error-codes/E0637.stderr b/src/test/ui/error-codes/E0637.stderr index 87aaba65a73ad..35a4b34fb0a4d 100644 --- a/src/test/ui/error-codes/E0637.stderr +++ b/src/test/ui/error-codes/E0637.stderr @@ -4,12 +4,6 @@ error[E0637]: `'_` cannot be used here LL | fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str { | ^^ `'_` is a reserved lifetime name -error[E0637]: `&` without an explicit lifetime name cannot be used here - --> $DIR/E0637.rs:13:13 - | -LL | T: Into<&u32>, - | ^ explicit lifetime name needed here - error[E0106]: missing lifetime specifier --> $DIR/E0637.rs:1:62 | @@ -22,6 +16,12 @@ help: consider introducing a named lifetime parameter LL | fn underscore_lifetime<'a, '_>(str1: &'a str, str2: &'a str) -> &'a str { | +++ ~~ ~~ ~~ +error[E0637]: `&` without an explicit lifetime name cannot be used here + --> $DIR/E0637.rs:13:13 + | +LL | T: Into<&u32>, + | ^ explicit lifetime name needed here + error: aborting due to 3 previous errors Some errors have detailed explanations: E0106, E0637. diff --git a/src/test/ui/foreign-fn-return-lifetime.stderr b/src/test/ui/foreign-fn-return-lifetime.stderr index b174766cd3d0c..df1a23a19edd5 100644 --- a/src/test/ui/foreign-fn-return-lifetime.stderr +++ b/src/test/ui/foreign-fn-return-lifetime.stderr @@ -8,7 +8,7 @@ LL | pub fn f() -> &u8; help: consider using the `'static` lifetime | LL | pub fn f() -> &'static u8; - | ~~~~~~~~ + | +++++++ error: aborting due to previous error diff --git a/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.rs b/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.rs index 246659a268ac9..dbf7e02aeafcc 100644 --- a/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.rs +++ b/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.rs @@ -7,9 +7,10 @@ trait Foo { } impl Foo for T { + //~^ ERROR: the type parameter `T1` is not constrained type F = &[u8]; //~^ ERROR: the name `T1` is already used for - //~| ERROR: missing lifetime specifier + //~| ERROR: `&` without an explicit lifetime name cannot be used here } fn main() {} diff --git a/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.stderr b/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.stderr index e82cbf7e8e5ef..dad0dae6a44bf 100644 --- a/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.stderr +++ b/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.stderr @@ -1,23 +1,25 @@ error[E0403]: the name `T1` is already used for a generic parameter in this item's generic parameters - --> $DIR/gat-trait-path-generic-type-arg.rs:10:12 + --> $DIR/gat-trait-path-generic-type-arg.rs:11:12 | LL | impl Foo for T { | -- first use of `T1` +LL | LL | type F = &[u8]; | ^^ already used -error[E0106]: missing lifetime specifier - --> $DIR/gat-trait-path-generic-type-arg.rs:10:18 +error[E0637]: `&` without an explicit lifetime name cannot be used here + --> $DIR/gat-trait-path-generic-type-arg.rs:11:18 | LL | type F = &[u8]; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter + | ^ explicit lifetime name needed here + +error[E0207]: the type parameter `T1` is not constrained by the impl trait, self type, or predicates + --> $DIR/gat-trait-path-generic-type-arg.rs:9:10 | -LL | type F<'a, T1> = &'a [u8]; - | +++ ++ +LL | impl Foo for T { + | ^^ unconstrained type parameter -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0106, E0403. -For more information about an error, try `rustc --explain E0106`. +Some errors have detailed explanations: E0207, E0403, E0637. +For more information about an error, try `rustc --explain E0207`. diff --git a/src/test/ui/generic-associated-types/issue-70304.rs b/src/test/ui/generic-associated-types/issue-70304.rs index c9fd7248a8004..f778f985cf0d1 100644 --- a/src/test/ui/generic-associated-types/issue-70304.rs +++ b/src/test/ui/generic-associated-types/issue-70304.rs @@ -2,6 +2,7 @@ trait Document { type Cursor<'a>: DocCursor<'a>; + //~^ ERROR: missing required bound on `Cursor` fn cursor(&self) -> Self::Cursor<'_>; } diff --git a/src/test/ui/generic-associated-types/issue-70304.stderr b/src/test/ui/generic-associated-types/issue-70304.stderr index b3881ccb099f0..bba7cab7093ce 100644 --- a/src/test/ui/generic-associated-types/issue-70304.stderr +++ b/src/test/ui/generic-associated-types/issue-70304.stderr @@ -1,11 +1,11 @@ error[E0637]: `'_` cannot be used here - --> $DIR/issue-70304.rs:47:41 + --> $DIR/issue-70304.rs:48:41 | LL | fn create_doc() -> impl Document = DocCursorImpl<'_>> { | ^^ `'_` is a reserved lifetime name error[E0106]: missing lifetime specifier - --> $DIR/issue-70304.rs:47:61 + --> $DIR/issue-70304.rs:48:61 | LL | fn create_doc() -> impl Document = DocCursorImpl<'_>> { | ^^ expected named lifetime parameter @@ -16,7 +16,18 @@ help: consider using the `'static` lifetime LL | fn create_doc() -> impl Document = DocCursorImpl<'static>> { | ~~~~~~~ -error: aborting due to 2 previous errors +error: missing required bound on `Cursor` + --> $DIR/issue-70304.rs:4:5 + | +LL | type Cursor<'a>: DocCursor<'a>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- + | | + | help: add the required where clause: `where Self: 'a` + | + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information + +error: aborting due to 3 previous errors Some errors have detailed explanations: E0106, E0637. For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs index 54b483f53d4cb..9ea9fc71b557f 100644 --- a/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs +++ b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs @@ -8,6 +8,7 @@ fn should_error() where T : Into<&u32> {} trait X<'a, K: 'a> { fn foo<'b, L: X<&'b Nested>>(); //~^ ERROR missing lifetime specifier [E0106] + //~| ERROR the type `&'b Nested` does not fulfill the required lifetime } fn bar<'b, L: X<&'b Nested>>(){} diff --git a/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr index 270d6b8e18e22..e45387acaf31d 100644 --- a/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr +++ b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr @@ -5,21 +5,10 @@ LL | fn should_error() where T : Into<&u32> {} | ^ explicit lifetime name needed here error[E0106]: missing lifetime specifier - --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:13:17 - | -LL | fn bar<'b, L: X<&'b Nested>>(){} - | ^ expected named lifetime parameter - | -help: consider using the `'b` lifetime - | -LL | fn bar<'b, L: X<'b, &'b Nested>>(){} - | +++ - -error[E0106]: missing lifetime specifier - --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:21 + --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:20 | LL | fn foo<'b, L: X<&'b Nested>>(); - | ^ expected named lifetime parameter + | ^ expected named lifetime parameter | note: these named lifetimes are available to use --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:8:9 @@ -33,7 +22,30 @@ help: consider using one of the available lifetimes here LL | fn foo<'b, L: X<'lifetime, &'b Nested>>(); | ++++++++++ -error: aborting due to 3 previous errors +error[E0106]: missing lifetime specifier + --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:14:16 + | +LL | fn bar<'b, L: X<&'b Nested>>(){} + | ^ expected named lifetime parameter + | +help: consider using the `'b` lifetime + | +LL | fn bar<'b, L: X<'b, &'b Nested>>(){} + | +++ + +error[E0477]: the type `&'b Nested` does not fulfill the required lifetime + --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:19 + | +LL | fn foo<'b, L: X<&'b Nested>>(); + | ^^^^^^^^^^^^^^^^ + | +note: type must satisfy the static lifetime as required by this binding + --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:8:16 + | +LL | trait X<'a, K: 'a> { + | ^^ + +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0106, E0637. +Some errors have detailed explanations: E0106, E0477, E0637. For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/generics/wrong-number-of-args.rs b/src/test/ui/generics/wrong-number-of-args.rs index 272cd36196804..cd2f96a1819e4 100644 --- a/src/test/ui/generics/wrong-number-of-args.rs +++ b/src/test/ui/generics/wrong-number-of-args.rs @@ -120,6 +120,7 @@ mod r#trait { type B = Box; //~^ ERROR missing lifetime specifier //~| HELP consider introducing + //~| HELP consider making the bound lifetime-generic type C = Box>; //~^ ERROR this trait takes 1 lifetime argument but 2 lifetime arguments were supplied @@ -136,6 +137,7 @@ mod r#trait { type F = Box>; //~^ ERROR missing lifetime specifier //~| HELP consider introducing + //~| HELP consider making the bound lifetime-generic type G = Box>; //~^ ERROR this trait takes 1 generic argument but 0 generic arguments @@ -161,6 +163,7 @@ mod associated_item { type A = Box>; //~^ ERROR missing lifetime specifier //~| HELP consider introducing + //~| HELP consider making the bound lifetime-generic type B = Box>; //~^ ERROR this trait takes 1 lifetime argument but 2 lifetime arguments were supplied @@ -169,6 +172,7 @@ mod associated_item { type C = Box>; //~^ ERROR missing lifetime specifier //~| HELP consider introducing + //~| HELP consider making the bound lifetime-generic //~| ERROR this trait takes 0 generic arguments but 1 generic argument //~| HELP remove } @@ -203,6 +207,7 @@ mod associated_item { //~| HELP add missing //~| ERROR missing lifetime specifier //~| HELP consider introducing + //~| HELP consider making the bound lifetime-generic type B = Box>; //~^ ERROR this trait takes 1 generic argument but 0 generic arguments were supplied @@ -217,10 +222,12 @@ mod associated_item { type D = Box>; //~^ ERROR missing lifetime specifier //~| HELP consider introducing + //~| HELP consider making the bound lifetime-generic type E = Box>; //~^ ERROR missing lifetime specifier //~| HELP consider introducing + //~| HELP consider making the bound lifetime-generic //~| ERROR this trait takes 1 generic argument but 2 generic arguments //~| HELP remove @@ -265,6 +272,7 @@ mod associated_item { type A = Box>; //~^ ERROR missing lifetime specifier //~| HELP consider introducing + //~| HELP consider making the bound lifetime-generic type B = Box>; //~^ ERROR this trait takes 2 lifetime arguments but 1 lifetime argument was supplied @@ -279,6 +287,7 @@ mod associated_item { type A = Box>; //~^ ERROR missing lifetime specifier //~| HELP consider introducing + //~| HELP consider making the bound lifetime-generic //~| ERROR this trait takes 1 generic argument but 0 generic arguments //~| HELP add missing diff --git a/src/test/ui/generics/wrong-number-of-args.stderr b/src/test/ui/generics/wrong-number-of-args.stderr index 3b0834a5f51b2..388c23fc24f74 100644 --- a/src/test/ui/generics/wrong-number-of-args.stderr +++ b/src/test/ui/generics/wrong-number-of-args.stderr @@ -1,3 +1,172 @@ +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:48:14 + | +LL | type A = Ty; + | ^^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type A<'a> = Ty<'a>; + | ++++ ++++ + +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:58:16 + | +LL | type C = Ty; + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type C<'a> = Ty<'a, usize>; + | ++++ +++ + +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:64:16 + | +LL | type E = Ty<>; + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type E<'a> = Ty<'a, >; + | ++++ +++ + +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:120:22 + | +LL | type B = Box; + | ^^^^^^^^^^^^^^^ expected named lifetime parameter + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | type B = Box GenericLifetime<'a>>; + | +++++++ ++++ +help: consider introducing a named lifetime parameter + | +LL | type B<'a> = Box>; + | ++++ ++++ + +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:137:37 + | +LL | type F = Box>; + | ^ expected named lifetime parameter + | +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | type F = Box GenericLifetime<'a, >>; + | +++++++ +++ +help: consider introducing a named lifetime parameter + | +LL | type F<'a> = Box>; + | ++++ +++ + +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:163:43 + | +LL | type A = Box>; + | ^ expected named lifetime parameter + | +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | type A = Box GenericLifetimeAT<'a, AssocTy=()>>; + | +++++++ +++ +help: consider introducing a named lifetime parameter + | +LL | type A<'a> = Box>; + | ++++ +++ + +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:172:43 + | +LL | type C = Box>; + | ^ expected named lifetime parameter + | +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | type C = Box GenericLifetimeAT<'a, (), AssocTy=()>>; + | +++++++ +++ +help: consider introducing a named lifetime parameter + | +LL | type C<'a> = Box>; + | ++++ +++ + +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:205:47 + | +LL | type A = Box>; + | ^ expected named lifetime parameter + | +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | type A = Box GenericLifetimeTypeAT<'a, AssocTy=()>>; + | +++++++ +++ +help: consider introducing a named lifetime parameter + | +LL | type A<'a> = Box>; + | ++++ +++ + +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:222:47 + | +LL | type D = Box>; + | ^ expected named lifetime parameter + | +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | type D = Box GenericLifetimeTypeAT<'a, (), AssocTy=()>>; + | +++++++ +++ +help: consider introducing a named lifetime parameter + | +LL | type D<'a> = Box>; + | ++++ +++ + +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:227:47 + | +LL | type E = Box>; + | ^ expected named lifetime parameter + | +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | type E = Box GenericLifetimeTypeAT<'a, (), (), AssocTy=()>>; + | +++++++ +++ +help: consider introducing a named lifetime parameter + | +LL | type E<'a> = Box>; + | ++++ +++ + +error[E0106]: missing lifetime specifiers + --> $DIR/wrong-number-of-args.rs:272:51 + | +LL | type A = Box>; + | ^ expected 2 lifetime parameters + | +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | type A = Box GenericLifetimeLifetimeAT<'a, 'a, AssocTy=()>>; + | +++++++ +++++++ +help: consider introducing a named lifetime parameter + | +LL | type A<'a> = Box>; + | ++++ +++++++ + +error[E0106]: missing lifetime specifiers + --> $DIR/wrong-number-of-args.rs:287:55 + | +LL | type A = Box>; + | ^ expected 2 lifetime parameters + | +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | type A = Box GenericLifetimeLifetimeTypeAT<'a, 'a, AssocTy=()>>; + | +++++++ +++++++ +help: consider introducing a named lifetime parameter + | +LL | type A<'a> = Box>; + | ++++ +++++++ + error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied --> $DIR/wrong-number-of-args.rs:6:14 | @@ -148,17 +317,6 @@ help: add missing generic argument LL | type A = Ty; | ~~~~~ -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:48:14 - | -LL | type A = Ty; - | ^^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type A<'a> = Ty<'a>; - | ++++ ~~~~~~ - error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied --> $DIR/wrong-number-of-args.rs:54:14 | @@ -175,17 +333,6 @@ help: add missing generic argument LL | type B = Ty<'static, T>; | +++ -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:58:17 - | -LL | type C = Ty; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type C<'a> = Ty<'a, usize>; - | ++++ +++ - error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied --> $DIR/wrong-number-of-args.rs:64:14 | @@ -202,17 +349,6 @@ help: add missing generic argument LL | type E = Ty; | + -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:64:16 - | -LL | type E = Ty<>; - | ^- expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type E<'a> = Ty<'a>; - | ++++ ++ - error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied --> $DIR/wrong-number-of-args.rs:70:14 | @@ -319,19 +455,8 @@ note: trait defined here, with 0 generic parameters LL | trait NonGeneric { | ^^^^^^^^^^ -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:120:22 - | -LL | type B = Box; - | ^^^^^^^^^^^^^^^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type B<'a> = Box>; - | ++++ ~~~~~~~~~~~~~~~~~~~ - error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied - --> $DIR/wrong-number-of-args.rs:124:22 + --> $DIR/wrong-number-of-args.rs:125:22 | LL | type C = Box>; | ^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument @@ -345,7 +470,7 @@ LL | trait GenericLifetime<'a> { | ^^^^^^^^^^^^^^^ -- error[E0107]: missing generics for trait `GenericType` - --> $DIR/wrong-number-of-args.rs:128:22 + --> $DIR/wrong-number-of-args.rs:129:22 | LL | type D = Box; | ^^^^^^^^^^^ expected 1 generic argument @@ -361,7 +486,7 @@ LL | type D = Box>; | ~~~~~~~~~~~~~~ error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:132:22 + --> $DIR/wrong-number-of-args.rs:133:22 | LL | type E = Box>; | ^^^^^^^^^^^ ----- help: remove this generic argument @@ -374,19 +499,8 @@ note: trait defined here, with 1 generic parameter: `A` LL | trait GenericType { | ^^^^^^^^^^^ - -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:136:37 - | -LL | type F = Box>; - | ^- expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type F<'a> = Box>; - | ++++ ++ - error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:140:22 + --> $DIR/wrong-number-of-args.rs:142:22 | LL | type G = Box>; | ^^^^^^^^^^^ expected 1 generic argument @@ -402,7 +516,7 @@ LL | type G = Box>; | + error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied - --> $DIR/wrong-number-of-args.rs:151:26 + --> $DIR/wrong-number-of-args.rs:153:26 | LL | type A = Box>; | ^^^^^^^^^^^^------------------- help: remove these generics @@ -410,24 +524,13 @@ LL | type A = Box>; | expected 0 generic arguments | note: trait defined here, with 0 generic parameters - --> $DIR/wrong-number-of-args.rs:147:15 + --> $DIR/wrong-number-of-args.rs:149:15 | LL | trait NonGenericAT { | ^^^^^^^^^^^^ -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:161:44 - | -LL | type A = Box>; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type A<'a> = Box>; - | ++++ +++ - error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied - --> $DIR/wrong-number-of-args.rs:165:26 + --> $DIR/wrong-number-of-args.rs:168:26 | LL | type B = Box>; | ^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument @@ -435,13 +538,13 @@ LL | type B = Box>; | expected 1 lifetime argument | note: trait defined here, with 1 lifetime parameter: `'a` - --> $DIR/wrong-number-of-args.rs:157:15 + --> $DIR/wrong-number-of-args.rs:159:15 | LL | trait GenericLifetimeAT<'a> { | ^^^^^^^^^^^^^^^^^ -- error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied - --> $DIR/wrong-number-of-args.rs:169:26 + --> $DIR/wrong-number-of-args.rs:172:26 | LL | type C = Box>; | ^^^^^^^^^^^^^^^^^ -- help: remove this generic argument @@ -449,30 +552,19 @@ LL | type C = Box>; | expected 0 generic arguments | note: trait defined here, with 0 generic parameters - --> $DIR/wrong-number-of-args.rs:157:15 + --> $DIR/wrong-number-of-args.rs:159:15 | LL | trait GenericLifetimeAT<'a> { | ^^^^^^^^^^^^^^^^^ -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:169:44 - | -LL | type C = Box>; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type C<'a> = Box>; - | ++++ +++ - error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:181:26 + --> $DIR/wrong-number-of-args.rs:185:26 | LL | type A = Box>; | ^^^^^^^^^^^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:177:15 + --> $DIR/wrong-number-of-args.rs:181:15 | LL | trait GenericTypeAT { | ^^^^^^^^^^^^^ - @@ -482,7 +574,7 @@ LL | type A = Box>; | ++ error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:185:26 + --> $DIR/wrong-number-of-args.rs:189:26 | LL | type B = Box>; | ^^^^^^^^^^^^^ -- help: remove this generic argument @@ -490,13 +582,13 @@ LL | type B = Box>; | expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:177:15 + --> $DIR/wrong-number-of-args.rs:181:15 | LL | trait GenericTypeAT { | ^^^^^^^^^^^^^ - error[E0107]: this trait takes 0 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/wrong-number-of-args.rs:189:26 + --> $DIR/wrong-number-of-args.rs:193:26 | LL | type C = Box>; | ^^^^^^^^^^^^^--------------------- help: remove these generics @@ -504,19 +596,19 @@ LL | type C = Box>; | expected 0 lifetime arguments | note: trait defined here, with 0 lifetime parameters - --> $DIR/wrong-number-of-args.rs:177:15 + --> $DIR/wrong-number-of-args.rs:181:15 | LL | trait GenericTypeAT { | ^^^^^^^^^^^^^ error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:189:26 + --> $DIR/wrong-number-of-args.rs:193:26 | LL | type C = Box>; | ^^^^^^^^^^^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:177:15 + --> $DIR/wrong-number-of-args.rs:181:15 | LL | trait GenericTypeAT { | ^^^^^^^^^^^^^ - @@ -526,13 +618,13 @@ LL | type C = Box>; | +++ error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:201:26 + --> $DIR/wrong-number-of-args.rs:205:26 | LL | type A = Box>; | ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:197:15 + --> $DIR/wrong-number-of-args.rs:201:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ - @@ -541,25 +633,14 @@ help: add missing generic argument LL | type A = Box>; | ++ -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:201:48 - | -LL | type A = Box>; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type A<'a> = Box>; - | ++++ +++ - error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:207:26 + --> $DIR/wrong-number-of-args.rs:212:26 | LL | type B = Box>; | ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:197:15 + --> $DIR/wrong-number-of-args.rs:201:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ - @@ -569,7 +650,7 @@ LL | type B = Box>; | +++ error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied - --> $DIR/wrong-number-of-args.rs:211:26 + --> $DIR/wrong-number-of-args.rs:216:26 | LL | type C = Box>; | ^^^^^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument @@ -577,19 +658,19 @@ LL | type C = Box $DIR/wrong-number-of-args.rs:197:15 + --> $DIR/wrong-number-of-args.rs:201:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ -- error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:211:26 + --> $DIR/wrong-number-of-args.rs:216:26 | LL | type C = Box>; | ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:197:15 + --> $DIR/wrong-number-of-args.rs:201:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ - @@ -598,19 +679,8 @@ help: add missing generic argument LL | type C = Box>; | +++ -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:217:48 - | -LL | type D = Box>; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type D<'a> = Box>; - | ++++ +++ - error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:221:26 + --> $DIR/wrong-number-of-args.rs:227:26 | LL | type E = Box>; | ^^^^^^^^^^^^^^^^^^^^^ -- help: remove this generic argument @@ -618,24 +688,13 @@ LL | type E = Box>; | expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:197:15 + --> $DIR/wrong-number-of-args.rs:201:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ - -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:221:48 - | -LL | type E = Box>; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type E<'a> = Box>; - | ++++ +++ - error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied - --> $DIR/wrong-number-of-args.rs:227:26 + --> $DIR/wrong-number-of-args.rs:234:26 | LL | type F = Box>; | ^^^^^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument @@ -643,13 +702,13 @@ LL | type F = Box $DIR/wrong-number-of-args.rs:197:15 + --> $DIR/wrong-number-of-args.rs:201:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ -- error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:231:26 + --> $DIR/wrong-number-of-args.rs:238:26 | LL | type G = Box>; | ^^^^^^^^^^^^^^^^^^^^^ -- help: remove this generic argument @@ -657,13 +716,13 @@ LL | type G = Box | expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:197:15 + --> $DIR/wrong-number-of-args.rs:201:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ - error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied - --> $DIR/wrong-number-of-args.rs:235:26 + --> $DIR/wrong-number-of-args.rs:242:26 | LL | type H = Box>; | ^^^^^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument @@ -671,13 +730,13 @@ LL | type H = Box $DIR/wrong-number-of-args.rs:197:15 + --> $DIR/wrong-number-of-args.rs:201:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ -- error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:235:26 + --> $DIR/wrong-number-of-args.rs:242:26 | LL | type H = Box>; | ^^^^^^^^^^^^^^^^^^^^^ -- help: remove this generic argument @@ -685,19 +744,19 @@ LL | type H = Box $DIR/wrong-number-of-args.rs:197:15 + --> $DIR/wrong-number-of-args.rs:201:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ - error[E0107]: this trait takes 2 generic arguments but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:247:26 + --> $DIR/wrong-number-of-args.rs:254:26 | LL | type A = Box>; | ^^^^^^^^^^^^^^^^^ expected 2 generic arguments | note: trait defined here, with 2 generic parameters: `A`, `B` - --> $DIR/wrong-number-of-args.rs:243:15 + --> $DIR/wrong-number-of-args.rs:250:15 | LL | trait GenericTypeTypeAT { | ^^^^^^^^^^^^^^^^^ - - @@ -707,7 +766,7 @@ LL | type A = Box>; | +++++ error[E0107]: this trait takes 2 generic arguments but 1 generic argument was supplied - --> $DIR/wrong-number-of-args.rs:251:26 + --> $DIR/wrong-number-of-args.rs:258:26 | LL | type B = Box>; | ^^^^^^^^^^^^^^^^^ -- supplied 1 generic argument @@ -715,7 +774,7 @@ LL | type B = Box>; | expected 2 generic arguments | note: trait defined here, with 2 generic parameters: `A`, `B` - --> $DIR/wrong-number-of-args.rs:243:15 + --> $DIR/wrong-number-of-args.rs:250:15 | LL | trait GenericTypeTypeAT { | ^^^^^^^^^^^^^^^^^ - - @@ -725,7 +784,7 @@ LL | type B = Box>; | +++ error[E0107]: this trait takes 2 generic arguments but 3 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:255:26 + --> $DIR/wrong-number-of-args.rs:262:26 | LL | type C = Box>; | ^^^^^^^^^^^^^^^^^ -- help: remove this generic argument @@ -733,24 +792,13 @@ LL | type C = Box>; | expected 2 generic arguments | note: trait defined here, with 2 generic parameters: `A`, `B` - --> $DIR/wrong-number-of-args.rs:243:15 + --> $DIR/wrong-number-of-args.rs:250:15 | LL | trait GenericTypeTypeAT { | ^^^^^^^^^^^^^^^^^ - - -error[E0106]: missing lifetime specifiers - --> $DIR/wrong-number-of-args.rs:265:52 - | -LL | type A = Box>; - | ^ expected 2 lifetime parameters - | -help: consider introducing a named lifetime parameter - | -LL | type A<'a> = Box>; - | ++++ +++++++ - error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/wrong-number-of-args.rs:269:26 + --> $DIR/wrong-number-of-args.rs:277:26 | LL | type B = Box>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument @@ -758,7 +806,7 @@ LL | type B = Box>; | expected 2 lifetime arguments | note: trait defined here, with 2 lifetime parameters: `'a`, `'b` - --> $DIR/wrong-number-of-args.rs:261:15 + --> $DIR/wrong-number-of-args.rs:268:15 | LL | trait GenericLifetimeLifetimeAT<'a, 'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^ -- -- @@ -768,13 +816,13 @@ LL | type B = Box | ++++ error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:279:26 + --> $DIR/wrong-number-of-args.rs:287:26 | LL | type A = Box>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:275:15 + --> $DIR/wrong-number-of-args.rs:283:15 | LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - @@ -783,19 +831,8 @@ help: add missing generic argument LL | type A = Box>; | ++ -error[E0106]: missing lifetime specifiers - --> $DIR/wrong-number-of-args.rs:279:56 - | -LL | type A = Box>; - | ^ expected 2 lifetime parameters - | -help: consider introducing a named lifetime parameter - | -LL | type A<'a> = Box>; - | ++++ +++++++ - error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/wrong-number-of-args.rs:285:26 + --> $DIR/wrong-number-of-args.rs:294:26 | LL | type B = Box>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument @@ -803,7 +840,7 @@ LL | type B = Box | expected 2 lifetime arguments | note: trait defined here, with 2 lifetime parameters: `'a`, `'b` - --> $DIR/wrong-number-of-args.rs:275:15 + --> $DIR/wrong-number-of-args.rs:283:15 | LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- -- @@ -813,13 +850,13 @@ LL | type B = Box $DIR/wrong-number-of-args.rs:285:26 + --> $DIR/wrong-number-of-args.rs:294:26 | LL | type B = Box>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:275:15 + --> $DIR/wrong-number-of-args.rs:283:15 | LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - @@ -829,7 +866,7 @@ LL | type B = Box $DIR/wrong-number-of-args.rs:291:26 + --> $DIR/wrong-number-of-args.rs:300:26 | LL | type C = Box>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument @@ -837,7 +874,7 @@ LL | type C = Box $DIR/wrong-number-of-args.rs:275:15 + --> $DIR/wrong-number-of-args.rs:283:15 | LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- -- @@ -847,7 +884,7 @@ LL | type C = Box $DIR/wrong-number-of-args.rs:301:18 + --> $DIR/wrong-number-of-args.rs:310:18 | LL | type A = HashMap; | ^^^^^^^ expected at least 2 generic arguments @@ -863,7 +900,7 @@ LL | type A = HashMap; | ~~~~~~~~~~~~~ error[E0107]: this struct takes at least 2 generic arguments but 1 generic argument was supplied - --> $DIR/wrong-number-of-args.rs:305:18 + --> $DIR/wrong-number-of-args.rs:314:18 | LL | type B = HashMap; | ^^^^^^^ ------ supplied 1 generic argument @@ -881,7 +918,7 @@ LL | type B = HashMap; | +++ error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/wrong-number-of-args.rs:309:18 + --> $DIR/wrong-number-of-args.rs:318:18 | LL | type C = HashMap<'static>; | ^^^^^^^--------- help: remove these generics @@ -895,7 +932,7 @@ LL | pub struct HashMap { | ^^^^^^^ error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:309:18 + --> $DIR/wrong-number-of-args.rs:318:18 | LL | type C = HashMap<'static>; | ^^^^^^^ expected at least 2 generic arguments @@ -911,7 +948,7 @@ LL | type C = HashMap<'static, K, V>; | ++++++ error[E0107]: this struct takes at most 3 generic arguments but 4 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:315:18 + --> $DIR/wrong-number-of-args.rs:324:18 | LL | type D = HashMap; | ^^^^^^^ --- help: remove this generic argument @@ -925,7 +962,7 @@ LL | pub struct HashMap { | ^^^^^^^ - - --------------- error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:319:18 + --> $DIR/wrong-number-of-args.rs:328:18 | LL | type E = HashMap<>; | ^^^^^^^ expected at least 2 generic arguments @@ -941,7 +978,7 @@ LL | type E = HashMap; | ++++ error[E0107]: missing generics for enum `Result` - --> $DIR/wrong-number-of-args.rs:325:18 + --> $DIR/wrong-number-of-args.rs:334:18 | LL | type A = Result; | ^^^^^^ expected 2 generic arguments @@ -957,7 +994,7 @@ LL | type A = Result; | ~~~~~~~~~~~~ error[E0107]: this enum takes 2 generic arguments but 1 generic argument was supplied - --> $DIR/wrong-number-of-args.rs:329:18 + --> $DIR/wrong-number-of-args.rs:338:18 | LL | type B = Result; | ^^^^^^ ------ supplied 1 generic argument @@ -975,7 +1012,7 @@ LL | type B = Result; | +++ error[E0107]: this enum takes 0 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/wrong-number-of-args.rs:333:18 + --> $DIR/wrong-number-of-args.rs:342:18 | LL | type C = Result<'static>; | ^^^^^^--------- help: remove these generics @@ -989,7 +1026,7 @@ LL | pub enum Result { | ^^^^^^ error[E0107]: this enum takes 2 generic arguments but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:333:18 + --> $DIR/wrong-number-of-args.rs:342:18 | LL | type C = Result<'static>; | ^^^^^^ expected 2 generic arguments @@ -1005,7 +1042,7 @@ LL | type C = Result<'static, T, E>; | ++++++ error[E0107]: this enum takes 2 generic arguments but 3 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:339:18 + --> $DIR/wrong-number-of-args.rs:348:18 | LL | type D = Result; | ^^^^^^ ---- help: remove this generic argument @@ -1019,7 +1056,7 @@ LL | pub enum Result { | ^^^^^^ - - error[E0107]: this enum takes 2 generic arguments but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:343:18 + --> $DIR/wrong-number-of-args.rs:352:18 | LL | type E = Result<>; | ^^^^^^ expected 2 generic arguments diff --git a/src/test/ui/impl-header-lifetime-elision/assoc-type.rs b/src/test/ui/impl-header-lifetime-elision/assoc-type.rs index 44c46e444d66d..b0089a37aa05f 100644 --- a/src/test/ui/impl-header-lifetime-elision/assoc-type.rs +++ b/src/test/ui/impl-header-lifetime-elision/assoc-type.rs @@ -9,12 +9,12 @@ trait MyTrait { impl MyTrait for &i32 { type Output = &i32; - //~^ ERROR missing lifetime specifier + //~^ ERROR `&` without an explicit lifetime name cannot be used here } impl MyTrait for &u32 { type Output = &'_ i32; - //~^ ERROR missing lifetime specifier + //~^ ERROR `'_` cannot be used here } // This is what you have to do: diff --git a/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr b/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr index 44955c58889aa..c4f27e0b80e41 100644 --- a/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr +++ b/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr @@ -1,25 +1,15 @@ -error[E0106]: missing lifetime specifier +error[E0637]: `&` without an explicit lifetime name cannot be used here --> $DIR/assoc-type.rs:11:19 | LL | type Output = &i32; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type Output<'a> = &'a i32; - | ++++ ++ + | ^ explicit lifetime name needed here -error[E0106]: missing lifetime specifier +error[E0637]: `'_` cannot be used here --> $DIR/assoc-type.rs:16:20 | LL | type Output = &'_ i32; - | ^^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type Output<'a> = &'a i32; - | ++++ ~~ + | ^^ `'_` is a reserved lifetime name error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0106`. +For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/issues/issue-13497.stderr b/src/test/ui/issues/issue-13497.stderr index 6521a67428eb2..4b1d979da36e3 100644 --- a/src/test/ui/issues/issue-13497.stderr +++ b/src/test/ui/issues/issue-13497.stderr @@ -8,7 +8,7 @@ LL | &str help: consider using the `'static` lifetime | LL | &'static str - | ~~~~~~~~ + | +++++++ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-19707.stderr b/src/test/ui/issues/issue-19707.stderr index 18f69bb57755a..3e1bb32c19b92 100644 --- a/src/test/ui/issues/issue-19707.stderr +++ b/src/test/ui/issues/issue-19707.stderr @@ -22,7 +22,6 @@ LL | fn bar &u8>(f: &F) {} | --- --- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 - = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider making the bound lifetime-generic with a new `'a` lifetime | LL | fn bar Fn(&'a u8, &'a u8) -> &'a u8>(f: &F) {} diff --git a/src/test/ui/issues/issue-30255.stderr b/src/test/ui/issues/issue-30255.stderr index e5f492af5b366..adb721a1cbaf1 100644 --- a/src/test/ui/issues/issue-30255.stderr +++ b/src/test/ui/issues/issue-30255.stderr @@ -7,8 +7,8 @@ LL | fn f(a: &S, b: i32) -> &i32 { = help: this function's return type contains a borrowed value, but the signature does not say which one of `a`'s 2 lifetimes it is borrowed from help: consider introducing a named lifetime parameter | -LL | fn f<'a>(a: &'a S, b: i32) -> &'a i32 { - | ++++ ++ ++ +LL | fn f<'a>(a: &'a S<'a>, b: i32) -> &'a i32 { + | ++++ ++ ++++ ++ error[E0106]: missing lifetime specifier --> $DIR/issue-30255.rs:14:34 @@ -19,8 +19,8 @@ LL | fn g(a: &S, b: bool, c: &i32) -> &i32 { = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `a`'s 2 lifetimes or `c` help: consider introducing a named lifetime parameter | -LL | fn g<'a>(a: &'a S, b: bool, c: &'a i32) -> &'a i32 { - | ++++ ++ ++ ++ +LL | fn g<'a>(a: &'a S<'a>, b: bool, c: &'a i32) -> &'a i32 { + | ++++ ++ ++++ ++ ++ error[E0106]: missing lifetime specifier --> $DIR/issue-30255.rs:19:44 @@ -31,8 +31,8 @@ LL | fn h(a: &bool, b: bool, c: &S, d: &i32) -> &i32 { = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a`, one of `c`'s 2 lifetimes, or `d` help: consider introducing a named lifetime parameter | -LL | fn h<'a>(a: &'a bool, b: bool, c: &'a S, d: &'a i32) -> &'a i32 { - | ++++ ++ ++ ++ ++ +LL | fn h<'a>(a: &'a bool, b: bool, c: &'a S<'a>, d: &'a i32) -> &'a i32 { + | ++++ ++ ++ ++++ ++ ++ error: aborting due to 3 previous errors diff --git a/src/test/ui/lifetimes/issue-26638.rs b/src/test/ui/lifetimes/issue-26638.rs index 72fe4286a06b3..000ab6492bb96 100644 --- a/src/test/ui/lifetimes/issue-26638.rs +++ b/src/test/ui/lifetimes/issue-26638.rs @@ -1,8 +1,11 @@ fn parse_type(iter: Box+'static>) -> &str { iter.next() } //~^ ERROR missing lifetime specifier [E0106] +//~| ERROR mismatched types fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() } //~^ ERROR missing lifetime specifier [E0106] +//~| ERROR mismatched types +//~| ERROR this function takes 1 argument but 0 arguments were supplied fn parse_type_3() -> &str { unimplemented!() } //~^ ERROR missing lifetime specifier [E0106] diff --git a/src/test/ui/lifetimes/issue-26638.stderr b/src/test/ui/lifetimes/issue-26638.stderr index bb7cdcbb100ff..f3af5cf5a3576 100644 --- a/src/test/ui/lifetimes/issue-26638.stderr +++ b/src/test/ui/lifetimes/issue-26638.stderr @@ -7,23 +7,23 @@ LL | fn parse_type(iter: Box+'static>) -> &str { iter.ne = help: this function's return type contains a borrowed value, but the signature does not say which one of `iter`'s 2 lifetimes it is borrowed from help: consider introducing a named lifetime parameter | -LL | fn parse_type<'a>(iter: Box+'static>) -> &'a str { iter.next() } - | ++++ ++ +LL | fn parse_type<'a>(iter: Box+'static>) -> &'a str { iter.next() } + | ++++ ++ ++ error[E0106]: missing lifetime specifier - --> $DIR/issue-26638.rs:4:40 + --> $DIR/issue-26638.rs:5:40 | LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() } | ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments + = 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 parse_type_2(iter: fn(&u8)->&u8) -> &'static str { iter() } - | ~~~~~~~~ + | +++++++ error[E0106]: missing lifetime specifier - --> $DIR/issue-26638.rs:7:22 + --> $DIR/issue-26638.rs:10:22 | LL | fn parse_type_3() -> &str { unimplemented!() } | ^ expected named lifetime parameter @@ -32,8 +32,42 @@ LL | fn parse_type_3() -> &str { unimplemented!() } help: consider using the `'static` lifetime | LL | fn parse_type_3() -> &'static str { unimplemented!() } - | ~~~~~~~~ + | +++++++ + +error[E0308]: mismatched types + --> $DIR/issue-26638.rs:1:69 + | +LL | fn parse_type(iter: Box+'static>) -> &str { iter.next() } + | ---- ^^^^^^^^^^^ expected `&str`, found enum `Option` + | | + | expected `&'static str` because of return type + | + = note: expected reference `&'static str` + found enum `Option<&str>` + +error[E0061]: this function takes 1 argument but 0 arguments were supplied + --> $DIR/issue-26638.rs:5:47 + | +LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() } + | ^^^^-- an argument of type `&u8` is missing + | +help: provide the argument + | +LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter(/* &u8 */) } + | ~~~~~~~~~~~~~~~ + +error[E0308]: mismatched types + --> $DIR/issue-26638.rs:5:47 + | +LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() } + | ---- ^^^^^^ expected `str`, found `u8` + | | + | expected `&'static str` because of return type + | + = note: expected reference `&'static str` + found reference `&u8` -error: aborting due to 3 previous errors +error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0106`. +Some errors have detailed explanations: E0061, E0106, E0308. +For more information about an error, try `rustc --explain E0061`. diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr index 0e69cd50f6a82..d07754879559a 100644 --- a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr +++ b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr @@ -8,7 +8,7 @@ LL | fn f() -> &isize { help: consider using the `'static` lifetime | LL | fn f() -> &'static isize { - | ~~~~~~~~ + | +++++++ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:7:33 @@ -31,8 +31,8 @@ LL | fn h(_x: &Foo) -> &isize { = help: this function's return type contains a borrowed value, but the signature does not say which one of `_x`'s 2 lifetimes it is borrowed from help: consider introducing a named lifetime parameter | -LL | fn h<'a>(_x: &'a Foo) -> &'a isize { - | ++++ ++ ++ +LL | fn h<'a>(_x: &'a Foo<'a>) -> &'a isize { + | ++++ ++ ++++ ++ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:21:20 @@ -40,11 +40,11 @@ error[E0106]: missing lifetime specifier LL | fn i(_x: isize) -> &isize { | ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments + = 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 i(_x: isize) -> &'static isize { - | ~~~~~~~~ + | +++++++ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:34:24 @@ -52,11 +52,11 @@ error[E0106]: missing lifetime specifier LL | fn j(_x: StaticStr) -> &isize { | ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments + = 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 j(_x: StaticStr) -> &'static isize { - | ~~~~~~~~ + | +++++++ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:40:49 @@ -64,11 +64,11 @@ error[E0106]: missing lifetime specifier LL | fn k<'a, T: WithLifetime<'a>>(_x: T::Output) -> &isize { | ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments + = 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 `'a` lifetime | LL | fn k<'a, T: WithLifetime<'a>>(_x: T::Output) -> &'a isize { - | ~~~ + | ++ error: aborting due to 6 previous errors diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.rs b/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.rs index d1263a4acb28a..d6c918843c700 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.rs +++ b/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.rs @@ -2,4 +2,4 @@ fn foo(x: &i32, y: &i32) -> &i32 { //~ ERROR missing lifetime if x > y { x } else { y } } -fn main() { } +fn main() {} diff --git a/src/test/ui/lifetimes/missing-lifetime-in-alias.stderr b/src/test/ui/lifetimes/missing-lifetime-in-alias.stderr index b16b792aefee9..b8c68a4607da8 100644 --- a/src/test/ui/lifetimes/missing-lifetime-in-alias.stderr +++ b/src/test/ui/lifetimes/missing-lifetime-in-alias.stderr @@ -7,7 +7,7 @@ LL | type B<'a> = as Trait>::Foo; help: consider using the `'a` lifetime | LL | type B<'a> = as Trait<'a>>::Foo; - | ~~~~~~~~~ + | ++++ error[E0106]: missing lifetime specifier --> $DIR/missing-lifetime-in-alias.rs:26:28 @@ -20,6 +20,10 @@ note: these named lifetimes are available to use | LL | type C<'a, 'b> = as Trait>::Bar; | ^^ ^^ +help: consider using one of the available lifetimes here + | +LL | type C<'a, 'b> = as Trait<'lifetime>>::Bar; + | +++++++++++ error[E0107]: missing generics for associated type `Trait::Bar` --> $DIR/missing-lifetime-in-alias.rs:26:36 diff --git a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs index 6aa34354a7ad9..c7842667dc614 100644 --- a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs +++ b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs @@ -9,6 +9,7 @@ impl> Iterator for ChunkingIterator { type Item = IteratorChunk; //~ ERROR missing lifetime fn next(&mut self) -> Option> { + //~^ ERROR `impl` item signature doesn't match `trait` item signature todo!() } } diff --git a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr index c7e1f87f2d4d4..94a9c97576f67 100644 --- a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr +++ b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr @@ -1,14 +1,30 @@ error[E0106]: missing lifetime specifier - --> $DIR/issue-74918-missing-lifetime.rs:9:31 + --> $DIR/issue-74918-missing-lifetime.rs:9:30 | LL | type Item = IteratorChunk; - | ^ expected named lifetime parameter + | ^ expected named lifetime parameter | help: consider introducing a named lifetime parameter | LL | type Item<'a> = IteratorChunk<'a, T, S>; | ++++ +++ -error: aborting due to previous error +error: `impl` item signature doesn't match `trait` item signature + --> $DIR/issue-74918-missing-lifetime.rs:11:5 + | +LL | fn next(&mut self) -> Option> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 mut ChunkingIterator) -> Option>` + | + ::: $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + | +LL | fn next(&mut self) -> Option; + | ----------------------------------------- expected `fn(&'1 mut ChunkingIterator) -> Option>` + | + = note: expected `fn(&'1 mut ChunkingIterator) -> Option>` + found `fn(&'1 mut ChunkingIterator) -> Option>` + = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` + = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs b/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs index 4397baea4a940..c377ecea94d0c 100644 --- a/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs +++ b/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs @@ -2,5 +2,5 @@ fn main() {} trait Foo { fn fn_with_type_named_same_as_local_in_param(b: b); - //~^ ERROR cannot find type `b` in this scope + //~^ ERROR cannot find type `b` in this scope [E0412] } diff --git a/src/test/ui/rfc1623-2.rs b/src/test/ui/rfc1623-2.rs index 35a2ef10c2e3c..26fa6fdb57f95 100644 --- a/src/test/ui/rfc1623-2.rs +++ b/src/test/ui/rfc1623-2.rs @@ -9,5 +9,6 @@ static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = //~^ ERROR missing lifetime specifier [E0106] &(non_elidable as fn(&u8, &u8) -> &u8); //~^ ERROR missing lifetime specifier [E0106] + //~| ERROR non-primitive cast fn main() {} diff --git a/src/test/ui/rfc1623-2.stderr b/src/test/ui/rfc1623-2.stderr index 65b9f68817aa4..495d45e223416 100644 --- a/src/test/ui/rfc1623-2.stderr +++ b/src/test/ui/rfc1623-2.stderr @@ -18,12 +18,18 @@ LL | &(non_elidable as fn(&u8, &u8) -> &u8); | --- --- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 - = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider making the type lifetime-generic with a new `'a` lifetime | LL | &(non_elidable as for<'a> fn(&'a u8, &'a u8) -> &'a u8); | +++++++ ++ ++ ++ -error: aborting due to 2 previous errors +error[E0605]: non-primitive cast: `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8 {non_elidable}` as `for<'r, 's> fn(&'r u8, &'s u8) -> &u8` + --> $DIR/rfc1623-2.rs:10:6 + | +LL | &(non_elidable as fn(&u8, &u8) -> &u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0106`. +Some errors have detailed explanations: E0106, E0605. +For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr b/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr index a761ec5916745..6d7c3d73097a9 100644 --- a/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr +++ b/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr @@ -21,7 +21,6 @@ LL | struct S2 &i32>(F); | ---- ---- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 - = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider making the bound lifetime-generic with a new `'a` lifetime | LL | struct S2 Fn(&'a i32, &'a i32) -> &'a i32>(F); diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr b/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr index 9adc9679eee47..e82a6f769e090 100644 --- a/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr +++ b/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr @@ -1,43 +1,43 @@ -error[E0658]: anonymous lifetimes in `impl Trait` are unstable - --> $DIR/impl-trait-missing-lifetime-gated.rs:5:31 - | -LL | fn f(_: impl Iterator) {} - | ^^ - | - = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable - error[E0106]: missing lifetime specifier --> $DIR/impl-trait-missing-lifetime-gated.rs:8:50 | LL | fn g(x: impl Iterator) -> Option<&'_ ()> { x.next() } | ^^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from help: consider using the `'static` lifetime | LL | fn g(x: impl Iterator) -> Option<&'static ()> { x.next() } | ~~~~~~~ -error[E0658]: anonymous lifetimes in `impl Trait` are unstable - --> $DIR/impl-trait-missing-lifetime-gated.rs:8:31 - | -LL | fn g(x: impl Iterator) -> Option<&'_ ()> { x.next() } - | ^^ - | - = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable - error[E0106]: missing lifetime specifier --> $DIR/impl-trait-missing-lifetime-gated.rs:18:56 | LL | async fn i(x: impl Iterator) -> Option<&'_ ()> { x.next() } | ^^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from help: consider using the `'static` lifetime | LL | async fn i(x: impl Iterator) -> Option<&'static ()> { x.next() } | ~~~~~~~ +error[E0658]: anonymous lifetimes in `impl Trait` are unstable + --> $DIR/impl-trait-missing-lifetime-gated.rs:5:31 + | +LL | fn f(_: impl Iterator) {} + | ^^ + | + = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable + +error[E0658]: anonymous lifetimes in `impl Trait` are unstable + --> $DIR/impl-trait-missing-lifetime-gated.rs:8:31 + | +LL | fn g(x: impl Iterator) -> Option<&'_ ()> { x.next() } + | ^^ + | + = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable + error: aborting due to 4 previous errors Some errors have detailed explanations: E0106, E0658. diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime.rs b/src/test/ui/suggestions/impl-trait-missing-lifetime.rs index dcc716f56b705..6f7c912d707cf 100644 --- a/src/test/ui/suggestions/impl-trait-missing-lifetime.rs +++ b/src/test/ui/suggestions/impl-trait-missing-lifetime.rs @@ -6,14 +6,15 @@ fn f(_: impl Iterator) {} // But that lifetime does not participate in resolution. -fn g(x: impl Iterator) -> Option<&'_ ()> { x.next() } +fn g(mut x: impl Iterator) -> Option<&'_ ()> { x.next() } //~^ ERROR missing lifetime specifier // This is understood as `fn foo<'_1>(_: impl Iterator) {}`. async fn h(_: impl Iterator) {} // But that lifetime does not participate in resolution. -async fn i(x: impl Iterator) -> Option<&'_ ()> { x.next() } +async fn i(mut x: impl Iterator) -> Option<&'_ ()> { x.next() } //~^ ERROR missing lifetime specifier +//~| ERROR lifetime may not live long enough fn main() {} diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr b/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr index d3c64cb466d74..b476d61017f14 100644 --- a/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr +++ b/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr @@ -1,27 +1,35 @@ error[E0106]: missing lifetime specifier - --> $DIR/impl-trait-missing-lifetime.rs:9:50 + --> $DIR/impl-trait-missing-lifetime.rs:9:54 | -LL | fn g(x: impl Iterator) -> Option<&'_ ()> { x.next() } - | ^^ expected named lifetime parameter +LL | fn g(mut x: impl Iterator) -> Option<&'_ ()> { x.next() } + | ^^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from help: consider using the `'static` lifetime | -LL | fn g(x: impl Iterator) -> Option<&'static ()> { x.next() } - | ~~~~~~~ +LL | fn g(mut x: impl Iterator) -> Option<&'static ()> { x.next() } + | ~~~~~~~ error[E0106]: missing lifetime specifier - --> $DIR/impl-trait-missing-lifetime.rs:16:56 + --> $DIR/impl-trait-missing-lifetime.rs:16:60 | -LL | async fn i(x: impl Iterator) -> Option<&'_ ()> { x.next() } - | ^^ expected named lifetime parameter +LL | async fn i(mut x: impl Iterator) -> Option<&'_ ()> { x.next() } + | ^^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from help: consider using the `'static` lifetime | -LL | async fn i(x: impl Iterator) -> Option<&'static ()> { x.next() } - | ~~~~~~~ +LL | async fn i(mut x: impl Iterator) -> Option<&'static ()> { x.next() } + | ~~~~~~~ -error: aborting due to 2 previous errors +error: lifetime may not live long enough + --> $DIR/impl-trait-missing-lifetime.rs:16:69 + | +LL | async fn i(mut x: impl Iterator) -> Option<&'_ ()> { x.next() } + | -------------- ^^^^^^^^ returning this value requires that `'1` must outlive `'static` + | | + | return type `impl Future>` contains a lifetime `'1` + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/suggestions/issue-86667.rs b/src/test/ui/suggestions/issue-86667.rs index 6aceb13746937..366787df1b4dd 100644 --- a/src/test/ui/suggestions/issue-86667.rs +++ b/src/test/ui/suggestions/issue-86667.rs @@ -6,6 +6,7 @@ async fn a(s1: &str, s2: &str) -> &str { //~^ ERROR: missing lifetime specifier [E0106] s1 +//~^ ERROR: lifetime may not live long enough } fn b(s1: &str, s2: &str) -> &str { diff --git a/src/test/ui/suggestions/issue-86667.stderr b/src/test/ui/suggestions/issue-86667.stderr index 14dbbfffb0e62..8d611641626e1 100644 --- a/src/test/ui/suggestions/issue-86667.stderr +++ b/src/test/ui/suggestions/issue-86667.stderr @@ -11,7 +11,7 @@ LL | async fn a<'a>(s1: &'a str, s2: &'a str) -> &'a str { | ++++ ++ ++ ++ error[E0106]: missing lifetime specifier - --> $DIR/issue-86667.rs:11:29 + --> $DIR/issue-86667.rs:12:29 | LL | fn b(s1: &str, s2: &str) -> &str { | ---- ---- ^ expected named lifetime parameter @@ -22,6 +22,15 @@ help: consider introducing a named lifetime parameter LL | fn b<'a>(s1: &'a str, s2: &'a str) -> &'a str { | ++++ ++ ++ ++ -error: aborting due to 2 previous errors +error: lifetime may not live long enough + --> $DIR/issue-86667.rs:8:5 + | +LL | async fn a(s1: &str, s2: &str) -> &str { + | - let's call the lifetime of this reference `'1` +LL | +LL | s1 + | ^^ returning this value requires that `'1` must outlive `'static` + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr b/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr index 1ecaade93c8ca..233f1bc5a86ee 100644 --- a/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr +++ b/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr @@ -4,10 +4,6 @@ error[E0106]: missing lifetime specifier LL | const A: &str = ""; | ^ expected named lifetime parameter | -help: consider using the `'static` lifetime - | -LL | const A: &'static str = ""; - | +++++++ help: consider introducing a named lifetime parameter | LL ~ trait ZstAssert<'a>: Sized { @@ -20,10 +16,6 @@ error[E0106]: missing lifetime specifier LL | const B: S = S { s: &() }; | ^ expected named lifetime parameter | -help: consider using the `'static` lifetime - | -LL | const B: S<'static> = S { s: &() }; - | +++++++++ help: consider introducing a named lifetime parameter | LL ~ trait ZstAssert<'a>: Sized { @@ -37,10 +29,6 @@ error[E0106]: missing lifetime specifier LL | const C: &'_ str = ""; | ^^ expected named lifetime parameter | -help: consider using the `'static` lifetime - | -LL | const C: &'static str = ""; - | ~~~~~~~ help: consider introducing a named lifetime parameter | LL ~ trait ZstAssert<'a>: Sized { @@ -55,10 +43,6 @@ error[E0106]: missing lifetime specifiers LL | const D: T = T { a: &(), b: &() }; | ^ expected 2 lifetime parameters | -help: consider using the `'static` lifetime - | -LL | const D: T<'static, 'static> = T { a: &(), b: &() }; - | ++++++++++++++++++ help: consider introducing a named lifetime parameter | LL ~ trait ZstAssert<'a>: Sized { diff --git a/src/test/ui/suggestions/missing-lifetime-specifier.rs b/src/test/ui/suggestions/missing-lifetime-specifier.rs index ce847c86bedde..24f5f782f3521 100644 --- a/src/test/ui/suggestions/missing-lifetime-specifier.rs +++ b/src/test/ui/suggestions/missing-lifetime-specifier.rs @@ -21,22 +21,18 @@ thread_local! { } thread_local! { static b: RefCell>>> = RefCell::new(HashMap::new()); - //~^ ERROR missing lifetime specifier - //~| ERROR missing lifetime specifier - //~| ERROR missing lifetime specifier - //~| ERROR missing lifetime specifier + //~^ ERROR missing lifetime specifiers + //~| ERROR missing lifetime specifiers } thread_local! { static c: RefCell>>>> = RefCell::new(HashMap::new()); - //~^ ERROR missing lifetime - //~| ERROR missing lifetime + //~^ ERROR missing lifetime specifiers + //~| ERROR missing lifetime specifiers } thread_local! { static d: RefCell>>>> = RefCell::new(HashMap::new()); - //~^ ERROR missing lifetime - //~| ERROR missing lifetime - //~| ERROR missing lifetime - //~| ERROR missing lifetime + //~^ ERROR missing lifetime specifiers + //~| ERROR missing lifetime specifiers } thread_local! { diff --git a/src/test/ui/suggestions/missing-lifetime-specifier.stderr b/src/test/ui/suggestions/missing-lifetime-specifier.stderr index 1498337549d81..10fb28c189197 100644 --- a/src/test/ui/suggestions/missing-lifetime-specifier.stderr +++ b/src/test/ui/suggestions/missing-lifetime-specifier.stderr @@ -8,7 +8,7 @@ LL | static a: RefCell>>> = RefCell::new(HashMap:: help: consider using the `'static` lifetime | LL | static a: RefCell>>>> = RefCell::new(HashMap::new()); - | ~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++ error[E0106]: missing lifetime specifiers --> $DIR/missing-lifetime-specifier.rs:18:44 @@ -23,38 +23,28 @@ LL | | } | = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from -error[E0106]: missing lifetime specifier +error[E0106]: missing lifetime specifiers --> $DIR/missing-lifetime-specifier.rs:23:44 | LL | static b: RefCell>>> = RefCell::new(HashMap::new()); - | ^ expected named lifetime parameter + | ^^^^ expected 2 lifetime parameters + | | + | 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 | static b: RefCell>>> = RefCell::new(HashMap::new()); - | ~~~~~~~~ +LL | static b: RefCell>>>> = RefCell::new(HashMap::new()); + | +++++++ ++++++++++++++++++ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:23:45 - | -LL | static b: RefCell>>> = RefCell::new(HashMap::new()); - | ^^^ expected 2 lifetime parameters - | - = 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 | static b: RefCell>>>> = RefCell::new(HashMap::new()); - | ~~~~~~~~~~~~~~~~~~~~~ - -error[E0106]: missing lifetime specifier --> $DIR/missing-lifetime-specifier.rs:23:44 | LL | / thread_local! { LL | | static b: RefCell>>> = RefCell::new(HashMap::new()); - | | ^ expected named lifetime parameter -LL | | -LL | | + | | ^^^^ expected 2 lifetime parameters + | | | + | | expected named lifetime parameter LL | | LL | | LL | | } @@ -63,25 +53,10 @@ LL | | } = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:23:45 - | -LL | / thread_local! { -LL | | static b: RefCell>>> = RefCell::new(HashMap::new()); - | | ^^^ expected 2 lifetime parameters -LL | | -LL | | -LL | | -LL | | -LL | | } - | |_- - | - = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from - -error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:30:48 + --> $DIR/missing-lifetime-specifier.rs:28:47 | LL | static c: RefCell>>>> = RefCell::new(HashMap::new()); - | ^ expected 2 lifetime parameters + | ^ expected 2 lifetime parameters | = 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 @@ -90,11 +65,11 @@ LL | static c: RefCell>>>> = | +++++++++++++++++ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:30:48 + --> $DIR/missing-lifetime-specifier.rs:28:47 | LL | / thread_local! { LL | | static c: RefCell>>>> = RefCell::new(HashMap::new()); - | | ^ expected 2 lifetime parameters + | | ^ expected 2 lifetime parameters LL | | LL | | LL | | } @@ -102,38 +77,28 @@ LL | | } | = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from -error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-specifier.rs:35:44 - | -LL | static d: RefCell>>>> = RefCell::new(HashMap::new()); - | ^ 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 | static d: RefCell>>>> = RefCell::new(HashMap::new()); - | ~~~~~~~~ - error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:35:49 + --> $DIR/missing-lifetime-specifier.rs:33:44 | LL | static d: RefCell>>>> = RefCell::new(HashMap::new()); - | ^ expected 2 lifetime parameters + | ^ ^ expected 2 lifetime parameters + | | + | 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 | static d: RefCell>>>> = RefCell::new(HashMap::new()); - | +++++++++++++++++ +LL | static d: RefCell>>>> = RefCell::new(HashMap::new()); + | +++++++ +++++++++++++++++ -error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-specifier.rs:35:44 +error[E0106]: missing lifetime specifiers + --> $DIR/missing-lifetime-specifier.rs:33:44 | LL | / thread_local! { LL | | static d: RefCell>>>> = RefCell::new(HashMap::new()); - | | ^ expected named lifetime parameter -LL | | -LL | | + | | ^ ^ expected 2 lifetime parameters + | | | + | | expected named lifetime parameter LL | | LL | | LL | | } @@ -141,23 +106,35 @@ LL | | } | = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from -error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:35:49 +error[E0106]: missing lifetime specifier + --> $DIR/missing-lifetime-specifier.rs:47:44 + | +LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); + | ^ 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 | static f: RefCell>>>> = RefCell::new(HashMap::new()); + | +++++++ + +error[E0106]: missing lifetime specifier + --> $DIR/missing-lifetime-specifier.rs:47:44 | LL | / thread_local! { -LL | | static d: RefCell>>>> = RefCell::new(HashMap::new()); - | | ^ expected 2 lifetime parameters -LL | | +LL | | static f: RefCell>>>> = RefCell::new(HashMap::new()); + | | ^ expected named lifetime parameter LL | | LL | | +... | LL | | LL | | } | |_- | - = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from + = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:43:44 + --> $DIR/missing-lifetime-specifier.rs:39:44 | LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -175,7 +152,7 @@ LL | static e: RefCell>>>> = | +++++++++ error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:43:44 + --> $DIR/missing-lifetime-specifier.rs:39:44 | LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -193,7 +170,7 @@ LL | static e: RefCell>>>> = RefC | ++++ error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:43:44 + --> $DIR/missing-lifetime-specifier.rs:39:44 | LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -211,7 +188,7 @@ LL | static e: RefCell>>>> = RefC | ++++ error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:43:44 + --> $DIR/missing-lifetime-specifier.rs:39:44 | LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -229,7 +206,7 @@ LL | static e: RefCell>>>> = RefC | ++++ error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:43:44 + --> $DIR/missing-lifetime-specifier.rs:39:44 | LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -247,7 +224,7 @@ LL | static e: RefCell>>>> = | +++++++++ error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:51:45 + --> $DIR/missing-lifetime-specifier.rs:47:45 | LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -264,20 +241,8 @@ help: add missing lifetime argument LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); | +++++++++ -error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-specifier.rs:51:44 - | -LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); - | ^ 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 | static f: RefCell>>>> = RefCell::new(HashMap::new()); - | ~~~~~~~~ - error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:51:45 + --> $DIR/missing-lifetime-specifier.rs:47:45 | LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -294,23 +259,8 @@ help: add missing lifetime argument LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); | ++++ -error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-specifier.rs:51:44 - | -LL | / thread_local! { -LL | | static f: RefCell>>>> = RefCell::new(HashMap::new()); - | | ^ expected named lifetime parameter -LL | | -LL | | -... | -LL | | -LL | | } - | |_- - | - = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from - error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:51:45 + --> $DIR/missing-lifetime-specifier.rs:47:45 | LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -328,7 +278,7 @@ LL | static f: RefCell>>>> = Ref | ++++ error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:51:45 + --> $DIR/missing-lifetime-specifier.rs:47:45 | LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -346,7 +296,7 @@ LL | static f: RefCell>>>> = Ref | ++++ error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:51:45 + --> $DIR/missing-lifetime-specifier.rs:47:45 | LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -363,7 +313,7 @@ help: add missing lifetime argument LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); | +++++++++ -error: aborting due to 24 previous errors +error: aborting due to 20 previous errors Some errors have detailed explanations: E0106, E0107. For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/suggestions/missing-lt-for-hrtb.rs b/src/test/ui/suggestions/missing-lt-for-hrtb.rs index a90a90122ad19..04ea3d831c93a 100644 --- a/src/test/ui/suggestions/missing-lt-for-hrtb.rs +++ b/src/test/ui/suggestions/missing-lt-for-hrtb.rs @@ -1,10 +1,8 @@ struct X<'a>(&'a ()); struct S<'a>(&'a dyn Fn(&X) -> &X); -//~^ ERROR missing lifetime specifier -//~| ERROR missing lifetime specifier +//~^ ERROR missing lifetime specifiers struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X); -//~^ ERROR missing lifetime specifier -//~| ERROR missing lifetime specifier +//~^ ERROR missing lifetime specifiers fn main() { let x = S(&|x| { diff --git a/src/test/ui/suggestions/missing-lt-for-hrtb.stderr b/src/test/ui/suggestions/missing-lt-for-hrtb.stderr index 33f9d092e6ee0..fa515644431ac 100644 --- a/src/test/ui/suggestions/missing-lt-for-hrtb.stderr +++ b/src/test/ui/suggestions/missing-lt-for-hrtb.stderr @@ -1,67 +1,36 @@ -error[E0106]: missing lifetime specifier +error[E0106]: missing lifetime specifiers --> $DIR/missing-lt-for-hrtb.rs:2:32 | LL | struct S<'a>(&'a dyn Fn(&X) -> &X); - | -- ^ expected named lifetime parameter + | -- ^^ expected named lifetime parameter + | | + | expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from - = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html -help: consider making the bound lifetime-generic with a new `'b` lifetime - | -LL | struct S<'a>(&'a dyn for<'b> Fn(&'b X) -> &'b X); - | +++++++ ~~~~~ ~~~ -help: consider using the `'a` lifetime - | -LL | struct S<'a>(&'a dyn Fn(&X) -> &'a X); - | ~~~ - -error[E0106]: missing lifetime specifier - --> $DIR/missing-lt-for-hrtb.rs:2:33 - | -LL | struct S<'a>(&'a dyn Fn(&X) -> &X); - | -- ^ expected named lifetime parameter - | - = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from - = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html -help: consider making the bound lifetime-generic with a new `'b` lifetime - | -LL | struct S<'a>(&'a dyn for<'b> Fn(&'b X) -> &X<'b>); - | +++++++ ~~~~~ ~~~~~ help: consider using the `'a` lifetime | -LL | struct S<'a>(&'a dyn Fn(&X) -> &X<'a>); - | ~~~~~ +LL | struct S<'a>(&'a dyn Fn(&X) -> &'a X<'a>); + | ++ ++++ -error[E0106]: missing lifetime specifier - --> $DIR/missing-lt-for-hrtb.rs:5:40 +error[E0106]: missing lifetime specifiers + --> $DIR/missing-lt-for-hrtb.rs:4:40 | LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X); - | -- ^ expected named lifetime parameter + | -- ^^ expected named lifetime parameter + | | + | expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from note: these named lifetimes are available to use - --> $DIR/missing-lt-for-hrtb.rs:5:10 + --> $DIR/missing-lt-for-hrtb.rs:4:10 | LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X); | ^^ ^^ help: consider using one of the available lifetimes here | -LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &'lifetime X); - | +++++++++ - -error[E0106]: missing lifetime specifier - --> $DIR/missing-lt-for-hrtb.rs:5:41 - | -LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X); - | -- ^ expected named lifetime parameter - | - = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from -note: these named lifetimes are available to use - --> $DIR/missing-lt-for-hrtb.rs:5:10 - | -LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X); - | ^^ ^^ +LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &'lifetime X<'lifetime>); + | +++++++++ +++++++++++ -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/suggestions/return-elided-lifetime.rs b/src/test/ui/suggestions/return-elided-lifetime.rs index ca336bbb056d5..012d5492a0404 100644 --- a/src/test/ui/suggestions/return-elided-lifetime.rs +++ b/src/test/ui/suggestions/return-elided-lifetime.rs @@ -6,32 +6,27 @@ fn f1() -> &i32 { loop {} } //~^ ERROR missing lifetime specifier [E0106] fn f1_() -> (&i32, &i32) { loop {} } -//~^ ERROR missing lifetime specifier [E0106] -//~^^ ERROR missing lifetime specifier [E0106] +//~^ ERROR missing lifetime specifiers [E0106] fn f2(a: i32, b: i32) -> &i32 { loop {} } //~^ ERROR missing lifetime specifier [E0106] fn f2_(a: i32, b: i32) -> (&i32, &i32) { loop {} } -//~^ ERROR missing lifetime specifier [E0106] -//~^^ ERROR missing lifetime specifier [E0106] +//~^ ERROR missing lifetime specifiers [E0106] struct S<'a, 'b> { a: &'a i32, b: &'b i32 } fn f3(s: &S) -> &i32 { loop {} } //~^ ERROR missing lifetime specifier [E0106] fn f3_(s: &S, t: &S) -> (&i32, &i32) { loop {} } -//~^ ERROR missing lifetime specifier [E0106] -//~^^ ERROR missing lifetime specifier [E0106] +//~^ ERROR missing lifetime specifiers [E0106] fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &i32 { loop {} } //~^ ERROR missing lifetime specifier [E0106] fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} } -//~^ ERROR missing lifetime specifier [E0106] -//~^^ ERROR missing lifetime specifier [E0106] +//~^ ERROR missing lifetime specifiers [E0106] fn f5<'a>(a: &'a i32, b: &i32) -> &i32 { loop {} } //~^ ERROR missing lifetime specifier [E0106] fn f5_<'a>(a: &'a i32, b: &i32) -> (&i32, &i32) { loop {} } -//~^ ERROR missing lifetime specifier [E0106] -//~^^ ERROR missing lifetime specifier [E0106] +//~^ ERROR missing lifetime specifiers [E0106] fn main() {} diff --git a/src/test/ui/suggestions/return-elided-lifetime.stderr b/src/test/ui/suggestions/return-elided-lifetime.stderr index f147b4463e2f2..273d95bc747d3 100644 --- a/src/test/ui/suggestions/return-elided-lifetime.stderr +++ b/src/test/ui/suggestions/return-elided-lifetime.stderr @@ -8,70 +8,50 @@ LL | fn f1() -> &i32 { loop {} } help: consider using the `'static` lifetime | LL | fn f1() -> &'static i32 { loop {} } - | ~~~~~~~~ + | +++++++ -error[E0106]: missing lifetime specifier +error[E0106]: missing lifetime specifiers --> $DIR/return-elided-lifetime.rs:8:14 | LL | fn f1_() -> (&i32, &i32) { loop {} } - | ^ expected named lifetime parameter + | ^ ^ expected named lifetime parameter + | | + | expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from help: consider using the `'static` lifetime | -LL | fn f1_() -> (&'static i32, &i32) { loop {} } - | ~~~~~~~~ +LL | fn f1_() -> (&'static i32, &'static i32) { loop {} } + | +++++++ +++++++ error[E0106]: missing lifetime specifier - --> $DIR/return-elided-lifetime.rs:8:20 - | -LL | fn f1_() -> (&i32, &i32) { loop {} } - | ^ 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 f1_() -> (&i32, &'static i32) { loop {} } - | ~~~~~~~~ - -error[E0106]: missing lifetime specifier - --> $DIR/return-elided-lifetime.rs:12:26 + --> $DIR/return-elided-lifetime.rs:11:26 | LL | fn f2(a: i32, b: i32) -> &i32 { loop {} } | ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments + = 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 f2(a: i32, b: i32) -> &'static i32 { loop {} } - | ~~~~~~~~ + | +++++++ -error[E0106]: missing lifetime specifier - --> $DIR/return-elided-lifetime.rs:14:28 +error[E0106]: missing lifetime specifiers + --> $DIR/return-elided-lifetime.rs:13:28 | LL | fn f2_(a: i32, b: i32) -> (&i32, &i32) { loop {} } - | ^ expected named lifetime parameter - | - = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments -help: consider using the `'static` lifetime + | ^ ^ expected named lifetime parameter + | | + | expected named lifetime parameter | -LL | fn f2_(a: i32, b: i32) -> (&'static i32, &i32) { loop {} } - | ~~~~~~~~ - -error[E0106]: missing lifetime specifier - --> $DIR/return-elided-lifetime.rs:14:34 - | -LL | fn f2_(a: i32, b: i32) -> (&i32, &i32) { loop {} } - | ^ expected named lifetime parameter - | - = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments + = 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 f2_(a: i32, b: i32) -> (&i32, &'static i32) { loop {} } - | ~~~~~~~~ +LL | fn f2_(a: i32, b: i32) -> (&'static i32, &'static i32) { loop {} } + | +++++++ +++++++ error[E0106]: missing lifetime specifier - --> $DIR/return-elided-lifetime.rs:19:17 + --> $DIR/return-elided-lifetime.rs:17:17 | LL | fn f3(s: &S) -> &i32 { loop {} } | -- ^ expected named lifetime parameter @@ -79,42 +59,32 @@ LL | fn f3(s: &S) -> &i32 { loop {} } = help: this function's return type contains a borrowed value, but the signature does not say which one of `s`'s 3 lifetimes it is borrowed from help: consider introducing a named lifetime parameter | -LL | fn f3<'a>(s: &'a S) -> &'a i32 { loop {} } - | ++++ ++ ++ +LL | fn f3<'a>(s: &'a S<'a, 'a>) -> &'a i32 { loop {} } + | ++++ ++ ++++++++ ++ -error[E0106]: missing lifetime specifier - --> $DIR/return-elided-lifetime.rs:21:26 +error[E0106]: missing lifetime specifiers + --> $DIR/return-elided-lifetime.rs:19:26 | LL | fn f3_(s: &S, t: &S) -> (&i32, &i32) { loop {} } - | -- -- ^ expected named lifetime parameter + | -- -- ^ ^ expected named lifetime parameter + | | + | expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `s`'s 3 lifetimes or one of `t`'s 3 lifetimes help: consider introducing a named lifetime parameter | -LL | fn f3_<'a>(s: &'a S, t: &'a S) -> (&'a i32, &i32) { loop {} } - | ++++ ++ ++ ++ +LL | fn f3_<'a>(s: &'a S<'a, 'a>, t: &'a S<'a, 'a>) -> (&'a i32, &'a i32) { loop {} } + | ++++ ++ ++++++++ ++ ++++++++ ++ ++ error[E0106]: missing lifetime specifier - --> $DIR/return-elided-lifetime.rs:21:32 - | -LL | fn f3_(s: &S, t: &S) -> (&i32, &i32) { loop {} } - | -- -- ^ expected named lifetime parameter - | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `s`'s 3 lifetimes or one of `t`'s 3 lifetimes -help: consider introducing a named lifetime parameter - | -LL | fn f3_<'a>(s: &'a S, t: &'a S) -> (&i32, &'a i32) { loop {} } - | ++++ ++ ++ ++ - -error[E0106]: missing lifetime specifier - --> $DIR/return-elided-lifetime.rs:25:42 + --> $DIR/return-elided-lifetime.rs:22:42 | LL | fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &i32 { loop {} } | ------- ------- ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b` + = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments note: these named lifetimes are available to use - --> $DIR/return-elided-lifetime.rs:25:7 + --> $DIR/return-elided-lifetime.rs:22:7 | LL | fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &i32 { loop {} } | ^^ ^^ @@ -123,42 +93,27 @@ help: consider using one of the available lifetimes here LL | fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &'lifetime i32 { loop {} } | +++++++++ -error[E0106]: missing lifetime specifier - --> $DIR/return-elided-lifetime.rs:27:44 - | -LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} } - | ------- ------- ^ expected named lifetime parameter - | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b` -note: these named lifetimes are available to use - --> $DIR/return-elided-lifetime.rs:27:8 - | -LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} } - | ^^ ^^ -help: consider using one of the available lifetimes here - | -LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&'lifetime i32, &i32) { loop {} } - | +++++++++ - -error[E0106]: missing lifetime specifier - --> $DIR/return-elided-lifetime.rs:27:50 +error[E0106]: missing lifetime specifiers + --> $DIR/return-elided-lifetime.rs:24:44 | LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} } - | ------- ------- ^ expected named lifetime parameter + | ------- ------- ^ ^ expected named lifetime parameter + | | + | expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b` + = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments note: these named lifetimes are available to use - --> $DIR/return-elided-lifetime.rs:27:8 + --> $DIR/return-elided-lifetime.rs:24:8 | LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} } | ^^ ^^ help: consider using one of the available lifetimes here | -LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &'lifetime i32) { loop {} } - | +++++++++ +LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&'lifetime i32, &'lifetime i32) { loop {} } + | +++++++++ +++++++++ error[E0106]: missing lifetime specifier - --> $DIR/return-elided-lifetime.rs:31:35 + --> $DIR/return-elided-lifetime.rs:27:35 | LL | fn f5<'a>(a: &'a i32, b: &i32) -> &i32 { loop {} } | ------- ---- ^ expected named lifetime parameter @@ -167,32 +122,22 @@ LL | fn f5<'a>(a: &'a i32, b: &i32) -> &i32 { loop {} } help: consider using the `'a` lifetime | LL | fn f5<'a>(a: &'a i32, b: &i32) -> &'a i32 { loop {} } - | ~~~ - -error[E0106]: missing lifetime specifier - --> $DIR/return-elided-lifetime.rs:33:37 - | -LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&i32, &i32) { loop {} } - | ------- ---- ^ expected named lifetime parameter - | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b` -help: consider using the `'a` lifetime - | -LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&'a i32, &i32) { loop {} } - | ~~~ + | ++ -error[E0106]: missing lifetime specifier - --> $DIR/return-elided-lifetime.rs:33:43 +error[E0106]: missing lifetime specifiers + --> $DIR/return-elided-lifetime.rs:29:37 | LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&i32, &i32) { loop {} } - | ------- ---- ^ expected named lifetime parameter + | ------- ---- ^ ^ expected named lifetime parameter + | | + | expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b` help: consider using the `'a` lifetime | -LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&i32, &'a i32) { loop {} } - | ~~~ +LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&'a i32, &'a i32) { loop {} } + | ++ ++ -error: aborting due to 15 previous errors +error: aborting due to 10 previous errors For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/suggestions/return-without-lifetime.stderr b/src/test/ui/suggestions/return-without-lifetime.stderr index 449a61d48090c..5028e8d628f27 100644 --- a/src/test/ui/suggestions/return-without-lifetime.stderr +++ b/src/test/ui/suggestions/return-without-lifetime.stderr @@ -7,7 +7,7 @@ LL | struct Foo<'a>(&usize); help: consider using the `'a` lifetime | LL | struct Foo<'a>(&'a usize); - | ~~~ + | ++ error[E0106]: missing lifetime specifier --> $DIR/return-without-lifetime.rs:5:34 @@ -19,7 +19,7 @@ LL | fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() } help: consider using the `'a` lifetime | LL | fn func1<'a>(_arg: &'a Thing) -> &'a () { unimplemented!() } - | ~~~ + | ++ error[E0106]: missing lifetime specifier --> $DIR/return-without-lifetime.rs:7:35 @@ -31,7 +31,7 @@ LL | fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() } help: consider using the `'a` lifetime | LL | fn func2<'a>(_arg: &Thing<'a>) -> &'a () { unimplemented!() } - | ~~~ + | ++ error: aborting due to 3 previous errors diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr index d25452456bb21..2b8fec86c8a18 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr @@ -5,6 +5,11 @@ LL | let _: dyn Foo(&isize, &usize) -> &usize; | ------ ------ ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | let _: dyn for<'a> Foo(&'a isize, &'a usize) -> &'a usize; + | +++++++ ++ ++ ++ help: consider introducing a named lifetime parameter | LL ~ fn main<'a>() { diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs index 37c87dbeaa9e5..e1deab736cf56 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs @@ -7,7 +7,6 @@ use std::fmt::Debug; struct Foo { x: Box, //~ ERROR missing lifetime specifier - //~^ ERROR E0228 } -fn main() { } +fn main() {} diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr index b865278e25fd8..fd08600280393 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr @@ -10,13 +10,6 @@ LL ~ struct Foo<'a> { LL ~ x: Box, | -error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound - --> $DIR/dyn-trait-underscore-in-struct.rs:9:12 - | -LL | x: Box, - | ^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0106, E0228. -For more information about an error, try `rustc --explain E0106`. +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr index 22bf1fdba326f..50401791effb8 100644 --- a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr +++ b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr @@ -1,3 +1,14 @@ +error[E0106]: missing lifetime specifier + --> $DIR/underscore-lifetime-binders.rs:2:17 + | +LL | struct Baz<'a>(&'_ &'a u8); + | ^^ expected named lifetime parameter + | +help: consider using the `'a` lifetime + | +LL | struct Baz<'a>(&'a &'a u8); + | ~~ + error[E0637]: `'_` cannot be used here --> $DIR/underscore-lifetime-binders.rs:4:8 | @@ -10,17 +21,6 @@ error[E0637]: `'_` cannot be used here LL | fn meh() -> Box Meh<'_>> | ^^ `'_` is a reserved lifetime name -error[E0106]: missing lifetime specifier - --> $DIR/underscore-lifetime-binders.rs:2:17 - | -LL | struct Baz<'a>(&'_ &'a u8); - | ^^ expected named lifetime parameter - | -help: consider using the `'a` lifetime - | -LL | struct Baz<'a>(&'a &'a u8); - | ~~ - error[E0106]: missing lifetime specifier --> $DIR/underscore-lifetime-binders.rs:10:33 | diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 083c437a293c0..826353aafc069 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -9,12 +9,14 @@ use rustc_hir::intravisit::{ use rustc_hir::FnRetTy::Return; use rustc_hir::{ BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem, - ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, LifetimeParamKind, ParamName, PolyTraitRef, - PredicateOrigin, TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, + ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, PredicateOrigin, + TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter as middle_nested_filter; +use rustc_middle::ty::TyCtxt; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Span; use rustc_span::symbol::{kw, Ident, Symbol}; @@ -129,7 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { enum RefLt { Unnamed, Static, - Named(Symbol), + Named(LocalDefId), } fn check_fn_inner<'tcx>( @@ -232,7 +234,7 @@ fn could_use_elision<'tcx>( // level of the current item. // check named LTs - let allowed_lts = allowed_lts_from(named_generics); + let allowed_lts = allowed_lts_from(cx.tcx, named_generics); // these will collect all the lifetimes for references in arg/return types let mut input_visitor = RefVisitor::new(cx); @@ -254,22 +256,6 @@ fn could_use_elision<'tcx>( return false; } - if allowed_lts - .intersection( - &input_visitor - .nested_elision_site_lts - .iter() - .chain(output_visitor.nested_elision_site_lts.iter()) - .cloned() - .filter(|v| matches!(v, RefLt::Named(_))) - .collect(), - ) - .next() - .is_some() - { - return false; - } - let input_lts = input_visitor.lts; let output_lts = output_visitor.lts; @@ -303,6 +289,31 @@ fn could_use_elision<'tcx>( } } + // check for higher-ranked trait bounds + if !input_visitor.nested_elision_site_lts.is_empty() || !output_visitor.nested_elision_site_lts.is_empty() { + let allowed_lts: FxHashSet<_> = allowed_lts + .iter() + .filter_map(|lt| match lt { + RefLt::Named(def_id) => Some(cx.tcx.item_name(def_id.to_def_id())), + _ => None, + }) + .collect(); + for lt in input_visitor.nested_elision_site_lts { + if let RefLt::Named(def_id) = lt { + if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) { + return false; + } + } + } + for lt in output_visitor.nested_elision_site_lts { + if let RefLt::Named(def_id) = lt { + if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) { + return false; + } + } + } + } + // no input lifetimes? easy case! if input_lts.is_empty() { false @@ -335,14 +346,11 @@ fn could_use_elision<'tcx>( } } -fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet { +fn allowed_lts_from(tcx: TyCtxt<'_>, named_generics: &[GenericParam<'_>]) -> FxHashSet { let mut allowed_lts = FxHashSet::default(); for par in named_generics.iter() { - if let GenericParamKind::Lifetime { - kind: LifetimeParamKind::Explicit, - } = par.kind - { - allowed_lts.insert(RefLt::Named(par.name.ident().name)); + if let GenericParamKind::Lifetime { .. } = par.kind { + allowed_lts.insert(RefLt::Named(tcx.hir().local_def_id(par.hir_id))); } } allowed_lts.insert(RefLt::Unnamed); @@ -385,8 +393,10 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> { self.lts.push(RefLt::Unnamed); } else if lt.is_elided() { self.lts.push(RefLt::Unnamed); + } else if let LifetimeName::Param(def_id, _) = lt.name { + self.lts.push(RefLt::Named(def_id)); } else { - self.lts.push(RefLt::Named(lt.name.ident().name)); + self.lts.push(RefLt::Unnamed); } } else { self.lts.push(RefLt::Unnamed); @@ -434,10 +444,15 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { TyKind::OpaqueDef(item, bounds) => { let map = self.cx.tcx.hir(); let item = map.item(item); + let len = self.lts.len(); walk_item(self, item); - walk_ty(self, ty); + self.lts.truncate(len); self.lts.extend(bounds.iter().filter_map(|bound| match bound { - GenericArg::Lifetime(l) => Some(RefLt::Named(l.name.ident().name)), + GenericArg::Lifetime(l) => Some(if let LifetimeName::Param(def_id, _) = l.name { + RefLt::Named(def_id) + } else { + RefLt::Unnamed + }), _ => None, })); }, @@ -456,9 +471,8 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { } return; }, - _ => (), + _ => walk_ty(self, ty), } - walk_ty(self, ty); } } @@ -477,7 +491,7 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_ return true; } // if the bounds define new lifetimes, they are fine to occur - let allowed_lts = allowed_lts_from(pred.bound_generic_params); + let allowed_lts = allowed_lts_from(cx.tcx, pred.bound_generic_params); // now walk the bounds for bound in pred.bounds.iter() { walk_param_bound(&mut visitor, bound);