From 5c7a657e997b7bef2a26db40372d58afa0bf74f7 Mon Sep 17 00:00:00 2001 From: qaijuang <237468078+qaijuang@users.noreply.github.com> Date: Tue, 19 May 2026 05:04:19 -0400 Subject: [PATCH 1/5] add red test --- tests/ui/error-codes/E0637.rs | 5 +++++ tests/ui/error-codes/E0637.stderr | 13 ++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/ui/error-codes/E0637.rs b/tests/ui/error-codes/E0637.rs index 382ce3ed01f34..323e6b048e96c 100644 --- a/tests/ui/error-codes/E0637.rs +++ b/tests/ui/error-codes/E0637.rs @@ -14,4 +14,9 @@ where { } +// Regression test for https://github.com/rust-lang/rust/issues/156456 and +// https://github.com/rust-lang/rust/issues/122025. +fn associated_type_binding>() {} +//~^ ERROR: `&` without an explicit lifetime name cannot be used here [E0637] + fn main() {} diff --git a/tests/ui/error-codes/E0637.stderr b/tests/ui/error-codes/E0637.stderr index 88c08cb94ba8d..3bb69de5d9190 100644 --- a/tests/ui/error-codes/E0637.stderr +++ b/tests/ui/error-codes/E0637.stderr @@ -30,7 +30,18 @@ help: consider introducing a higher-ranked lifetime here LL | T: for<'a> Into<&'a u32>, | +++++++ ++ -error: aborting due to 3 previous errors +error[E0637]: `&` without an explicit lifetime name cannot be used here + --> $DIR/E0637.rs:19:51 + | +LL | fn associated_type_binding>() {} + | ^ explicit lifetime name needed here + | +help: consider introducing a higher-ranked lifetime here + | +LL | fn associated_type_binding IntoIterator>() {} + | +++++++ ++ + +error: aborting due to 4 previous errors Some errors have detailed explanations: E0106, E0637. For more information about an error, try `rustc --explain E0106`. From cfbd3b1b136e507080ce75e03879d8d4ffb953c1 Mon Sep 17 00:00:00 2001 From: qaijuang <237468078+qaijuang@users.noreply.github.com> Date: Tue, 19 May 2026 08:53:51 -0400 Subject: [PATCH 2/5] allow filtering lifetime introduction suggestions --- .../rustc_resolve/src/late/diagnostics.rs | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 8994a7713c858..95fdf8124a225 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -3762,6 +3762,50 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { String, Vec<(Span, String)>, ) -> bool, + ) { + self.suggest_introducing_lifetime_filtered(err, name, |_| true, suggest); + } + + pub(crate) fn suggest_introducing_lifetime_for_assoc_ty_binding( + &self, + err: &mut Diag<'_>, + lifetime: Span, + ) { + self.suggest_introducing_lifetime_filtered( + err, + None, + |kind| { + !matches!( + kind, + LifetimeBinderKind::FnPtrType + | LifetimeBinderKind::PolyTrait + | LifetimeBinderKind::WhereBound + ) + }, + |err, _higher_ranked, span, message, intro_sugg, _| { + err.multipart_suggestion( + message, + vec![(span, intro_sugg), (lifetime.shrink_to_hi(), "'a ".to_string())], + Applicability::MaybeIncorrect, + ); + false + }, + ); + } + + fn suggest_introducing_lifetime_filtered( + &self, + err: &mut Diag<'_>, + name: Option, + mut consider: impl FnMut(LifetimeBinderKind) -> bool, + suggest: impl Fn( + &mut Diag<'_>, + bool, + Span, + Cow<'static, str>, + String, + Vec<(Span, String)>, + ) -> bool, ) { let mut suggest_note = true; for rib in self.lifetime_ribs.iter().rev() { @@ -3775,7 +3819,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { { continue; } - if let LifetimeBinderKind::ImplAssocType = kind { + if matches!(kind, LifetimeBinderKind::ImplAssocType) || !consider(kind) { continue; } From d1bc1b4631fdc9fc9e05e488dcf85bd5281c1ee1 Mon Sep 17 00:00:00 2001 From: qaijuang <237468078+qaijuang@users.noreply.github.com> Date: Tue, 19 May 2026 08:56:53 -0400 Subject: [PATCH 3/5] suggest named lifetimes in assoc type bindings --- compiler/rustc_resolve/src/late.rs | 57 +++++++++++++++++++++--------- tests/ui/error-codes/E0637.stderr | 6 ++-- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 5ae2aaadffae7..48b318535ca0a 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -768,6 +768,9 @@ pub(crate) struct DiagMetadata<'ast> { /// Given `where ::Baz: String`, suggest `where T: Bar`. current_where_predicate: Option<&'ast WherePredicate>, + /// Whether we are visiting an associated type equality binding like `Trait`. + in_assoc_ty_binding: bool, + current_type_path: Option<&'ast Ty>, /// The current impl items (used to suggest). @@ -1327,7 +1330,11 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc } match constraint.kind { AssocItemConstraintKind::Equality { ref term } => match term { - Term::Ty(ty) => self.visit_ty(ty), + Term::Ty(ty) => { + let prev = replace(&mut self.diag_metadata.in_assoc_ty_binding, true); + self.visit_ty(ty); + self.diag_metadata.in_assoc_ty_binding = prev; + } Term::Const(c) => { self.resolve_anon_const(c, AnonConstKind::ConstArg(IsRepeatExpr::No)) } @@ -1927,21 +1934,27 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } LifetimeRibKind::AnonymousReportError => { let guar = if elided { - let suggestion = self.lifetime_ribs[i..].iter().rev().find_map(|rib| { - if let LifetimeRibKind::Generics { - span, - kind: LifetimeBinderKind::PolyTrait | LifetimeBinderKind::WhereBound, - .. - } = rib.kind - { - Some(crate::diagnostics::ElidedAnonymousLifetimeReportErrorSuggestion { - lo: span.shrink_to_lo(), - hi: lifetime.ident.span.shrink_to_hi(), - }) - } else { - None - } - }); + let suggestion = if self.diag_metadata.in_assoc_ty_binding { + None + } else { + self.lifetime_ribs[i..].iter().rev().find_map(|rib| { + if let LifetimeRibKind::Generics { + span, + kind: + LifetimeBinderKind::PolyTrait + | LifetimeBinderKind::WhereBound, + .. + } = rib.kind + { + Some(crate::diagnostics::ElidedAnonymousLifetimeReportErrorSuggestion { + lo: span.shrink_to_lo(), + hi: lifetime.ident.span.shrink_to_hi(), + }) + } else { + None + } + }) + }; // are we trying to use an anonymous lifetime // on a non GAT associated trait type? if !self.in_func_body @@ -1993,6 +2006,18 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.point_at_impl_lifetimes(&mut err, i, lifetime.ident.span); err.emit() } + } else if self.diag_metadata.in_assoc_ty_binding { + let mut err = self.r.dcx().create_err( + crate::diagnostics::ElidedAnonymousLifetimeReportError { + span: lifetime.ident.span, + suggestion, + }, + ); + self.suggest_introducing_lifetime_for_assoc_ty_binding( + &mut err, + lifetime.ident.span, + ); + err.emit() } else { self.r.dcx().emit_err( crate::diagnostics::ElidedAnonymousLifetimeReportError { diff --git a/tests/ui/error-codes/E0637.stderr b/tests/ui/error-codes/E0637.stderr index 3bb69de5d9190..4b6ed9ad34491 100644 --- a/tests/ui/error-codes/E0637.stderr +++ b/tests/ui/error-codes/E0637.stderr @@ -36,10 +36,10 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here LL | fn associated_type_binding>() {} | ^ explicit lifetime name needed here | -help: consider introducing a higher-ranked lifetime here +help: consider introducing a named lifetime parameter | -LL | fn associated_type_binding IntoIterator>() {} - | +++++++ ++ +LL | fn associated_type_binding<'a, I: IntoIterator>() {} + | +++ ++ error: aborting due to 4 previous errors From 98c932aba72ca3e6c0d3ca058ebe43d5a855a49f Mon Sep 17 00:00:00 2001 From: qaijuang <237468078+qaijuang@users.noreply.github.com> Date: Tue, 19 May 2026 09:09:42 -0400 Subject: [PATCH 4/5] add missing test --- tests/ui/error-codes/E0637.rs | 11 +++++++++-- tests/ui/error-codes/E0637.stderr | 15 +++++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/tests/ui/error-codes/E0637.rs b/tests/ui/error-codes/E0637.rs index 323e6b048e96c..17275b145b21b 100644 --- a/tests/ui/error-codes/E0637.rs +++ b/tests/ui/error-codes/E0637.rs @@ -14,9 +14,16 @@ where { } -// Regression test for https://github.com/rust-lang/rust/issues/156456 and -// https://github.com/rust-lang/rust/issues/122025. +// Regression test for https://github.com/rust-lang/rust/issues/156456. fn associated_type_binding>() {} //~^ ERROR: `&` without an explicit lifetime name cannot be used here [E0637] +trait T { + type Assoc; +} + +// Regression test for https://github.com/rust-lang/rust/issues/122025. +fn foo(t: F) where F: T {} +//~^ ERROR: `&` without an explicit lifetime name cannot be used here [E0637] + fn main() {} diff --git a/tests/ui/error-codes/E0637.stderr b/tests/ui/error-codes/E0637.stderr index 4b6ed9ad34491..d7e718a25e5c8 100644 --- a/tests/ui/error-codes/E0637.stderr +++ b/tests/ui/error-codes/E0637.stderr @@ -31,7 +31,7 @@ LL | T: for<'a> Into<&'a u32>, | +++++++ ++ error[E0637]: `&` without an explicit lifetime name cannot be used here - --> $DIR/E0637.rs:19:51 + --> $DIR/E0637.rs:18:51 | LL | fn associated_type_binding>() {} | ^ explicit lifetime name needed here @@ -41,7 +41,18 @@ help: consider introducing a named lifetime parameter LL | fn associated_type_binding<'a, I: IntoIterator>() {} | +++ ++ -error: aborting due to 4 previous errors +error[E0637]: `&` without an explicit lifetime name cannot be used here + --> $DIR/E0637.rs:26:34 + | +LL | fn foo(t: F) where F: T {} + | ^ explicit lifetime name needed here + | +help: consider introducing a named lifetime parameter + | +LL | fn foo<'a, F>(t: F) where F: T {} + | +++ ++ + +error: aborting due to 5 previous errors Some errors have detailed explanations: E0106, E0637. For more information about an error, try `rustc --explain E0106`. From f2dbc3d26166b0e75abb01ed35fa0c79835758af Mon Sep 17 00:00:00 2001 From: qaijuang <237468078+qaijuang@users.noreply.github.com> Date: Tue, 2 Jun 2026 16:49:45 -0400 Subject: [PATCH 5/5] address suggested nits --- compiler/rustc_resolve/src/late.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 48b318535ca0a..bf53b891a08f1 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1935,9 +1935,17 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { LifetimeRibKind::AnonymousReportError => { let guar = if elided { let suggestion = if self.diag_metadata.in_assoc_ty_binding { + // In an associated type binding like `I: IntoIterator`, + // introducing the lifetime on the trait ref would produce + // `I: for<'a> IntoIterator`. Prefer a named lifetime + // from an enclosing item instead, so the assoc-ty-binding-specific path + // below builds that suggestion. None } else { self.lifetime_ribs[i..].iter().rev().find_map(|rib| { + // Look for a `Generics` rib that represents a trait or where-bound + // binder (`T: Trait<&U>` or `where T: Trait<&U>`), since that is + // where the generic E0637 diagnostic can insert `for<'a>`. if let LifetimeRibKind::Generics { span, kind: @@ -2007,6 +2015,10 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { err.emit() } } else if self.diag_metadata.in_assoc_ty_binding { + // For associated type bindings, e.g. + // `fn f>()`, introduce a named lifetime + // on an enclosing generics binder instead: + // `fn f<'a, I: IntoIterator>()`. let mut err = self.r.dcx().create_err( crate::diagnostics::ElidedAnonymousLifetimeReportError { span: lifetime.ident.span,