mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Rollup merge of #135602 - estebank:issue-135589, r=Nadrieril
Tweak output of missing lifetime on associated type Each commit can be reviewed independently. Address parts of #135589. --- 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 ``` --- 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 { | ++ ``` --- Do not suggest introducing lifetime in impl assoc type --- Previously we only showed the trait's assoc item if the trait was local, because we were looking for a small span only for the generics, which we don't have for foreign traits. We now use `def_span` for the item, so we at least provide some context, even if its span is too wide. ``` error[E0195]: lifetime parameters or bounds on type `IntoIter` do not match the trait declaration --> tests/ui/lifetimes/missing-lifetime-in-assoc-type-4.rs:7:18 | 7 | type IntoIter<'a> = std::collections::btree_map::Values<'a, i32, T>; | ^^^^ lifetimes do not match type in trait | ::: /home/gh-estebank/rust/library/core/src/iter/traits/collect.rs:292:5 | 292 | type IntoIter: Iterator<Item = Self::Item>; | ------------------------------------------ lifetimes in impl do not match this type in trait ```
This commit is contained in:
@@ -12,11 +12,12 @@
|
||||
|
||||
use min_specialization::check_min_specialization;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::ErrorGuaranteed;
|
||||
use rustc_span::{ErrorGuaranteed, kw};
|
||||
|
||||
use crate::constrained_generic_params as cgp;
|
||||
use crate::errors::UnconstrainedGenericParameter;
|
||||
@@ -150,6 +151,27 @@ pub(crate) fn enforce_impl_lifetime_params_are_constrained(
|
||||
const_param_note2: false,
|
||||
});
|
||||
diag.code(E0207);
|
||||
for p in &impl_generics.own_params {
|
||||
if p.name == kw::UnderscoreLifetime {
|
||||
let span = tcx.def_span(p.def_id);
|
||||
let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let (span, sugg) = if &snippet == "'_" {
|
||||
(span, param.name.to_string())
|
||||
} else {
|
||||
(span.shrink_to_hi(), format!("{} ", param.name))
|
||||
};
|
||||
diag.span_suggestion_verbose(
|
||||
span,
|
||||
"consider using the named lifetime here instead of an implicit \
|
||||
lifetime",
|
||||
sugg,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
res = Err(diag.emit());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
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};
|
||||
@@ -377,6 +378,7 @@ enum LifetimeBinderKind {
|
||||
Function,
|
||||
Closure,
|
||||
ImplBlock,
|
||||
ImplAssocType,
|
||||
}
|
||||
|
||||
impl LifetimeBinderKind {
|
||||
@@ -387,6 +389,7 @@ fn descr(self) -> &'static str {
|
||||
PolyTrait => "bound",
|
||||
WhereBound => "bound",
|
||||
Item | ConstItem => "item",
|
||||
ImplAssocType => "associated type",
|
||||
ImplBlock => "impl block",
|
||||
Function => "function",
|
||||
Closure => "closure",
|
||||
@@ -1874,9 +1877,13 @@ fn resolve_anonymous_lifetime(
|
||||
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 +1920,47 @@ fn resolve_anonymous_lifetime(
|
||||
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();
|
||||
@@ -3352,7 +3400,7 @@ fn resolve_impl_item(
|
||||
&generics.params,
|
||||
RibKind::AssocItem,
|
||||
item.id,
|
||||
LifetimeBinderKind::Item,
|
||||
LifetimeBinderKind::ImplAssocType,
|
||||
generics.span,
|
||||
|this| {
|
||||
this.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
|
||||
|
||||
@@ -3178,6 +3178,9 @@ fn suggest_introducing_lifetime(
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if let LifetimeBinderKind::ImplAssocType = kind {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !span.can_be_used_for_suggestions()
|
||||
&& suggest_note
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
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
|
||||
//~| HELP consider using the named lifetime here instead of an implicit lifetime
|
||||
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() {}
|
||||
@@ -0,0 +1,28 @@
|
||||
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:9: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
|
||||
|
|
||||
help: consider using the named lifetime here instead of an implicit lifetime
|
||||
|
|
||||
LL | impl<'a> IntoIterator for &'a S {
|
||||
| ++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0207`.
|
||||
@@ -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() {}
|
||||
@@ -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-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 | impl<'a> IntoIterator for &S {
|
||||
| ++++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0261`.
|
||||
@@ -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() {}
|
||||
@@ -0,0 +1,25 @@
|
||||
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 ~ impl<'a> IntoIterator for &S {
|
||||
LL | type Item = &T;
|
||||
LL |
|
||||
LL ~ type IntoIter = 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`.
|
||||
@@ -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 associated type `IntoIter` do not match the trait declaration
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
fn main() {}
|
||||
@@ -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 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 associated type in trait
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0195`.
|
||||
@@ -0,0 +1,19 @@
|
||||
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
|
||||
//~| HELP consider using the named lifetime here instead of an implicit lifetime
|
||||
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() {}
|
||||
@@ -0,0 +1,29 @@
|
||||
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-5.rs:9: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-5.rs:4:6
|
||||
|
|
||||
LL | impl<'a> IntoIterator for &'_ S {
|
||||
| ^^ unconstrained lifetime parameter
|
||||
|
|
||||
help: consider using the named lifetime here instead of an implicit lifetime
|
||||
|
|
||||
LL - impl<'a> IntoIterator for &'_ S {
|
||||
LL + impl<'a> IntoIterator for &'a S {
|
||||
|
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0207`.
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -6,8 +6,9 @@ LL | type Item = IteratorChunk<T, S>;
|
||||
|
|
||||
help: consider introducing a named lifetime parameter
|
||||
|
|
||||
LL | type Item<'a> = IteratorChunk<'a, T, S>;
|
||||
| ++++ +++
|
||||
LL ~ impl<'a, T, S: Iterator<Item = T>> Iterator for ChunkingIterator<T, S> {
|
||||
LL ~ type Item = IteratorChunk<'a, T, S>;
|
||||
|
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
||||
@@ -17,10 +17,6 @@ LL | type T = &'missing ();
|
||||
|
|
||||
help: consider introducing lifetime `'missing` here
|
||||
|
|
||||
LL | type T<'missing> = &'missing ();
|
||||
| ++++++++++
|
||||
help: consider introducing lifetime `'missing` here
|
||||
|
|
||||
LL | impl<'missing> Lt<'missing> for () {
|
||||
| ++++++++++
|
||||
|
||||
|
||||
Reference in New Issue
Block a user