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
```
This commit is contained in:
parent
2e01acc59e
commit
8ba2950fb6
9 changed files with 74 additions and 8 deletions
|
|
@ -19,7 +19,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
|||
use rustc_data_structures::unord::{UnordMap, UnordSet};
|
||||
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};
|
||||
|
|
@ -1874,9 +1875,13 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
ty: ty.span,
|
||||
});
|
||||
} else {
|
||||
self.r.dcx().emit_err(errors::AnonymousLifetimeNonGatReportError {
|
||||
lifetime: lifetime.ident.span,
|
||||
});
|
||||
let mut err = self.r.dcx().create_err(
|
||||
errors::AnonymousLifetimeNonGatReportError {
|
||||
lifetime: lifetime.ident.span,
|
||||
},
|
||||
);
|
||||
self.point_at_impl_lifetimes(&mut err, i, lifetime.ident.span);
|
||||
err.emit();
|
||||
}
|
||||
} else {
|
||||
self.r.dcx().emit_err(errors::ElidedAnonymousLifetimeReportError {
|
||||
|
|
@ -1913,6 +1918,47 @@ impl<'a, 'ast, 'ra, '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)
|
||||
.filter_map(|rib| match rib.kind {
|
||||
LifetimeRibKind::Generics { span, kind: LifetimeBinderKind::ImplBlock, .. } => {
|
||||
Some((rib, span))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.next()
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ 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
|
||||
//~^ ERROR lifetime parameters or bounds on associated type `IntoIter` do not match the trait declaration
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
todo!()
|
||||
|
|
|
|||
|
|
@ -1,14 +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-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
|
||||
error[E0195]: lifetime parameters or bounds on associated 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
|
||||
| ^^^^ lifetimes do not match associated type in trait
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue