Account for enclosing item when suggesting new lifetime name

This commit is contained in:
Esteban Küber 2020-05-27 15:33:23 -07:00
parent 8f7ee34379
commit 224ad326ea
5 changed files with 96 additions and 23 deletions

View File

@ -60,7 +60,7 @@ use rustc_errors::{pluralize, struct_span_err};
use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::Node;
use rustc_hir::{Item, ItemKind, Node};
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::{
self,
@ -1685,12 +1685,26 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let hir = &self.tcx.hir();
// Attempt to obtain the span of the parameter so we can
// suggest adding an explicit lifetime bound to it.
let generics = self
.in_progress_tables
.and_then(|table| table.borrow().hir_owner)
.map(|table_owner| self.tcx.generics_of(table_owner.to_def_id()));
let generics =
self.in_progress_tables.and_then(|table| table.borrow().hir_owner).map(|table_owner| {
let hir_id = hir.as_local_hir_id(table_owner);
let parent_id = hir.get_parent_item(hir_id);
(
// Parent item could be a `mod`, so we check the HIR before calling:
if let Some(Node::Item(Item {
kind: ItemKind::Trait(..) | ItemKind::Impl { .. },
..
})) = hir.find(parent_id)
{
Some(self.tcx.generics_of(hir.local_def_id(parent_id).to_def_id()))
} else {
None
},
self.tcx.generics_of(table_owner.to_def_id()),
)
});
let type_param_span = match (generics, bound_kind) {
(Some(ref generics), GenericKind::Param(ref param)) => {
(Some((_, ref generics)), GenericKind::Param(ref param)) => {
// Account for the case where `param` corresponds to `Self`,
// which doesn't have the expected type argument.
if !(generics.has_self && param.index == 0) {
@ -1727,21 +1741,29 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
};
let new_lt = generics
.as_ref()
.and_then(|g| {
.and_then(|(parent_g, g)| {
let possible = ["'a", "'b", "'c", "'d", "'e", "'f", "'g", "'h", "'i", "'j", "'k"];
let lts_names = g
let mut lts_names = g
.params
.iter()
.filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime))
.map(|p| p.name.as_str())
.collect::<Vec<_>>();
if let Some(g) = parent_g {
lts_names.extend(
g.params
.iter()
.filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime))
.map(|p| p.name.as_str()),
);
}
let lts = lts_names.iter().map(|s| -> &str { &*s }).collect::<Vec<_>>();
possible.iter().filter(|&candidate| !lts.contains(&*candidate)).next().map(|s| *s)
})
.unwrap_or("'lt");
let add_lt_sugg = generics
.as_ref()
.and_then(|g| g.params.first())
.and_then(|(_, g)| g.params.first())
.and_then(|param| param.def_id.as_local())
.map(|def_id| {
(hir.span(hir.as_local_hir_id(def_id)).shrink_to_lo(), format!("{}, ", new_lt))

View File

@ -121,16 +121,14 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
(Some(ret_span), _) => (
ty_sub.span,
ret_span,
"this parameter and the return type are declared \
with different lifetimes..."
"this parameter and the return type are declared with different lifetimes..."
.to_owned(),
format!("...but data{} is returned here", span_label_var1),
),
(_, Some(ret_span)) => (
ty_sup.span,
ret_span,
"this parameter and the return type are declared \
with different lifetimes..."
"this parameter and the return type are declared with different lifetimes..."
.to_owned(),
format!("...but data{} is returned here", span_label_var1),
),

View File

@ -56,13 +56,30 @@ LL | | }
| |_^
error[E0311]: the parameter type `G` may not live long enough
--> $DIR/missing-lifetimes-in-signature.rs:58:45
--> $DIR/missing-lifetimes-in-signature.rs:59:58
|
LL | fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
| ^^^^^^^^^^^^^^^^^^
|
note: the parameter type `G` must be valid for the anonymous lifetime #1 defined on the method body at 59:5...
--> $DIR/missing-lifetimes-in-signature.rs:59:5
|
LL | / fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
LL | |
LL | | move || {
LL | | *dest = g.get();
LL | | }
LL | | }
| |_____^
error[E0311]: the parameter type `G` may not live long enough
--> $DIR/missing-lifetimes-in-signature.rs:68:45
|
LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
| ^^^^^^^^^^^^^^^^^^^^^^^
|
note: the parameter type `G` must be valid for the anonymous lifetime #1 defined on the function body at 58:1...
--> $DIR/missing-lifetimes-in-signature.rs:58:1
note: the parameter type `G` must be valid for the anonymous lifetime #1 defined on the function body at 68:1...
--> $DIR/missing-lifetimes-in-signature.rs:68:1
|
LL | / fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
LL | |
@ -74,7 +91,7 @@ LL | | }
| |_^
error[E0621]: explicit lifetime required in the type of `dest`
--> $DIR/missing-lifetimes-in-signature.rs:63:5
--> $DIR/missing-lifetimes-in-signature.rs:73:5
|
LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
| ------ help: add explicit lifetime `'a` to the type of `dest`: `&'a mut T`
@ -85,14 +102,14 @@ LL | | }
| |_____^ lifetime `'a` required
error[E0309]: the parameter type `G` may not live long enough
--> $DIR/missing-lifetimes-in-signature.rs:69:44
--> $DIR/missing-lifetimes-in-signature.rs:79:44
|
LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a
| ^^^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `G: 'a`...
error: aborting due to 7 previous errors
error: aborting due to 8 previous errors
Some errors have detailed explanations: E0261, E0309, E0621.
For more information about an error, try `rustc --explain E0261`.

