From 364475b281519695da69736ac2ee38c254b30c4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 16 Jan 2025 20:56:37 +0000 Subject: [PATCH 1/8] Add tests for some cases mentioned in #135589 --- .../missing-lifetime-in-assoc-type-1.rs | 16 +++++++++++++ .../missing-lifetime-in-assoc-type-1.stderr | 15 ++++++++++++ .../missing-lifetime-in-assoc-type-2.rs | 14 +++++++++++ .../missing-lifetime-in-assoc-type-2.stderr | 24 +++++++++++++++++++ .../missing-lifetime-in-assoc-type-3.rs | 14 +++++++++++ .../missing-lifetime-in-assoc-type-3.stderr | 20 ++++++++++++++++ .../missing-lifetime-in-assoc-type-4.rs | 14 +++++++++++ .../missing-lifetime-in-assoc-type-4.stderr | 15 ++++++++++++ 8 files changed, 132 insertions(+) create mode 100644 tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.rs create mode 100644 tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.stderr create mode 100644 tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.rs create mode 100644 tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.stderr create mode 100644 tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.rs create mode 100644 tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.stderr create mode 100644 tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.rs create mode 100644 tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.stderr diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.rs b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.rs new file mode 100644 index 0000000000000..28e86635b1b79 --- /dev/null +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.rs @@ -0,0 +1,16 @@ +struct S; +struct T; + +impl<'a> IntoIterator for &S { + //~^ ERROR E0207 + //~| NOTE unconstrained lifetime parameter + type Item = &T; + //~^ ERROR in the trait associated type + //~| NOTE this lifetime must come from the implemented type + type IntoIter = std::collections::btree_map::Values<'a, i32, T>; + + fn into_iter(self) -> Self::IntoIter { + todo!() + } +} +fn main() {} diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.stderr b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.stderr new file mode 100644 index 0000000000000..0796f65b9b2d1 --- /dev/null +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.stderr @@ -0,0 +1,15 @@ +error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + --> $DIR/missing-lifetime-in-assoc-type-1.rs:7:17 + | +LL | type Item = &T; + | ^ this lifetime must come from the implemented type + +error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates + --> $DIR/missing-lifetime-in-assoc-type-1.rs:4:6 + | +LL | impl<'a> IntoIterator for &S { + | ^^ unconstrained lifetime parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.rs b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.rs new file mode 100644 index 0000000000000..dd720f075ac46 --- /dev/null +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.rs @@ -0,0 +1,14 @@ +struct S; +struct T; + +impl IntoIterator for &S { + type Item = &T; + //~^ ERROR in the trait associated type + type IntoIter = std::collections::btree_map::Values<'a, i32, T>; + //~^ ERROR use of undeclared lifetime name `'a` + + fn into_iter(self) -> Self::IntoIter { + todo!() + } +} +fn main() {} diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.stderr b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.stderr new file mode 100644 index 0000000000000..77916b651b13c --- /dev/null +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.stderr @@ -0,0 +1,24 @@ +error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + --> $DIR/missing-lifetime-in-assoc-type-2.rs:5:17 + | +LL | type Item = &T; + | ^ this lifetime must come from the implemented type + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/missing-lifetime-in-assoc-type-2.rs:7:57 + | +LL | type IntoIter = std::collections::btree_map::Values<'a, i32, T>; + | ^^ undeclared lifetime + | +help: consider introducing lifetime `'a` here + | +LL | type IntoIter<'a> = std::collections::btree_map::Values<'a, i32, T>; + | ++++ +help: consider introducing lifetime `'a` here + | +LL | impl<'a> IntoIterator for &S { + | ++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0261`. diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.rs b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.rs new file mode 100644 index 0000000000000..60d1f0f8fe571 --- /dev/null +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.rs @@ -0,0 +1,14 @@ +struct S; +struct T; + +impl IntoIterator for &S { + type Item = &T; + //~^ ERROR in the trait associated type + type IntoIter = std::collections::btree_map::Values; + //~^ ERROR missing lifetime specifier + + fn into_iter(self) -> Self::IntoIter { + todo!() + } +} +fn main() {} diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.stderr b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.stderr new file mode 100644 index 0000000000000..50012ac72d22f --- /dev/null +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.stderr @@ -0,0 +1,20 @@ +error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + --> $DIR/missing-lifetime-in-assoc-type-3.rs:5:17 + | +LL | type Item = &T; + | ^ this lifetime must come from the implemented type + +error[E0106]: missing lifetime specifier + --> $DIR/missing-lifetime-in-assoc-type-3.rs:7:56 + | +LL | type IntoIter = std::collections::btree_map::Values; + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type IntoIter<'a> = std::collections::btree_map::Values<'a, i32, T>; + | ++++ +++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0106`. diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.rs b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.rs new file mode 100644 index 0000000000000..b01c59f3ee6d2 --- /dev/null +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.rs @@ -0,0 +1,14 @@ +struct S; +struct T; + +impl IntoIterator for &S { + type Item = &T; + //~^ ERROR in the trait associated type + type IntoIter<'a> = std::collections::btree_map::Values<'a, i32, T>; + //~^ ERROR lifetime parameters or bounds on type `IntoIter` do not match the trait declaration + + fn into_iter(self) -> Self::IntoIter { + todo!() + } +} +fn main() {} diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.stderr b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.stderr new file mode 100644 index 0000000000000..f17c098ab6d04 --- /dev/null +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.stderr @@ -0,0 +1,15 @@ +error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + --> $DIR/missing-lifetime-in-assoc-type-4.rs:5:17 + | +LL | type Item = &T; + | ^ this lifetime must come from the implemented type + +error[E0195]: lifetime parameters or bounds on type `IntoIter` do not match the trait declaration + --> $DIR/missing-lifetime-in-assoc-type-4.rs:7:18 + | +LL | type IntoIter<'a> = std::collections::btree_map::Values<'a, i32, T>; + | ^^^^ lifetimes do not match type in trait + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0195`. From 31556877de42e30a27edabb40014535932137cc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 16 Jan 2025 21:02:23 +0000 Subject: [PATCH 2/8] Detect case of missing lifetime in assoc type When an associated type is missing a lifetime, point at its enclosing `impl`, whether it has or doesn't have lifetimes defined. If it does have a lifetime, suggest using it. ``` error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type --> $DIR/missing-lifetime-in-assoc-type-1.rs:8:17 | LL | impl<'a> IntoIterator for &S { | ---- there is a named lifetime specified on the impl block you could use ... LL | type Item = &T; | ^ this lifetime must come from the implemented type | help: consider using the lifetime from the impl block | LL | type Item = &'a T; | ++ ``` ``` error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type --> $DIR/missing-lifetime-in-assoc-type-2.rs:5:17 | LL | impl IntoIterator for &S { | - you could add a lifetime on the impl block, if the trait or the self type can have one LL | type Item = &T; | ^ this lifetime must come from the implemented type ``` --- compiler/rustc_resolve/src/late.rs | 54 +++++++++++++++++-- .../assoc-type.stderr | 2 + .../missing-lifetime-in-assoc-type-1.rs | 2 + .../missing-lifetime-in-assoc-type-1.stderr | 10 +++- .../missing-lifetime-in-assoc-type-2.stderr | 2 + .../missing-lifetime-in-assoc-type-3.stderr | 2 + .../missing-lifetime-in-assoc-type-4.rs | 2 +- .../missing-lifetime-in-assoc-type-4.stderr | 6 ++- .../ui/lifetimes/no_lending_iterators.stderr | 2 + 9 files changed, 74 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index e52cbeb733ac0..cc1eaaa46772e 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -20,7 +20,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, DiagArgValue, ErrorGuaranteed, IntoDiagArg, StashKey, Suggestions, + Applicability, Diag, DiagArgValue, ErrorGuaranteed, IntoDiagArg, StashKey, Suggestions, + pluralize, }; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS}; @@ -1887,9 +1888,13 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ty: ty.span, }); } else { - self.r.dcx().emit_err(errors::AnonymousLifetimeNonGatReportError { - lifetime: lifetime.ident.span, - }); + let mut err = self.r.dcx().create_err( + errors::AnonymousLifetimeNonGatReportError { + lifetime: lifetime.ident.span, + }, + ); + self.point_at_impl_lifetimes(&mut err, i, lifetime.ident.span); + err.emit(); } } else { self.r.dcx().emit_err(errors::ElidedAnonymousLifetimeReportError { @@ -1926,6 +1931,47 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.report_missing_lifetime_specifiers(vec![missing_lifetime], None); } + fn point_at_impl_lifetimes(&mut self, err: &mut Diag<'_>, i: usize, lifetime: Span) { + let Some((rib, span)) = self.lifetime_ribs[..i] + .iter() + .rev() + .skip(1) + .filter_map(|rib| match rib.kind { + LifetimeRibKind::Generics { span, kind: LifetimeBinderKind::ImplBlock, .. } => { + Some((rib, span)) + } + _ => None, + }) + .next() + else { + return; + }; + if !rib.bindings.is_empty() { + err.span_label( + span, + format!( + "there {} named lifetime{} specified on the impl block you could use", + if rib.bindings.len() == 1 { "is a" } else { "are" }, + pluralize!(rib.bindings.len()), + ), + ); + if rib.bindings.len() == 1 { + err.span_suggestion_verbose( + lifetime.shrink_to_hi(), + "consider using the lifetime from the impl block", + format!("{} ", rib.bindings.keys().next().unwrap()), + Applicability::MaybeIncorrect, + ); + } + } else { + err.span_label( + span, + "you could add a lifetime on the impl block, if the trait or the self type can \ + have one", + ); + } + } + #[instrument(level = "debug", skip(self))] fn resolve_elided_lifetime(&mut self, anchor_id: NodeId, span: Span) { let id = self.r.next_node_id(); diff --git a/tests/ui/impl-header-lifetime-elision/assoc-type.stderr b/tests/ui/impl-header-lifetime-elision/assoc-type.stderr index e650eeca48ad9..72c066426bd99 100644 --- a/tests/ui/impl-header-lifetime-elision/assoc-type.stderr +++ b/tests/ui/impl-header-lifetime-elision/assoc-type.stderr @@ -1,6 +1,8 @@ error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type --> $DIR/assoc-type.rs:11:19 | +LL | impl MyTrait for &i32 { + | - you could add a lifetime on the impl block, if the trait or the self type can have one LL | type Output = &i32; | ^ this lifetime must come from the implemented type diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.rs b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.rs index 28e86635b1b79..5953466375d4e 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.rs +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.rs @@ -3,9 +3,11 @@ struct T; impl<'a> IntoIterator for &S { //~^ ERROR E0207 + //~| NOTE there is a named lifetime specified on the impl block you could use //~| NOTE unconstrained lifetime parameter type Item = &T; //~^ ERROR in the trait associated type + //~| HELP consider using the lifetime from the impl block //~| NOTE this lifetime must come from the implemented type type IntoIter = std::collections::btree_map::Values<'a, i32, T>; diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.stderr b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.stderr index 0796f65b9b2d1..1fbde0cfb3988 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.stderr +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.stderr @@ -1,8 +1,16 @@ error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type - --> $DIR/missing-lifetime-in-assoc-type-1.rs:7:17 + --> $DIR/missing-lifetime-in-assoc-type-1.rs:8:17 | +LL | impl<'a> IntoIterator for &S { + | ---- there is a named lifetime specified on the impl block you could use +... LL | type Item = &T; | ^ this lifetime must come from the implemented type + | +help: consider using the lifetime from the impl block + | +LL | type Item = &'a T; + | ++ error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates --> $DIR/missing-lifetime-in-assoc-type-1.rs:4:6 diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.stderr b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.stderr index 77916b651b13c..8408d37a901fd 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.stderr +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.stderr @@ -1,6 +1,8 @@ error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type --> $DIR/missing-lifetime-in-assoc-type-2.rs:5:17 | +LL | impl IntoIterator for &S { + | - you could add a lifetime on the impl block, if the trait or the self type can have one LL | type Item = &T; | ^ this lifetime must come from the implemented type diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.stderr b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.stderr index 50012ac72d22f..d93852aee1bd3 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.stderr +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.stderr @@ -1,6 +1,8 @@ error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type --> $DIR/missing-lifetime-in-assoc-type-3.rs:5:17 | +LL | impl IntoIterator for &S { + | - you could add a lifetime on the impl block, if the trait or the self type can have one LL | type Item = &T; | ^ this lifetime must come from the implemented type diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.rs b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.rs index b01c59f3ee6d2..0c99e8874c354 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.rs +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.rs @@ -5,7 +5,7 @@ impl IntoIterator for &S { type Item = &T; //~^ ERROR in the trait associated type type IntoIter<'a> = std::collections::btree_map::Values<'a, i32, T>; - //~^ ERROR lifetime parameters or bounds on type `IntoIter` do not match the trait declaration + //~^ ERROR lifetime parameters or bounds on associated type `IntoIter` do not match the trait declaration fn into_iter(self) -> Self::IntoIter { todo!() diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.stderr b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.stderr index f17c098ab6d04..ebe051509aad2 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.stderr +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.stderr @@ -1,14 +1,16 @@ error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type --> $DIR/missing-lifetime-in-assoc-type-4.rs:5:17 | +LL | impl IntoIterator for &S { + | - you could add a lifetime on the impl block, if the trait or the self type can have one LL | type Item = &T; | ^ this lifetime must come from the implemented type -error[E0195]: lifetime parameters or bounds on type `IntoIter` do not match the trait declaration +error[E0195]: lifetime parameters or bounds on associated type `IntoIter` do not match the trait declaration --> $DIR/missing-lifetime-in-assoc-type-4.rs:7:18 | LL | type IntoIter<'a> = std::collections::btree_map::Values<'a, i32, T>; - | ^^^^ lifetimes do not match type in trait + | ^^^^ lifetimes do not match associated type in trait error: aborting due to 2 previous errors diff --git a/tests/ui/lifetimes/no_lending_iterators.stderr b/tests/ui/lifetimes/no_lending_iterators.stderr index 340ef93588515..cadba149c234d 100644 --- a/tests/ui/lifetimes/no_lending_iterators.stderr +++ b/tests/ui/lifetimes/no_lending_iterators.stderr @@ -13,6 +13,8 @@ LL | impl Iterator for Data { error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type --> $DIR/no_lending_iterators.rs:18:17 | +LL | impl Bar for usize { + | - you could add a lifetime on the impl block, if the trait or the self type can have one LL | type Item = &usize; | ^ this lifetime must come from the implemented type From 02b8028cb3b677940a5d3620da79206a9d42dd1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 16 Jan 2025 21:38:14 +0000 Subject: [PATCH 3/8] On unconstrained lifetime on `impl` block, suggest using it if there's an implicit borrow in the self type ``` error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates --> $DIR/missing-lifetime-in-assoc-type-1.rs:4:6 | LL | impl<'a> IntoIterator for &S { | ^^ unconstrained lifetime parameter | help: consider using the named lifetime here instead of an implict lifetime | LL | impl<'a> IntoIterator for &'a S { | ++ ``` --- .../rustc_hir_analysis/src/impl_wf_check.rs | 24 +++++++++++++++- .../missing-lifetime-in-assoc-type-1.rs | 1 + .../missing-lifetime-in-assoc-type-1.stderr | 7 ++++- .../missing-lifetime-in-assoc-type-5.rs | 19 +++++++++++++ .../missing-lifetime-in-assoc-type-5.stderr | 28 +++++++++++++++++++ 5 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 tests/ui/lifetimes/missing-lifetime-in-assoc-type-5.rs create mode 100644 tests/ui/lifetimes/missing-lifetime-in-assoc-type-5.stderr diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index cbdc501291bc8..5b8eef0965759 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -12,11 +12,12 @@ use std::assert_matches::debug_assert_matches; use min_specialization::check_min_specialization; use rustc_data_structures::fx::FxHashSet; +use rustc_errors::Applicability; use rustc_errors::codes::*; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; -use rustc_span::ErrorGuaranteed; +use rustc_span::{ErrorGuaranteed, kw}; use crate::constrained_generic_params as cgp; use crate::errors::UnconstrainedGenericParameter; @@ -158,6 +159,27 @@ pub(crate) fn enforce_impl_lifetime_params_are_constrained( const_param_note2: false, }); diag.code(E0207); + for p in &impl_generics.own_params { + if p.name == kw::UnderscoreLifetime { + let span = tcx.def_span(p.def_id); + let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) else { + continue; + }; + + let (span, sugg) = if &snippet == "'_" { + (span, param.name.to_string()) + } else { + (span.shrink_to_hi(), format!("{} ", param.name)) + }; + diag.span_suggestion_verbose( + span, + "consider using the named lifetime here instead of an implict \ + lifetime", + sugg, + Applicability::MaybeIncorrect, + ); + } + } res = Err(diag.emit()); } } diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.rs b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.rs index 5953466375d4e..1ae381ef7bc02 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.rs +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.rs @@ -5,6 +5,7 @@ impl<'a> IntoIterator for &S { //~^ ERROR E0207 //~| NOTE there is a named lifetime specified on the impl block you could use //~| NOTE unconstrained lifetime parameter + //~| HELP consider using the named lifetime here instead of an implict lifetime type Item = &T; //~^ ERROR in the trait associated type //~| HELP consider using the lifetime from the impl block diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.stderr b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.stderr index 1fbde0cfb3988..bf26ce4a63027 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.stderr +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.stderr @@ -1,5 +1,5 @@ error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type - --> $DIR/missing-lifetime-in-assoc-type-1.rs:8:17 + --> $DIR/missing-lifetime-in-assoc-type-1.rs:9:17 | LL | impl<'a> IntoIterator for &S { | ---- there is a named lifetime specified on the impl block you could use @@ -17,6 +17,11 @@ error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, | LL | impl<'a> IntoIterator for &S { | ^^ unconstrained lifetime parameter + | +help: consider using the named lifetime here instead of an implict lifetime + | +LL | impl<'a> IntoIterator for &'a S { + | ++ error: aborting due to 2 previous errors diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-5.rs b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-5.rs new file mode 100644 index 0000000000000..ff64d6b900949 --- /dev/null +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-5.rs @@ -0,0 +1,19 @@ +struct S; +struct T; + +impl<'a> IntoIterator for &'_ S { + //~^ ERROR E0207 + //~| NOTE there is a named lifetime specified on the impl block you could use + //~| NOTE unconstrained lifetime parameter + //~| HELP consider using the named lifetime here instead of an implict lifetime + type Item = &T; + //~^ ERROR in the trait associated type + //~| HELP consider using the lifetime from the impl block + //~| NOTE this lifetime must come from the implemented type + type IntoIter = std::collections::btree_map::Values<'a, i32, T>; + + fn into_iter(self) -> Self::IntoIter { + todo!() + } +} +fn main() {} diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-5.stderr b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-5.stderr new file mode 100644 index 0000000000000..7a63bd5b05eff --- /dev/null +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-5.stderr @@ -0,0 +1,28 @@ +error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + --> $DIR/missing-lifetime-in-assoc-type-5.rs:9:17 + | +LL | impl<'a> IntoIterator for &'_ S { + | ---- there is a named lifetime specified on the impl block you could use +... +LL | type Item = &T; + | ^ this lifetime must come from the implemented type + | +help: consider using the lifetime from the impl block + | +LL | type Item = &'a T; + | ++ + +error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates + --> $DIR/missing-lifetime-in-assoc-type-5.rs:4:6 + | +LL | impl<'a> IntoIterator for &'_ S { + | ^^ unconstrained lifetime parameter + | +help: consider using the named lifetime here instead of an implict lifetime + | +LL | impl<'a> IntoIterator for &'a S { + | ~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0207`. From 6fcc9f5b16526f9c221eba01bacf5ad84cf859f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 16 Jan 2025 22:12:35 +0000 Subject: [PATCH 4/8] Do not suggest introducing lifetime in impl assoc type ``` error[E0261]: use of undeclared lifetime name `'a` --> $DIR/missing-lifetime-in-assoc-type-2.rs:7:57 | LL | impl IntoIterator for &S { | - help: consider introducing lifetime `'a` here: `<'a>` ... LL | type IntoIter = std::collections::btree_map::Values<'a, i32, T>; | ^^ undeclared lifetime ``` ``` error[E0106]: missing lifetime specifier --> $DIR/issue-74918-missing-lifetime.rs:9:30 | LL | type Item = IteratorChunk; | ^ expected named lifetime parameter | help: consider introducing a named lifetime parameter | LL ~ impl<'a, T, S: Iterator> Iterator for ChunkingIterator { LL ~ type Item = IteratorChunk<'a, T, S>; | ``` --- compiler/rustc_resolve/src/late.rs | 4 +++- compiler/rustc_resolve/src/late/diagnostics.rs | 3 +++ tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.stderr | 4 ---- tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.stderr | 7 +++++-- tests/ui/lifetimes/missing-lifetime-in-assoc-type-5.stderr | 5 +++-- .../mismatched_types/issue-74918-missing-lifetime.stderr | 5 +++-- .../ui/nll/user-annotations/region-error-ice-109072.stderr | 4 ---- 7 files changed, 17 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index cc1eaaa46772e..12c5f7fbc1113 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -378,6 +378,7 @@ enum LifetimeBinderKind { Function, Closure, ImplBlock, + ImplAssocType, } impl LifetimeBinderKind { @@ -388,6 +389,7 @@ impl LifetimeBinderKind { PolyTrait => "bound", WhereBound => "bound", Item | ConstItem => "item", + ImplAssocType => "associated type", ImplBlock => "impl block", Function => "function", Closure => "closure", @@ -3406,7 +3408,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { &generics.params, RibKind::AssocItem, item.id, - LifetimeBinderKind::Item, + LifetimeBinderKind::ImplAssocType, generics.span, |this| { this.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index aca251da71d39..f1fde99f1fc12 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -3154,6 +3154,9 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { { continue; } + if let LifetimeBinderKind::ImplAssocType = kind { + continue; + } if !span.can_be_used_for_suggestions() && suggest_note diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.stderr b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.stderr index 8408d37a901fd..7a0246eaac8fd 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.stderr +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.stderr @@ -14,10 +14,6 @@ LL | type IntoIter = std::collections::btree_map::Values<'a, i32, T>; | help: consider introducing lifetime `'a` here | -LL | type IntoIter<'a> = std::collections::btree_map::Values<'a, i32, T>; - | ++++ -help: consider introducing lifetime `'a` here - | LL | impl<'a> IntoIterator for &S { | ++++ diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.stderr b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.stderr index d93852aee1bd3..408d5bb40664d 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.stderr +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.stderr @@ -14,8 +14,11 @@ LL | type IntoIter = std::collections::btree_map::Values; | help: consider introducing a named lifetime parameter | -LL | type IntoIter<'a> = std::collections::btree_map::Values<'a, i32, T>; - | ++++ +++ +LL ~ impl<'a> IntoIterator for &S { +LL | type Item = &T; +LL | +LL ~ type IntoIter = std::collections::btree_map::Values<'a, i32, T>; + | error: aborting due to 2 previous errors diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-5.stderr b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-5.stderr index 7a63bd5b05eff..9c960c67e2502 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-5.stderr +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-5.stderr @@ -20,8 +20,9 @@ LL | impl<'a> IntoIterator for &'_ S { | help: consider using the named lifetime here instead of an implict lifetime | -LL | impl<'a> IntoIterator for &'a S { - | ~~ +LL - impl<'a> IntoIterator for &'_ S { +LL + impl<'a> IntoIterator for &'a S { + | error: aborting due to 2 previous errors diff --git a/tests/ui/mismatched_types/issue-74918-missing-lifetime.stderr b/tests/ui/mismatched_types/issue-74918-missing-lifetime.stderr index 5020395eb6aea..dc21c2e3cf9bf 100644 --- a/tests/ui/mismatched_types/issue-74918-missing-lifetime.stderr +++ b/tests/ui/mismatched_types/issue-74918-missing-lifetime.stderr @@ -6,8 +6,9 @@ LL | type Item = IteratorChunk; | help: consider introducing a named lifetime parameter | -LL | type Item<'a> = IteratorChunk<'a, T, S>; - | ++++ +++ +LL ~ impl<'a, T, S: Iterator> Iterator for ChunkingIterator { +LL ~ type Item = IteratorChunk<'a, T, S>; + | error: aborting due to 1 previous error diff --git a/tests/ui/nll/user-annotations/region-error-ice-109072.stderr b/tests/ui/nll/user-annotations/region-error-ice-109072.stderr index 42551b87f6234..026f5b5f80a9b 100644 --- a/tests/ui/nll/user-annotations/region-error-ice-109072.stderr +++ b/tests/ui/nll/user-annotations/region-error-ice-109072.stderr @@ -17,10 +17,6 @@ LL | type T = &'missing (); | help: consider introducing lifetime `'missing` here | -LL | type T<'missing> = &'missing (); - | ++++++++++ -help: consider introducing lifetime `'missing` here - | LL | impl<'missing> Lt<'missing> for () { | ++++++++++ From 4b394b2d720cb2e6d99a039200c292e49165c7be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 16 Jan 2025 22:21:24 +0000 Subject: [PATCH 5/8] Always point at trait assoc item when generics don't match Previously we only showed the trait's assoc item if the trait was local, because we were looking for a small span only for the generics, which we don't have for foreign traits. We now use `def_span` for the item, so we at least provide some context, even if its span is too wide. ``` error[E0195]: lifetime parameters or bounds on type `IntoIter` do not match the trait declaration --> tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.rs:7:18 | 7 | type IntoIter<'a> = std::collections::btree_map::Values<'a, i32, T>; | ^^^^ lifetimes do not match type in trait | ::: /home/gh-estebank/rust/library/core/src/iter/traits/collect.rs:292:5 | 292 | type IntoIter: Iterator; | ------------------------------------------ lifetimes in impl do not match this type in trait ``` --- compiler/rustc_hir_analysis/src/check/compare_impl_item.rs | 4 ++-- compiler/rustc_hir_analysis/src/errors.rs | 2 +- tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.stderr | 3 +++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 6767e5ed88d4d..26084ff6b0b83 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1103,14 +1103,14 @@ fn check_region_bounds_on_impl_item<'tcx>( .expect("expected impl item to have generics or else we can't compare them") .span; - let mut generics_span = None; + let mut generics_span = tcx.def_span(trait_m.def_id); let mut bounds_span = vec![]; let mut where_span = None; if let Some(trait_node) = tcx.hir_get_if_local(trait_m.def_id) && let Some(trait_generics) = trait_node.generics() { - generics_span = Some(trait_generics.span); + generics_span = trait_generics.span; // FIXME: we could potentially look at the impl's bounds to not point at bounds that // *are* present in the impl. for p in trait_generics.predicates { diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 26a98722b341e..50941dcb5b99d 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -190,7 +190,7 @@ pub(crate) struct LifetimesOrBoundsMismatchOnTrait { #[label] pub span: Span, #[label(hir_analysis_generics_label)] - pub generics_span: Option, + pub generics_span: Span, #[label(hir_analysis_where_label)] pub where_span: Option, #[label(hir_analysis_bounds_label)] diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.stderr b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.stderr index ebe051509aad2..f07b5cdd65ca6 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.stderr +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.stderr @@ -11,6 +11,9 @@ error[E0195]: lifetime parameters or bounds on associated type `IntoIter` do not | LL | type IntoIter<'a> = std::collections::btree_map::Values<'a, i32, T>; | ^^^^ lifetimes do not match associated type in trait + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + | + = note: lifetimes in impl do not match this associated type in trait error: aborting due to 2 previous errors From 41159f6d4ad8ec44630c9298534be02574396774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 16 Jan 2025 23:03:26 +0000 Subject: [PATCH 6/8] Look at the current `impl` before suggesting adding a lifetime Given an associated item that needs a named lifetime, look at the enclosing `impl` item for one. If there is none, look at the self type and the implemented trait to see if either of those has an anonimous lifetime. If so, suggest adding a named lifetime. ``` error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type --> $DIR/missing-lifetime-in-assoc-type-2.rs:5:17 | LL | type Item = &T; | ^ this lifetime must come from the implemented type | help: add a lifetime to the impl block and use it in the self type and associated type | LL ~ impl<'a> IntoIterator for &'a S { LL ~ type Item = &'a T; | ``` --- compiler/rustc_resolve/src/late.rs | 63 +++++++++++++++++-- .../assoc-type.rs | 13 ++++ .../assoc-type.stderr | 35 ++++++++++- .../missing-lifetime-in-assoc-type-2.stderr | 8 ++- .../missing-lifetime-in-assoc-type-3.stderr | 8 ++- .../missing-lifetime-in-assoc-type-4.stderr | 8 ++- .../ui/lifetimes/no_lending_iterators.stderr | 2 +- 7 files changed, 122 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 12c5f7fbc1113..fa07f35166538 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -11,6 +11,7 @@ use std::borrow::Cow; use std::collections::BTreeSet; use std::collections::hash_map::Entry; use std::mem::{replace, swap, take}; +use std::ops::ControlFlow; use rustc_ast::visit::{ AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, try_visit, visit_opt, walk_list, @@ -1966,11 +1967,63 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ); } } else { - err.span_label( - span, - "you could add a lifetime on the impl block, if the trait or the self type can \ - have one", - ); + struct AnonRefFinder; + impl<'ast> Visitor<'ast> for AnonRefFinder { + type Result = ControlFlow; + + fn visit_ty(&mut self, ty: &'ast ast::Ty) -> Self::Result { + if let ast::TyKind::Ref(None, mut_ty) = &ty.kind { + return ControlFlow::Break(mut_ty.ty.span.shrink_to_lo()); + } + visit::walk_ty(self, ty) + } + + fn visit_lifetime( + &mut self, + lt: &'ast ast::Lifetime, + _cx: visit::LifetimeCtxt, + ) -> Self::Result { + if lt.ident.name == kw::UnderscoreLifetime { + return ControlFlow::Break(lt.ident.span); + } + visit::walk_lifetime(self, lt) + } + } + + if let Some(ty) = &self.diag_metadata.current_self_type + && let ControlFlow::Break(sp) = AnonRefFinder.visit_ty(ty) + { + err.multipart_suggestion_verbose( + "add a lifetime to the impl block and use it in the self type and associated \ + type", + vec![ + (span, "<'a>".to_string()), + (sp, "'a ".to_string()), + (lifetime.shrink_to_hi(), "'a ".to_string()), + ], + Applicability::MaybeIncorrect, + ); + } else if let Some(item) = &self.diag_metadata.current_item + && let ItemKind::Impl(impl_) = &item.kind + && let Some(of_trait) = &impl_.of_trait + && let ControlFlow::Break(sp) = AnonRefFinder.visit_trait_ref(of_trait) + { + err.multipart_suggestion_verbose( + "add a lifetime to the impl block and use it in the trait and associated type", + vec![ + (span, "<'a>".to_string()), + (sp, "'a".to_string()), + (lifetime.shrink_to_hi(), "'a ".to_string()), + ], + Applicability::MaybeIncorrect, + ); + } else { + err.span_label( + span, + "you could add a lifetime on the impl block, if the trait or the self type \ + could have one", + ); + } } } diff --git a/tests/ui/impl-header-lifetime-elision/assoc-type.rs b/tests/ui/impl-header-lifetime-elision/assoc-type.rs index 14b2ea647f190..e999bd02db26e 100644 --- a/tests/ui/impl-header-lifetime-elision/assoc-type.rs +++ b/tests/ui/impl-header-lifetime-elision/assoc-type.rs @@ -17,6 +17,19 @@ impl MyTrait for &u32 { //~^ ERROR `'_` cannot be used here } +impl<'a> MyTrait for &f64 { + type Output = &f64; + //~^ ERROR in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type +} + +trait OtherTrait<'a> { + type Output; +} +impl OtherTrait<'_> for f64 { + type Output = &f64; + //~^ ERROR in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type +} + // This is what you have to do: impl<'a> MyTrait for &'a f32 { type Output = &'a f32; diff --git a/tests/ui/impl-header-lifetime-elision/assoc-type.stderr b/tests/ui/impl-header-lifetime-elision/assoc-type.stderr index 72c066426bd99..933ed3efec5d6 100644 --- a/tests/ui/impl-header-lifetime-elision/assoc-type.stderr +++ b/tests/ui/impl-header-lifetime-elision/assoc-type.stderr @@ -1,10 +1,14 @@ error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type --> $DIR/assoc-type.rs:11:19 | -LL | impl MyTrait for &i32 { - | - you could add a lifetime on the impl block, if the trait or the self type can have one LL | type Output = &i32; | ^ this lifetime must come from the implemented type + | +help: add a lifetime to the impl block and use it in the self type and associated type + | +LL ~ impl<'a> MyTrait for &'a i32 { +LL ~ type Output = &'a i32; + | error[E0637]: `'_` cannot be used here --> $DIR/assoc-type.rs:16:20 @@ -12,6 +16,31 @@ error[E0637]: `'_` cannot be used here LL | type Output = &'_ i32; | ^^ `'_` is a reserved lifetime name -error: aborting due to 2 previous errors +error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + --> $DIR/assoc-type.rs:21:19 + | +LL | impl<'a> MyTrait for &f64 { + | ---- there is a named lifetime specified on the impl block you could use +LL | type Output = &f64; + | ^ this lifetime must come from the implemented type + | +help: consider using the lifetime from the impl block + | +LL | type Output = &'a f64; + | ++ + +error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + --> $DIR/assoc-type.rs:29:19 + | +LL | type Output = &f64; + | ^ this lifetime must come from the implemented type + | +help: add a lifetime to the impl block and use it in the trait and associated type + | +LL ~ impl<'a> OtherTrait<'a> for f64 { +LL ~ type Output = &'a f64; + | + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0637`. diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.stderr b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.stderr index 7a0246eaac8fd..cd6fa2894ad28 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.stderr +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.stderr @@ -1,10 +1,14 @@ error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type --> $DIR/missing-lifetime-in-assoc-type-2.rs:5:17 | -LL | impl IntoIterator for &S { - | - you could add a lifetime on the impl block, if the trait or the self type can have one LL | type Item = &T; | ^ this lifetime must come from the implemented type + | +help: add a lifetime to the impl block and use it in the self type and associated type + | +LL ~ impl<'a> IntoIterator for &'a S { +LL ~ type Item = &'a T; + | error[E0261]: use of undeclared lifetime name `'a` --> $DIR/missing-lifetime-in-assoc-type-2.rs:7:57 diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.stderr b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.stderr index 408d5bb40664d..a71042fa9872e 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.stderr +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.stderr @@ -1,10 +1,14 @@ error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type --> $DIR/missing-lifetime-in-assoc-type-3.rs:5:17 | -LL | impl IntoIterator for &S { - | - you could add a lifetime on the impl block, if the trait or the self type can have one LL | type Item = &T; | ^ this lifetime must come from the implemented type + | +help: add a lifetime to the impl block and use it in the self type and associated type + | +LL ~ impl<'a> IntoIterator for &'a S { +LL ~ type Item = &'a T; + | error[E0106]: missing lifetime specifier --> $DIR/missing-lifetime-in-assoc-type-3.rs:7:56 diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.stderr b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.stderr index f07b5cdd65ca6..8481b60f845a1 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.stderr +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.stderr @@ -1,10 +1,14 @@ error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type --> $DIR/missing-lifetime-in-assoc-type-4.rs:5:17 | -LL | impl IntoIterator for &S { - | - you could add a lifetime on the impl block, if the trait or the self type can have one LL | type Item = &T; | ^ this lifetime must come from the implemented type + | +help: add a lifetime to the impl block and use it in the self type and associated type + | +LL ~ impl<'a> IntoIterator for &'a S { +LL ~ type Item = &'a T; + | error[E0195]: lifetime parameters or bounds on associated type `IntoIter` do not match the trait declaration --> $DIR/missing-lifetime-in-assoc-type-4.rs:7:18 diff --git a/tests/ui/lifetimes/no_lending_iterators.stderr b/tests/ui/lifetimes/no_lending_iterators.stderr index cadba149c234d..0f18f858cb8ff 100644 --- a/tests/ui/lifetimes/no_lending_iterators.stderr +++ b/tests/ui/lifetimes/no_lending_iterators.stderr @@ -14,7 +14,7 @@ error: in the trait associated type is declared without lifetime parameters, so --> $DIR/no_lending_iterators.rs:18:17 | LL | impl Bar for usize { - | - you could add a lifetime on the impl block, if the trait or the self type can have one + | - you could add a lifetime on the impl block, if the trait or the self type could have one LL | type Item = &usize; | ^ this lifetime must come from the implemented type From e4c1caaef96511830a2a8d0aa9182dfe29427860 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 17 Jan 2025 01:05:15 +0000 Subject: [PATCH 7/8] Tweak wording in associated type with anon lifetime error Move the previous long message to a note and use a shorter primary message: ``` error: missing lifetime in associated type --> $DIR/missing-lifetime-in-assoc-type-1.rs:9:17 | LL | impl<'a> IntoIterator for &S { | ---- there is a named lifetime specified on the impl block you could use ... LL | type Item = &T; | ^ this lifetime must come from the implemented type | note: in the trait the associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL help: consider using the lifetime from the impl block | LL | type Item = &'a T; | ++ ``` --- compiler/rustc_resolve/messages.ftl | 4 +- compiler/rustc_resolve/src/errors.rs | 2 + compiler/rustc_resolve/src/late.rs | 38 ++++++++++++++++--- .../assoc-type.rs | 6 +-- .../assoc-type.stderr | 9 +++-- .../missing-lifetime-in-assoc-type-1.rs | 3 +- .../missing-lifetime-in-assoc-type-1.stderr | 4 +- .../missing-lifetime-in-assoc-type-2.rs | 2 +- .../missing-lifetime-in-assoc-type-2.stderr | 4 +- .../missing-lifetime-in-assoc-type-3.rs | 2 +- .../missing-lifetime-in-assoc-type-3.stderr | 4 +- .../missing-lifetime-in-assoc-type-4.rs | 2 +- .../missing-lifetime-in-assoc-type-4.stderr | 4 +- .../missing-lifetime-in-assoc-type-5.rs | 3 +- .../missing-lifetime-in-assoc-type-5.stderr | 4 +- .../missing-lifetime-in-assoc-type-6.rs | 26 +++++++++++++ .../missing-lifetime-in-assoc-type-6.stderr | 30 +++++++++++++++ tests/ui/lifetimes/no_lending_iterators.rs | 2 +- .../ui/lifetimes/no_lending_iterators.stderr | 4 +- 19 files changed, 128 insertions(+), 25 deletions(-) create mode 100644 tests/ui/lifetimes/missing-lifetime-in-assoc-type-6.rs create mode 100644 tests/ui/lifetimes/missing-lifetime-in-assoc-type-6.stderr diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index ceef558c0cf95..76ab835e56804 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -11,9 +11,9 @@ resolve_added_macro_use = resolve_ancestor_only = visibilities can only be restricted to ancestor modules -resolve_anonymous_lifetime_non_gat_report_error = - in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type +resolve_anonymous_lifetime_non_gat_report_error = missing lifetime in associated type .label = this lifetime must come from the implemented type + .note = in the trait the associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type resolve_arguments_macro_use_not_allowed = arguments to `macro_use` are not allowed here diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 2747ba135ed0d..238325ed240d1 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -897,6 +897,8 @@ pub(crate) struct AnonymousLifetimeNonGatReportError { #[primary_span] #[label] pub(crate) lifetime: Span, + #[note] + pub(crate) decl: MultiSpan, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index fa07f35166538..67d698db57c86 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -21,21 +21,21 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagArgValue, ErrorGuaranteed, IntoDiagArg, StashKey, Suggestions, - pluralize, + Applicability, Diag, DiagArgValue, ErrorGuaranteed, IntoDiagArg, MultiSpan, StashKey, + Suggestions, pluralize, }; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::{MissingLifetimeKind, PrimTy, TraitCandidate}; use rustc_middle::middle::resolve_bound_vars::Set1; -use rustc_middle::ty::{DelegationFnSig, Visibility}; +use rustc_middle::ty::{AssocTag, DelegationFnSig, Visibility}; use rustc_middle::{bug, span_bug}; use rustc_session::config::{CrateType, ResolveDocLinks}; use rustc_session::lint::{self, BuiltinLintDiag}; use rustc_session::parse::feature_err; use rustc_span::source_map::{Spanned, respan}; -use rustc_span::{BytePos, Ident, Span, Symbol, SyntaxContext, kw, sym}; +use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, SyntaxContext, kw, sym}; use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; use tracing::{debug, instrument, trace}; @@ -725,6 +725,9 @@ struct DiagMetadata<'ast> { /// The current impl items (used to suggest). current_impl_items: Option<&'ast [Box]>, + /// The current impl items (used to suggest). + current_impl_item: Option<&'ast AssocItem>, + /// When processing impl trait currently_processing_impl_trait: Option<(TraitRef, Ty)>, @@ -1891,9 +1894,31 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ty: ty.span, }); } else { + let decl = if !trait_id.is_local() + && let Some(assoc) = self.diag_metadata.current_impl_item + && let AssocItemKind::Type(_) = assoc.kind + && let assocs = self.r.tcx.associated_items(trait_id) + && let Some(ident) = assoc.kind.ident() + && let Some(assoc) = assocs.find_by_ident_and_kind( + self.r.tcx, + ident, + AssocTag::Type, + trait_id, + ) { + let mut decl: MultiSpan = + self.r.tcx.def_span(assoc.def_id).into(); + decl.push_span_label( + self.r.tcx.def_span(trait_id), + String::new(), + ); + decl + } else { + DUMMY_SP.into() + }; let mut err = self.r.dcx().create_err( errors::AnonymousLifetimeNonGatReportError { lifetime: lifetime.ident.span, + decl, }, ); self.point_at_impl_lifetimes(&mut err, i, lifetime.ident.span); @@ -2006,7 +2031,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } else if let Some(item) = &self.diag_metadata.current_item && let ItemKind::Impl(impl_) = &item.kind && let Some(of_trait) = &impl_.of_trait - && let ControlFlow::Break(sp) = AnonRefFinder.visit_trait_ref(of_trait) + && let ControlFlow::Break(sp) = AnonRefFinder.visit_trait_ref(&of_trait.trait_ref) { err.multipart_suggestion_verbose( "add a lifetime to the impl block and use it in the trait and associated type", @@ -3362,6 +3387,8 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ) { use crate::ResolutionError::*; self.resolve_doc_links(&item.attrs, MaybeExported::ImplItem(trait_id.ok_or(&item.vis))); + let prev = self.diag_metadata.current_impl_item.take(); + self.diag_metadata.current_impl_item = Some(&item); match &item.kind { AssocItemKind::Const(box ast::ConstItem { ident, @@ -3510,6 +3537,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { panic!("unexpanded macro in resolve!") } } + self.diag_metadata.current_impl_item = prev; } fn check_trait_item( diff --git a/tests/ui/impl-header-lifetime-elision/assoc-type.rs b/tests/ui/impl-header-lifetime-elision/assoc-type.rs index e999bd02db26e..f03a110d7dc1d 100644 --- a/tests/ui/impl-header-lifetime-elision/assoc-type.rs +++ b/tests/ui/impl-header-lifetime-elision/assoc-type.rs @@ -9,7 +9,7 @@ trait MyTrait { impl MyTrait for &i32 { type Output = &i32; - //~^ ERROR in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + //~^ ERROR missing lifetime in associated type } impl MyTrait for &u32 { @@ -19,7 +19,7 @@ impl MyTrait for &u32 { impl<'a> MyTrait for &f64 { type Output = &f64; - //~^ ERROR in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + //~^ ERROR missing lifetime in associated type } trait OtherTrait<'a> { @@ -27,7 +27,7 @@ trait OtherTrait<'a> { } impl OtherTrait<'_> for f64 { type Output = &f64; - //~^ ERROR in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + //~^ ERROR missing lifetime in associated type } // This is what you have to do: diff --git a/tests/ui/impl-header-lifetime-elision/assoc-type.stderr b/tests/ui/impl-header-lifetime-elision/assoc-type.stderr index 933ed3efec5d6..201ea2d894eb7 100644 --- a/tests/ui/impl-header-lifetime-elision/assoc-type.stderr +++ b/tests/ui/impl-header-lifetime-elision/assoc-type.stderr @@ -1,9 +1,10 @@ -error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type +error: missing lifetime in associated type --> $DIR/assoc-type.rs:11:19 | LL | type Output = &i32; | ^ this lifetime must come from the implemented type | + = note: in the trait the associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type help: add a lifetime to the impl block and use it in the self type and associated type | LL ~ impl<'a> MyTrait for &'a i32 { @@ -16,7 +17,7 @@ error[E0637]: `'_` cannot be used here LL | type Output = &'_ i32; | ^^ `'_` is a reserved lifetime name -error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type +error: missing lifetime in associated type --> $DIR/assoc-type.rs:21:19 | LL | impl<'a> MyTrait for &f64 { @@ -24,17 +25,19 @@ LL | impl<'a> MyTrait for &f64 { LL | type Output = &f64; | ^ this lifetime must come from the implemented type | + = note: in the trait the associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type help: consider using the lifetime from the impl block | LL | type Output = &'a f64; | ++ -error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type +error: missing lifetime in associated type --> $DIR/assoc-type.rs:29:19 | LL | type Output = &f64; | ^ this lifetime must come from the implemented type | + = note: in the trait the associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type help: add a lifetime to the impl block and use it in the trait and associated type | LL ~ impl<'a> OtherTrait<'a> for f64 { diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.rs b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.rs index 1ae381ef7bc02..0f220a0b62a16 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.rs +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.rs @@ -7,9 +7,10 @@ impl<'a> IntoIterator for &S { //~| NOTE unconstrained lifetime parameter //~| HELP consider using the named lifetime here instead of an implict lifetime type Item = &T; - //~^ ERROR in the trait associated type + //~^ ERROR missing lifetime in associated type //~| HELP consider using the lifetime from the impl block //~| NOTE this lifetime must come from the implemented type + //~| NOTE in the trait the associated type is declared without lifetime parameters type IntoIter = std::collections::btree_map::Values<'a, i32, T>; fn into_iter(self) -> Self::IntoIter { diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.stderr b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.stderr index bf26ce4a63027..b4305098b01f7 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.stderr +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.stderr @@ -1,4 +1,4 @@ -error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type +error: missing lifetime in associated type --> $DIR/missing-lifetime-in-assoc-type-1.rs:9:17 | LL | impl<'a> IntoIterator for &S { @@ -7,6 +7,8 @@ LL | impl<'a> IntoIterator for &S { LL | type Item = &T; | ^ this lifetime must come from the implemented type | +note: in the trait the associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL help: consider using the lifetime from the impl block | LL | type Item = &'a T; diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.rs b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.rs index dd720f075ac46..d24aaaf8b10ed 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.rs +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.rs @@ -3,7 +3,7 @@ struct T; impl IntoIterator for &S { type Item = &T; - //~^ ERROR in the trait associated type + //~^ ERROR missing lifetime in associated type type IntoIter = std::collections::btree_map::Values<'a, i32, T>; //~^ ERROR use of undeclared lifetime name `'a` diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.stderr b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.stderr index cd6fa2894ad28..9d9d2bc97d901 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.stderr +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.stderr @@ -1,9 +1,11 @@ -error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type +error: missing lifetime in associated type --> $DIR/missing-lifetime-in-assoc-type-2.rs:5:17 | LL | type Item = &T; | ^ this lifetime must come from the implemented type | +note: in the trait the associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL help: add a lifetime to the impl block and use it in the self type and associated type | LL ~ impl<'a> IntoIterator for &'a S { diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.rs b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.rs index 60d1f0f8fe571..cf745ab97eb3a 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.rs +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.rs @@ -3,7 +3,7 @@ struct T; impl IntoIterator for &S { type Item = &T; - //~^ ERROR in the trait associated type + //~^ ERROR missing lifetime in associated type type IntoIter = std::collections::btree_map::Values; //~^ ERROR missing lifetime specifier diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.stderr b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.stderr index a71042fa9872e..b5811dc8ff279 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.stderr +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.stderr @@ -1,9 +1,11 @@ -error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type +error: missing lifetime in associated type --> $DIR/missing-lifetime-in-assoc-type-3.rs:5:17 | LL | type Item = &T; | ^ this lifetime must come from the implemented type | +note: in the trait the associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL help: add a lifetime to the impl block and use it in the self type and associated type | LL ~ impl<'a> IntoIterator for &'a S { diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.rs b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.rs index 0c99e8874c354..138f6d7bdf2f7 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.rs +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.rs @@ -3,7 +3,7 @@ struct T; impl IntoIterator for &S { type Item = &T; - //~^ ERROR in the trait associated type + //~^ ERROR missing lifetime in associated type type IntoIter<'a> = std::collections::btree_map::Values<'a, i32, T>; //~^ ERROR lifetime parameters or bounds on associated type `IntoIter` do not match the trait declaration diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.stderr b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.stderr index 8481b60f845a1..ccc0d7ebae9f3 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.stderr +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.stderr @@ -1,9 +1,11 @@ -error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type +error: missing lifetime in associated type --> $DIR/missing-lifetime-in-assoc-type-4.rs:5:17 | LL | type Item = &T; | ^ this lifetime must come from the implemented type | +note: in the trait the associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL help: add a lifetime to the impl block and use it in the self type and associated type | LL ~ impl<'a> IntoIterator for &'a S { diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-5.rs b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-5.rs index ff64d6b900949..9e629a48de7b4 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-5.rs +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-5.rs @@ -7,9 +7,10 @@ impl<'a> IntoIterator for &'_ S { //~| NOTE unconstrained lifetime parameter //~| HELP consider using the named lifetime here instead of an implict lifetime type Item = &T; - //~^ ERROR in the trait associated type + //~^ ERROR missing lifetime in associated type //~| HELP consider using the lifetime from the impl block //~| NOTE this lifetime must come from the implemented type + //~| NOTE in the trait the associated type is declared without lifetime parameters type IntoIter = std::collections::btree_map::Values<'a, i32, T>; fn into_iter(self) -> Self::IntoIter { diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-5.stderr b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-5.stderr index 9c960c67e2502..f845596834b8c 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-5.stderr +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-5.stderr @@ -1,4 +1,4 @@ -error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type +error: missing lifetime in associated type --> $DIR/missing-lifetime-in-assoc-type-5.rs:9:17 | LL | impl<'a> IntoIterator for &'_ S { @@ -7,6 +7,8 @@ LL | impl<'a> IntoIterator for &'_ S { LL | type Item = &T; | ^ this lifetime must come from the implemented type | +note: in the trait the associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL help: consider using the lifetime from the impl block | LL | type Item = &'a T; diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-6.rs b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-6.rs new file mode 100644 index 0000000000000..036596c2aec62 --- /dev/null +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-6.rs @@ -0,0 +1,26 @@ +//~ NOTE in the trait the associated type is declared without lifetime parameters +struct S; +struct T; + +trait Trait { + type Item; + type IntoIter; + fn into_iter(self) -> Self::IntoIter; +} + +impl<'a> Trait for &'_ S { + //~^ ERROR E0207 + //~| NOTE there is a named lifetime specified on the impl block you could use + //~| NOTE unconstrained lifetime parameter + //~| HELP consider using the named lifetime here instead of an implict lifetime + type Item = &T; + //~^ ERROR missing lifetime in associated type + //~| HELP consider using the lifetime from the impl block + //~| NOTE this lifetime must come from the implemented type + type IntoIter = std::collections::btree_map::Values<'a, i32, T>; + + fn into_iter(self) -> Self::IntoIter { + todo!() + } +} +fn main() {} diff --git a/tests/ui/lifetimes/missing-lifetime-in-assoc-type-6.stderr b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-6.stderr new file mode 100644 index 0000000000000..2e81d43674613 --- /dev/null +++ b/tests/ui/lifetimes/missing-lifetime-in-assoc-type-6.stderr @@ -0,0 +1,30 @@ +error: missing lifetime in associated type + --> $DIR/missing-lifetime-in-assoc-type-6.rs:16:17 + | +LL | impl<'a> Trait for &'_ S { + | ---- there is a named lifetime specified on the impl block you could use +... +LL | type Item = &T; + | ^ this lifetime must come from the implemented type + | + = note: in the trait the associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type +help: consider using the lifetime from the impl block + | +LL | type Item = &'a T; + | ++ + +error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates + --> $DIR/missing-lifetime-in-assoc-type-6.rs:11:6 + | +LL | impl<'a> Trait for &'_ S { + | ^^ unconstrained lifetime parameter + | +help: consider using the named lifetime here instead of an implict lifetime + | +LL - impl<'a> Trait for &'_ S { +LL + impl<'a> Trait for &'a S { + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/lifetimes/no_lending_iterators.rs b/tests/ui/lifetimes/no_lending_iterators.rs index 88b8cda0898be..aa2e57ee30364 100644 --- a/tests/ui/lifetimes/no_lending_iterators.rs +++ b/tests/ui/lifetimes/no_lending_iterators.rs @@ -16,7 +16,7 @@ trait Bar { impl Bar for usize { type Item = &usize; - //~^ ERROR in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + //~^ ERROR missing lifetime in associated type fn poke(&mut self, item: Self::Item) { self += *item; diff --git a/tests/ui/lifetimes/no_lending_iterators.stderr b/tests/ui/lifetimes/no_lending_iterators.stderr index 0f18f858cb8ff..ef90c286fc755 100644 --- a/tests/ui/lifetimes/no_lending_iterators.stderr +++ b/tests/ui/lifetimes/no_lending_iterators.stderr @@ -10,13 +10,15 @@ note: you can't create an `Iterator` that borrows each `Item` from itself, but y LL | impl Iterator for Data { | ^^^^ -error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type +error: missing lifetime in associated type --> $DIR/no_lending_iterators.rs:18:17 | LL | impl Bar for usize { | - you could add a lifetime on the impl block, if the trait or the self type could have one LL | type Item = &usize; | ^ this lifetime must come from the implemented type + | + = note: in the trait the associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type error[E0195]: lifetime parameters or bounds on associated type `Item` do not match the trait declaration --> $DIR/no_lending_iterators.rs:27:14 From 648093d12b2afc444f7dbf591c3a2bb592bdf66d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 12 Aug 2025 17:58:52 +0000 Subject: [PATCH 8/8] review comments --- compiler/rustc_resolve/src/late.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 67d698db57c86..bac4762a70bfa 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -374,11 +374,14 @@ enum LifetimeBinderKind { FnPtrType, PolyTrait, WhereBound, + // Item covers foreign items, ADTs, type aliases, trait associated items and + // trait alias associated items. Item, ConstItem, Function, Closure, ImplBlock, + // Covers only `impl` associated types. ImplAssocType, } @@ -1963,14 +1966,12 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { let Some((rib, span)) = self.lifetime_ribs[..i] .iter() .rev() - .skip(1) - .filter_map(|rib| match rib.kind { + .find_map(|rib| match rib.kind { LifetimeRibKind::Generics { span, kind: LifetimeBinderKind::ImplBlock, .. } => { Some((rib, span)) } _ => None, }) - .next() else { return; };