Skip to content

Commit b4507bf

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 eb6d6f9 commit b4507bf

8 files changed

+71
-5
lines changed

compiler/rustc_resolve/src/late.rs

+50-4
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};
@@ -1870,9 +1871,13 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
18701871
ty: ty.span,
18711872
});
18721873
} else {
1873-
self.r.dcx().emit_err(errors::AnonymousLivetimeNonGatReportError {
1874-
lifetime: lifetime.ident.span,
1875-
});
1874+
let mut err = self.r.dcx().create_err(
1875+
errors::AnonymousLivetimeNonGatReportError {
1876+
lifetime: lifetime.ident.span,
1877+
},
1878+
);
1879+
self.point_at_impl_lifetimes(&mut err, i, lifetime.ident.span);
1880+
err.emit();
18761881
}
18771882
} else {
18781883
self.r.dcx().emit_err(errors::ElidedAnonymousLivetimeReportError {
@@ -1909,6 +1914,47 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
19091914
self.report_missing_lifetime_specifiers(vec![missing_lifetime], None);
19101915
}
19111916

1917+
fn point_at_impl_lifetimes(&mut self, err: &mut Diag<'_>, i: usize, lifetime: Span) {
1918+
let Some((rib, span)) = self.lifetime_ribs[..i]
1919+
.iter()
1920+
.rev()
1921+
.skip(1)
1922+
.filter_map(|rib| match rib.kind {
1923+
LifetimeRibKind::Generics { span, kind: LifetimeBinderKind::ImplBlock, .. } => {
1924+
Some((rib, span))
1925+
}
1926+
_ => None,
1927+
})
1928+
.next()
1929+
else {
1930+
return;
1931+
};
1932+
if !rib.bindings.is_empty() {
1933+
err.span_label(
1934+
span,
1935+
format!(
1936+
"there {} named lifetime{} specified on the impl block you could use",
1937+
if rib.bindings.len() == 1 { "is a" } else { "are" },
1938+
pluralize!(rib.bindings.len()),
1939+
),
1940+
);
1941+
if rib.bindings.len() == 1 {
1942+
err.span_suggestion_verbose(
1943+
lifetime.shrink_to_hi(),
1944+
"consider using the lifetime from the impl block",
1945+
format!("{} ", rib.bindings.keys().next().unwrap()),
1946+
Applicability::MaybeIncorrect,
1947+
);
1948+
}
1949+
} else {
1950+
err.span_label(
1951+
span,
1952+
"you could add a lifetime on the impl block, if the trait or the self type can \
1953+
have one",
1954+
);
1955+
}
1956+
}
1957+
19121958
#[instrument(level = "debug", skip(self))]
19131959
fn resolve_elided_lifetime(&mut self, anchor_id: NodeId, span: Span) {
19141960
let id = self.r.next_node_id();

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

+2
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

+2
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

+9-1
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

+2
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

+2
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

+2
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

+2
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)