View File

@ -54,6 +54,16 @@ where
}
}
// Same as above, but show that we pay attention to lifetime names from parent item
impl<'a> Foo {
fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
//~^ ERROR the parameter type `G` may not live long enough
move || {
*dest = g.get();
}
}
}
// After applying suggestion for `qux`:
fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
//~^ ERROR explicit lifetime required in the type of `dest`

View File

@ -87,8 +87,34 @@ help: consider introducing an explicit lifetime bound
LL | fn qux<'b, 'a, G: 'b + 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'b
| ^^^ ^^^^^^^ ^^^^
error[E0311]: the parameter type `G` may not live long enough
--> $DIR/missing-lifetimes-in-signature.rs:59:58
|
LL | fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
| ^^^^^^^^^^^^^^^^^^
|
note: the parameter type `G` must be valid for the anonymous lifetime #1 defined on the method body at 59:5...
--> $DIR/missing-lifetimes-in-signature.rs:59:5
|
LL | / fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
LL | |
LL | | move || {
LL | | *dest = g.get();
LL | | }
LL | | }
| |_____^
note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:61:9: 63:10 g:G, dest:&mut T]` will meet its required lifetime bounds
--> $DIR/missing-lifetimes-in-signature.rs:59:58
|
LL | fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
| ^^^^^^^^^^^^^^^^^^
help: consider introducing an explicit lifetime bound
|
LL | fn qux<'c, 'b, G: 'c + Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'c {
| ^^^ ^^^^^^^ ^^^^
error[E0621]: explicit lifetime required in the type of `dest`
--> $DIR/missing-lifetimes-in-signature.rs:58:45
--> $DIR/missing-lifetimes-in-signature.rs:68:45
|
LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
| ------ ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required
@ -96,14 +122,14 @@ LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
| help: add explicit lifetime `'a` to the type of `dest`: `&'a mut T`
error[E0309]: the parameter type `G` may not live long enough
--> $DIR/missing-lifetimes-in-signature.rs:69:44
--> $DIR/missing-lifetimes-in-signature.rs:79:44
|
LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a
| - ^^^^^^^^^^^^^^^^^^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:74:5: 76:6 g:G, dest:&mut T]` will meet its required lifetime bounds
| - ^^^^^^^^^^^^^^^^^^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:84:5: 86:6 g:G, dest:&mut T]` will meet its required lifetime bounds
| |
| help: consider adding an explicit lifetime bound...: `G: 'a`
error: aborting due to 6 previous errors
error: aborting due to 7 previous errors
Some errors have detailed explanations: E0261, E0309, E0621.
For more information about an error, try `rustc --explain E0261`.