Skip to content

Commit 1268377

Browse files
committed
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 ```
1 parent c92a579 commit 1268377

8 files changed

+71
-5
lines changed

compiler/rustc_resolve/src/late.rs

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ use rustc_ast::*;
2020
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
2121
use rustc_errors::codes::*;
2222
use rustc_errors::{
23-
Applicability, DiagArgValue, ErrorGuaranteed, IntoDiagArg, StashKey, Suggestions,
23+
Applicability, Diag, DiagArgValue, ErrorGuaranteed, IntoDiagArg, StashKey, Suggestions,
24+
pluralize,
2425
};
2526
use rustc_hir::def::Namespace::{self, *};
2627
use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS};
@@ -1841,9 +1842,13 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
18411842
ty: ty.span,
18421843
});
18431844
} else {
1844-
self.r.dcx().emit_err(errors::AnonymousLivetimeNonGatReportError {
1845-
lifetime: lifetime.ident.span,
1846-
});
1845+
let mut err = self.r.dcx().create_err(
1846+
errors::AnonymousLivetimeNonGatReportError {
1847+
lifetime: lifetime.ident.span,
1848+
},
1849+
);
1850+
self.point_at_impl_lifetimes(&mut err, i, lifetime.ident.span);
1851+
err.emit();
18471852
}
18481853
} else {
18491854
self.r.dcx().emit_err(errors::ElidedAnonymousLivetimeReportError {
@@ -1880,6 +1885,47 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
18801885
self.report_missing_lifetime_specifiers(vec![missing_lifetime], None);
18811886
}
18821887

1888+
fn point_at_impl_lifetimes(&mut self, err: &mut Diag<'_>, i: usize, lifetime: Span) {
1889+
let Some((rib, span)) = self.lifetime_ribs[..i]
1890+
.iter()
1891+
.rev()
1892+
.skip(1)
1893+
.filter_map(|rib| match rib.kind {
1894+
LifetimeRibKind::Generics { span, kind: LifetimeBinderKind::ImplBlock, .. } => {
1895+
Some((rib, span))
1896+
}
1897+
_ => None,
1898+
})
1899+
.next()
1900+
else {
1901+
return;
1902+
};
1903+
if !rib.bindings.is_empty() {
1904+
err.span_label(
1905+
span,
1906+
format!(
1907+
"there {} named lifetime{} specified on the impl block you could use",
1908+
if rib.bindings.len() == 1 { "is a" } else { "are" },
1909+
pluralize!(rib.bindings.len()),
1910+
),
1911+
);
1912+
if rib.bindings.len() == 1 {
1913+
err.span_suggestion_verbose(
1914+
lifetime.shrink_to_hi(),
1915+
"consider using the lifetime from the impl block",
1916+
format!("{} ", rib.bindings.keys().next().unwrap()),
1917+
Applicability::MaybeIncorrect,
1918+
);
1919+
}
1920+
} else {
1921+
err.span_label(
1922+
span,
1923+
"you could add a lifetime on the impl block, if the trait or the self type can \
1924+
have one",
1925+
);
1926+
}
1927+
}
1928+
18831929
#[instrument(level = "debug", skip(self))]
18841930
fn resolve_elided_lifetime(&mut self, anchor_id: NodeId, span: Span) {
18851931
let id = self.r.next_node_id();

tests/ui/impl-header-lifetime-elision/assoc-type.stderr

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
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
22
--> $DIR/assoc-type.rs:11:19
33
|
4+
LL | impl MyTrait for &i32 {
5+
| - you could add a lifetime on the impl block, if the trait or the self type can have one
46
LL | type Output = &i32;
57
| ^ this lifetime must come from the implemented type
68

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ struct T;
33

44
impl<'a> IntoIterator for &S {
55
//~^ ERROR E0207
6+
//~| NOTE there is a named lifetime specified on the impl block you could use
67
//~| NOTE unconstrained lifetime parameter
78
type Item = &T;
89
//~^ ERROR in the trait associated type
10+
//~| HELP consider using the lifetime from the impl block
911
//~| NOTE this lifetime must come from the implemented type
1012
type IntoIter = std::collections::btree_map::Values<'a, i32, T>;
1113

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
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:7:17
2+
--> $DIR/missing-lifetime-in-assoc-type-1.rs:8:17
33
|
4+
LL | impl<'a> IntoIterator for &S {
5+
| ---- there is a named lifetime specified on the impl block you could use
6+
...
47
LL | type Item = &T;
58
| ^ 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+
| ++
614

715
error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
816
--> $DIR/missing-lifetime-in-assoc-type-1.rs:4:6

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
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
22
--> $DIR/missing-lifetime-in-assoc-type-2.rs:5:17
33
|
4+
LL | impl IntoIterator for &S {
5+
| - you could add a lifetime on the impl block, if the trait or the self type can have one
46
LL | type Item = &T;
57
| ^ this lifetime must come from the implemented type
68

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
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
22
--> $DIR/missing-lifetime-in-assoc-type-3.rs:5:17
33
|
4+
LL | impl IntoIterator for &S {
5+
| - you could add a lifetime on the impl block, if the trait or the self type can have one
46
LL | type Item = &T;
57
| ^ this lifetime must come from the implemented type
68

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
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
22
--> $DIR/missing-lifetime-in-assoc-type-4.rs:5:17
33
|
4+
LL | impl IntoIterator for &S {
5+
| - you could add a lifetime on the impl block, if the trait or the self type can have one
46
LL | type Item = &T;
57
| ^ this lifetime must come from the implemented type
68

tests/ui/lifetimes/no_lending_iterators.stderr

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ LL | impl Iterator for Data {
1313
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
1414
--> $DIR/no_lending_iterators.rs:18:17
1515
|
16+
LL | impl Bar for usize {
17+
| - you could add a lifetime on the impl block, if the trait or the self type can have one
1618
LL | type Item = &usize;
1719
| ^ this lifetime must come from the implemented type
1820

0 commit comments

Comments
 (0)