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
18 changes: 18 additions & 0 deletions tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
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
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() {}
23 changes: 23 additions & 0 deletions tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
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[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`.
14 changes: 14 additions & 0 deletions tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.rs
Original file line number Diff line number Diff line change
@@ -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() {}
26 changes: 26 additions & 0 deletions tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
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

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`.
14 changes: 14 additions & 0 deletions tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.rs
Original file line number Diff line number Diff line change
@@ -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<i32, T>;
//~^ ERROR missing lifetime specifier

fn into_iter(self) -> Self::IntoIter {
todo!()
}
}
fn main() {}
22 changes: 22 additions & 0 deletions tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
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

error[E0106]: missing lifetime specifier
--> $DIR/missing-lifetime-in-assoc-type-3.rs:7:56
|
LL | type IntoIter = std::collections::btree_map::Values<i32, T>;
| ^ 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`.
14 changes: 14 additions & 0 deletions tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.rs
Original file line number Diff line number Diff line change
@@ -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() {}
17 changes: 17 additions & 0 deletions tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
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
--> $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`.
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