Skip to content

Commit

Permalink
Rollup merge of #94464 - kckeiks:lifetime-elision-mismatch-hint-for-t…
Browse files Browse the repository at this point in the history
…raits, r=estebank

Suggest adding a new lifetime parameter when two elided lifetimes should match up for traits and impls.

Suggest adding a new lifetime parameter when two elided lifetimes should match up for functions in traits and impls.

Issue #94462
  • Loading branch information
matthiaskrgr authored Mar 2, 2022
2 parents f0c4da4 + 1b08cba commit 2b72ecb
Show file tree
Hide file tree
Showing 11 changed files with 264 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -166,59 +166,61 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
if lifetime_sub.name.is_elided() && lifetime_sup.name.is_elided() {
if let Some(anon_reg) = self.tcx().is_suitable_region(sub) {
let hir_id = self.tcx().hir().local_def_id_to_hir_id(anon_reg.def_id);
if let hir::Node::Item(&hir::Item {
kind: hir::ItemKind::Fn(_, ref generics, ..),
..
}) = self.tcx().hir().get(hir_id)
{
let (suggestion_param_name, introduce_new) = generics
.params
.iter()
.find(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
.and_then(|p| self.tcx().sess.source_map().span_to_snippet(p.span).ok())
.map(|name| (name, false))
.unwrap_or_else(|| ("'a".to_string(), true));

let mut suggestions = vec![
if let hir::LifetimeName::Underscore = lifetime_sub.name {
(lifetime_sub.span, suggestion_param_name.clone())
} else {
(
lifetime_sub.span.shrink_to_hi(),
suggestion_param_name.clone() + " ",
)
},
if let hir::LifetimeName::Underscore = lifetime_sup.name {
(lifetime_sup.span, suggestion_param_name.clone())
} else {
(
lifetime_sup.span.shrink_to_hi(),
suggestion_param_name.clone() + " ",
)
},
];

if introduce_new {
let new_param_suggestion = match &generics.params {
[] => (generics.span, format!("<{}>", suggestion_param_name)),
[first, ..] => (
first.span.shrink_to_lo(),
format!("{}, ", suggestion_param_name),
),
};

suggestions.push(new_param_suggestion);
}

err.multipart_suggestion(
"consider introducing a named lifetime parameter",
suggestions,
Applicability::MaybeIncorrect,
);
err.note(
"each elided lifetime in input position becomes a distinct lifetime",
);

let node = self.tcx().hir().get(hir_id);
let is_impl = matches!(&node, hir::Node::ImplItem(_));
let generics = match node {
hir::Node::Item(&hir::Item {
kind: hir::ItemKind::Fn(_, ref generics, ..),
..
})
| hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
| hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
_ => return,
};

let (suggestion_param_name, introduce_new) = generics
.params
.iter()
.find(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
.and_then(|p| self.tcx().sess.source_map().span_to_snippet(p.span).ok())
.map(|name| (name, false))
.unwrap_or_else(|| ("'a".to_string(), true));

let mut suggestions = vec![
if let hir::LifetimeName::Underscore = lifetime_sub.name {
(lifetime_sub.span, suggestion_param_name.clone())
} else {
(lifetime_sub.span.shrink_to_hi(), suggestion_param_name.clone() + " ")
},
if let hir::LifetimeName::Underscore = lifetime_sup.name {
(lifetime_sup.span, suggestion_param_name.clone())
} else {
(lifetime_sup.span.shrink_to_hi(), suggestion_param_name.clone() + " ")
},
];

if introduce_new {
let new_param_suggestion = match &generics.params {
[] => (generics.span, format!("<{}>", suggestion_param_name)),
[first, ..] => {
(first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name))
}
};

suggestions.push(new_param_suggestion);
}

let mut sugg = String::from("consider introducing a named lifetime parameter");
if is_impl {
sugg.push_str(" and update trait if needed");
}
err.multipart_suggestion(
sugg.as_str(),
suggestions,
Applicability::MaybeIncorrect,
);
err.note("each elided lifetime in input position becomes a distinct lifetime");
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/test/ui/issues/issue-17728.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ LL | fn attemptTraverse(&self, room: &Room, directionStr: &str) -> Result<&R
...
LL | Some(entry) => Ok(entry),
| ^^^^^^^^^ ...but data from `room` is returned here
|
= note: each elided lifetime in input position becomes a distinct lifetime
help: consider introducing a named lifetime parameter
|
LL | fn attemptTraverse<'a>(&'a self, room: &'a Room, directionStr: &str) -> Result<&Room, &str> {
| ++++ ++ ++

error[E0308]: `match` arms have incompatible types
--> $DIR/issue-17728.rs:109:14
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ LL | fn foo<'a>(&self, x: &i32) -> &i32 {
| this parameter and the return type are declared with different lifetimes...
LL | x
| ^ ...but data from `x` is returned here
|
= note: each elided lifetime in input position becomes a distinct lifetime
help: consider introducing a named lifetime parameter and update trait if needed
|
LL | fn foo<'a>(&'a self, x: &'a i32) -> &i32 {
| ++ ++

error: aborting due to previous error

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ LL | fn foo<'a>(&self, x: &Foo) -> &Foo {
| this parameter and the return type are declared with different lifetimes...
LL | if true { x } else { self }
| ^ ...but data from `x` is returned here
|
= note: each elided lifetime in input position becomes a distinct lifetime
help: consider introducing a named lifetime parameter and update trait if needed
|
LL | fn foo<'a>(&'a self, x: &'a Foo) -> &Foo {
| ++ ++

error: aborting due to previous error

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ LL | fn foo(x: &mut Vec<&u8>, y: &u8) {
| --- --- these two types are declared with different lifetimes...
LL | x.push(y);
| ^ ...but data from `y` flows into `x` here
|
= note: each elided lifetime in input position becomes a distinct lifetime
help: consider introducing a named lifetime parameter and update trait if needed
|
LL | fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) {
| ++++ ++ ++

error: aborting due to previous error

Expand Down
12 changes: 12 additions & 0 deletions src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ LL | fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
| ---- ---- ^ ...but data from `f` is returned here
| |
| this parameter and the return type are declared with different lifetimes...
|
= note: each elided lifetime in input position becomes a distinct lifetime
help: consider introducing a named lifetime parameter and update trait if needed
|
LL | fn a<'a>(self: Pin<&'a Foo>, f: &'a Foo) -> &Foo { f }
| ++++ ++ ++

error[E0623]: lifetime mismatch
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:8:76
Expand All @@ -13,6 +19,12 @@ LL | fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self,
| ---- ----------------- ^ ...but data from `f` is returned here
| |
| this parameter and the return type are declared with different lifetimes...
|
= note: each elided lifetime in input position becomes a distinct lifetime
help: consider introducing a named lifetime parameter and update trait if needed
|
LL | fn c<'a>(self: Pin<&'a Self>, f: &'a Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
| ++++ ++ ++

error[E0623]: lifetime mismatch
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:13:58
Expand Down
36 changes: 36 additions & 0 deletions src/test/ui/self/elision/lt-ref-self.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ LL | fn ref_self(&self, f: &u32) -> &u32 {
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
|
= note: each elided lifetime in input position becomes a distinct lifetime
help: consider introducing a named lifetime parameter and update trait if needed
|
LL | fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
| ++++ ++ ++

error[E0623]: lifetime mismatch
--> $DIR/lt-ref-self.rs:17:9
Expand All @@ -17,6 +23,12 @@ LL | fn ref_Self(self: &Self, f: &u32) -> &u32 {
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
|
= note: each elided lifetime in input position becomes a distinct lifetime
help: consider introducing a named lifetime parameter and update trait if needed
|
LL | fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
| ++++ ++ ++

error[E0623]: lifetime mismatch
--> $DIR/lt-ref-self.rs:21:9
Expand All @@ -27,6 +39,12 @@ LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
|
= note: each elided lifetime in input position becomes a distinct lifetime
help: consider introducing a named lifetime parameter and update trait if needed
|
LL | fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
| ++++ ++ ++

error[E0623]: lifetime mismatch
--> $DIR/lt-ref-self.rs:25:9
Expand All @@ -37,6 +55,12 @@ LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
|
= note: each elided lifetime in input position becomes a distinct lifetime
help: consider introducing a named lifetime parameter and update trait if needed
|
LL | fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
| ++++ ++ ++

error[E0623]: lifetime mismatch
--> $DIR/lt-ref-self.rs:29:9
Expand All @@ -47,6 +71,12 @@ LL | fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
|
= note: each elided lifetime in input position becomes a distinct lifetime
help: consider introducing a named lifetime parameter and update trait if needed
|
LL | fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
| ++++ ++ ++

error[E0623]: lifetime mismatch
--> $DIR/lt-ref-self.rs:33:9
Expand All @@ -57,6 +87,12 @@ LL | fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
|
= note: each elided lifetime in input position becomes a distinct lifetime
help: consider introducing a named lifetime parameter and update trait if needed
|
LL | fn box_pin_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
| ++++ ++ ++

error: aborting due to 6 previous errors

Expand Down
36 changes: 36 additions & 0 deletions src/test/ui/self/elision/ref-mut-self.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ LL | fn ref_self(&mut self, f: &u32) -> &u32 {
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
|
= note: each elided lifetime in input position becomes a distinct lifetime
help: consider introducing a named lifetime parameter and update trait if needed
|
LL | fn ref_self<'a>(&'a mut self, f: &'a u32) -> &u32 {
| ++++ ++ ++

error[E0623]: lifetime mismatch
--> $DIR/ref-mut-self.rs:17:9
Expand All @@ -17,6 +23,12 @@ LL | fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
|
= note: each elided lifetime in input position becomes a distinct lifetime
help: consider introducing a named lifetime parameter and update trait if needed
|
LL | fn ref_Self<'a>(self: &'a mut Self, f: &'a u32) -> &u32 {
| ++++ ++ ++

error[E0623]: lifetime mismatch
--> $DIR/ref-mut-self.rs:21:9
Expand All @@ -27,6 +39,12 @@ LL | fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
|
= note: each elided lifetime in input position becomes a distinct lifetime
help: consider introducing a named lifetime parameter and update trait if needed
|
LL | fn box_ref_Self<'a>(self: Box<&'a mut Self>, f: &'a u32) -> &u32 {
| ++++ ++ ++

error[E0623]: lifetime mismatch
--> $DIR/ref-mut-self.rs:25:9
Expand All @@ -37,6 +55,12 @@ LL | fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
|
= note: each elided lifetime in input position becomes a distinct lifetime
help: consider introducing a named lifetime parameter and update trait if needed
|
LL | fn pin_ref_Self<'a>(self: Pin<&'a mut Self>, f: &'a u32) -> &u32 {
| ++++ ++ ++

error[E0623]: lifetime mismatch
--> $DIR/ref-mut-self.rs:29:9
Expand All @@ -47,6 +71,12 @@ LL | fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
|
= note: each elided lifetime in input position becomes a distinct lifetime
help: consider introducing a named lifetime parameter and update trait if needed
|
LL | fn box_box_ref_Self<'a>(self: Box<Box<&'a mut Self>>, f: &'a u32) -> &u32 {
| ++++ ++ ++

error[E0623]: lifetime mismatch
--> $DIR/ref-mut-self.rs:33:9
Expand All @@ -57,6 +87,12 @@ LL | fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
|
= note: each elided lifetime in input position becomes a distinct lifetime
help: consider introducing a named lifetime parameter and update trait if needed
|
LL | fn box_pin_ref_Self<'a>(self: Box<Pin<&'a mut Self>>, f: &'a u32) -> &u32 {
| ++++ ++ ++

error: aborting due to 6 previous errors

Expand Down
Loading

0 comments on commit 2b72ecb

Please sign in to comment.