Skip to content

Tweak output of missing lifetime on associated type #135602

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
54 changes: 50 additions & 4 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ use rustc_ast::*;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
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};
Expand Down Expand Up @@ -1870,9 +1871,13 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
ty: ty.span,
});
} else {
self.r.dcx().emit_err(errors::AnonymousLivetimeNonGatReportError {
lifetime: lifetime.ident.span,
});
let mut err = self.r.dcx().create_err(
errors::AnonymousLivetimeNonGatReportError {
lifetime: lifetime.ident.span,
},
);
self.point_at_impl_lifetimes(&mut err, i, lifetime.ident.span);
err.emit();
}
} else {
self.r.dcx().emit_err(errors::ElidedAnonymousLivetimeReportError {
Expand Down Expand Up @@ -1909,6 +1914,47 @@ impl<'a, 'ast, 'ra: 'ast, '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)
Copy link
Member

@Nadrieril Nadrieril Mar 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the skip? Could you add a comment explaining it?

.filter_map(|rib| match rib.kind {
LifetimeRibKind::Generics { span, kind: LifetimeBinderKind::ImplBlock, .. } => {
Some((rib, span))
}
_ => None,
})
.next()
Comment on lines +1949 to +1955
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
.filter_map(|rib| match rib.kind {
LifetimeRibKind::Generics { span, kind: LifetimeBinderKind::ImplBlock, .. } => {
Some((rib, span))
}
_ => None,
})
.next()
.find_map(|rib| match rib.kind {
LifetimeRibKind::Generics { span, kind: LifetimeBinderKind::ImplBlock, .. } => {
Some((rib, span))
}
_ => None,
})

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();
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/impl-header-lifetime-elision/assoc-type.stderr
Original file line number Diff line number Diff line change
@@ -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

Expand Down
2 changes: 2 additions & 0 deletions tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>;

Expand Down
10 changes: 9 additions & 1 deletion tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.stderr
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.stderr
Original file line number Diff line number Diff line change
@@ -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

Expand Down
2 changes: 2 additions & 0 deletions tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.stderr
Original file line number Diff line number Diff line change
@@ -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

Expand Down
2 changes: 2 additions & 0 deletions tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.stderr
Original file line number Diff line number Diff line change
@@ -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-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

Expand Down
2 changes: 2 additions & 0 deletions tests/ui/lifetimes/no_lending_iterators.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down