Skip to content

Commit a6cb0b5

Browse files
committed
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 { | ++ ```
1 parent b4507bf commit a6cb0b5

5 files changed

+77
-2
lines changed

compiler/rustc_hir_analysis/src/impl_wf_check.rs

+23-1
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@ use std::assert_matches::debug_assert_matches;
1212

1313
use min_specialization::check_min_specialization;
1414
use rustc_data_structures::fx::FxHashSet;
15+
use rustc_errors::Applicability;
1516
use rustc_errors::codes::*;
1617
use rustc_hir::def::DefKind;
1718
use rustc_hir::def_id::LocalDefId;
1819
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
19-
use rustc_span::ErrorGuaranteed;
20+
use rustc_span::{ErrorGuaranteed, kw};
2021

2122
use crate::constrained_generic_params as cgp;
2223
use crate::errors::UnconstrainedGenericParameter;
@@ -158,6 +159,27 @@ pub(crate) fn enforce_impl_lifetime_params_are_constrained(
158159
const_param_note2: false,
159160
});
160161
diag.code(E0207);
162+
for p in &impl_generics.own_params {
163+
if p.name == kw::UnderscoreLifetime {
164+
let span = tcx.def_span(p.def_id);
165+
let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) else {
166+
continue;
167+
};
168+
169+
let (span, sugg) = if &snippet == "'_" {
170+
(span, param.name.to_string())
171+
} else {
172+
(span.shrink_to_hi(), format!("{} ", param.name))
173+
};
174+
diag.span_suggestion_verbose(
175+
span,
176+
"consider using the named lifetime here instead of an implict \
177+
lifetime",
178+
sugg,
179+
Applicability::MaybeIncorrect,
180+
);
181+
}
182+
}
161183
res = Err(diag.emit());
162184
}
163185
}

tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.rs

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ impl<'a> IntoIterator for &S {
55
//~^ ERROR E0207
66
//~| NOTE there is a named lifetime specified on the impl block you could use
77
//~| NOTE unconstrained lifetime parameter
8+
//~| HELP consider using the named lifetime here instead of an implict lifetime
89
type Item = &T;
910
//~^ ERROR in the trait associated type
1011
//~| HELP consider using the lifetime from the impl block

tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.stderr

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
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
2-
--> $DIR/missing-lifetime-in-assoc-type-1.rs:8:17
2+
--> $DIR/missing-lifetime-in-assoc-type-1.rs:9:17
33
|
44
LL | impl<'a> IntoIterator for &S {
55
| ---- 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,
1717
|
1818
LL | impl<'a> IntoIterator for &S {
1919
| ^^ unconstrained lifetime parameter
20+
|
21+
help: consider using the named lifetime here instead of an implict lifetime
22+
|
23+
LL | impl<'a> IntoIterator for &'a S {
24+
| ++
2025

2126
error: aborting due to 2 previous errors
2227

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
struct S;
2+
struct T;
3+
4+
impl<'a> IntoIterator for &'_ S {
5+
//~^ ERROR E0207
6+
//~| NOTE there is a named lifetime specified on the impl block you could use
7+
//~| NOTE unconstrained lifetime parameter
8+
//~| HELP consider using the named lifetime here instead of an implict lifetime
9+
type Item = &T;
10+
//~^ ERROR in the trait associated type
11+
//~| HELP consider using the lifetime from the impl block
12+
//~| NOTE this lifetime must come from the implemented type
13+
type IntoIter = std::collections::btree_map::Values<'a, i32, T>;
14+
15+
fn into_iter(self) -> Self::IntoIter {
16+
todo!()
17+
}
18+
}
19+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
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
2+
--> $DIR/missing-lifetime-in-assoc-type-5.rs:9:17
3+
|
4+
LL | impl<'a> IntoIterator for &'_ S {
5+
| ---- there is a named lifetime specified on the impl block you could use
6+
...
7+
LL | type Item = &T;
8+
| ^ this lifetime must come from the implemented type
9+
|
10+
help: consider using the lifetime from the impl block
11+
|
12+
LL | type Item = &'a T;
13+
| ++
14+
15+
error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
16+
--> $DIR/missing-lifetime-in-assoc-type-5.rs:4:6
17+
|
18+
LL | impl<'a> IntoIterator for &'_ S {
19+
| ^^ unconstrained lifetime parameter
20+
|
21+
help: consider using the named lifetime here instead of an implict lifetime
22+
|
23+
LL | impl<'a> IntoIterator for &'a S {
24+
| ~~
25+
26+
error: aborting due to 2 previous errors
27+
28+
For more information about this error, try `rustc --explain E0207`.

0 commit comments

Comments
 (0)