When encountering an undefined named lifetime, point to where it can be

This doesn't mention that using an existing lifetime is possible, but
that would hopefully be clear as always being an option. The intention
of this is to teach newcomers what the lifetime syntax is.
This commit is contained in:
Esteban Küber 2020-01-15 18:34:30 -08:00
parent 7da653f669
commit 6ba08755df
14 changed files with 249 additions and 18 deletions

View File

@ -11,6 +11,7 @@
#![feature(crate_visibility_modifier)]
#![feature(label_break_value)]
#![feature(nll)]
#![feature(slice_patterns)]
#![recursion_limit = "256"]
pub use rustc_hir::def::{Namespace, PerNS};

View File

@ -183,6 +183,10 @@ struct LifetimeContext<'a, 'tcx> {
xcrate_object_lifetime_defaults: DefIdMap<Vec<ObjectLifetimeDefault>>,
lifetime_uses: &'a mut DefIdMap<LifetimeUseSet<'tcx>>,
/// When encountering an undefined named lifetime, we will suggest introducing it in these
/// places.
missing_named_lifetime_spots: Vec<&'tcx hir::Generics<'tcx>>,
}
#[derive(Debug)]
@ -342,6 +346,7 @@ fn krate(tcx: TyCtxt<'_>) -> NamedRegionMap {
labels_in_fn: vec![],
xcrate_object_lifetime_defaults: Default::default(),
lifetime_uses: &mut Default::default(),
missing_named_lifetime_spots: vec![],
};
for (_, item) in &krate.items {
visitor.visit_item(item);
@ -384,9 +389,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
match item.kind {
hir::ItemKind::Fn(ref sig, ref generics, _) => {
self.missing_named_lifetime_spots.push(generics);
self.visit_early_late(None, &sig.decl, generics, |this| {
intravisit::walk_item(this, item);
});
self.missing_named_lifetime_spots.pop();
}
hir::ItemKind::ExternCrate(_)
@ -417,6 +424,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
| hir::ItemKind::Trait(_, _, ref generics, ..)
| hir::ItemKind::TraitAlias(ref generics, ..)
| hir::ItemKind::Impl { ref generics, .. } => {
self.missing_named_lifetime_spots.push(generics);
// Impls permit `'_` to be used and it is equivalent to "some fresh lifetime name".
// This is not true for other kinds of items.x
let track_lifetime_uses = match item.kind {
@ -454,6 +463,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
this.check_lifetime_params(old_scope, &generics.params);
intravisit::walk_item(this, item);
});
self.missing_named_lifetime_spots.pop();
}
}
}
@ -686,6 +696,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
use self::hir::TraitItemKind::*;
self.missing_named_lifetime_spots.push(&trait_item.generics);
match trait_item.kind {
Method(ref sig, _) => {
let tcx = self.tcx;
@ -737,10 +748,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
intravisit::walk_trait_item(self, trait_item);
}
}
self.missing_named_lifetime_spots.pop();
}
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
use self::hir::ImplItemKind::*;
self.missing_named_lifetime_spots.push(&impl_item.generics);
match impl_item.kind {
Method(ref sig, _) => {
let tcx = self.tcx;
@ -824,6 +837,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
intravisit::walk_impl_item(self, impl_item);
}
}
self.missing_named_lifetime_spots.pop();
}
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
@ -1306,7 +1320,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
where
F: for<'b> FnOnce(ScopeRef<'_>, &mut LifetimeContext<'b, 'tcx>),
{
let LifetimeContext { tcx, map, lifetime_uses, .. } = self;
let LifetimeContext { tcx, map, lifetime_uses, missing_named_lifetime_spots, .. } = self;
let labels_in_fn = take(&mut self.labels_in_fn);
let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults);
let mut this = LifetimeContext {
@ -1317,7 +1331,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
is_in_fn_syntax: self.is_in_fn_syntax,
labels_in_fn,
xcrate_object_lifetime_defaults,
lifetime_uses: lifetime_uses,
lifetime_uses,
missing_named_lifetime_spots: missing_named_lifetime_spots.to_vec(),
};
debug!("entering scope {:?}", this.scope);
f(self.scope, &mut this);
@ -1807,15 +1822,29 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
self.insert_lifetime(lifetime_ref, def);
} else {
struct_span_err!(
let mut err = struct_span_err!(
self.tcx.sess,
lifetime_ref.span,
E0261,
"use of undeclared lifetime name `{}`",
lifetime_ref
)
.span_label(lifetime_ref.span, "undeclared lifetime")
.emit();
);
err.span_label(lifetime_ref.span, "undeclared lifetime");
if !self.is_in_fn_syntax {
for generics in &self.missing_named_lifetime_spots {
let (span, sugg) = match &generics.params {
[] => (generics.span, format!("<{}>", lifetime_ref)),
[param, ..] => (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref)),
};
err.span_suggestion(
span,
&format!("consider introducing lifetime `{}` here", lifetime_ref),
sugg,
Applicability::MaybeIncorrect,
);
}
}
err.emit();
}
}

View File

@ -2,11 +2,15 @@ error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/E0261.rs:1:12
|
LL | fn foo(x: &'a str) { }
| ^^ undeclared lifetime
| - ^^ undeclared lifetime
| |
| help: consider introducing lifetime `'a` here: `<'a>`
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/E0261.rs:5:9
|
LL | struct Foo {
| - help: consider introducing lifetime `'a` here: `<'a>`
LL | x: &'a str,
| ^^ undeclared lifetime

View File

@ -2,103 +2,207 @@ error[E0261]: use of undeclared lifetime name `'x`
--> $DIR/feature-gate-in_band_lifetimes.rs:3:12
|
LL | fn foo(x: &'x u8) -> &'x u8 { x }
| ^^ undeclared lifetime
| - ^^ undeclared lifetime
| |
| help: consider introducing lifetime `'x` here: `<'x>`
error[E0261]: use of undeclared lifetime name `'x`
--> $DIR/feature-gate-in_band_lifetimes.rs:3:23
|
LL | fn foo(x: &'x u8) -> &'x u8 { x }
| ^^ undeclared lifetime
| - ^^ undeclared lifetime
| |
| help: consider introducing lifetime `'x` here: `<'x>`
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/feature-gate-in_band_lifetimes.rs:15:12
|
LL | impl<'a> X<'b> {
| ^^ undeclared lifetime
| - ^^ undeclared lifetime
| |
| help: consider introducing lifetime `'b` here: `'b,`
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/feature-gate-in_band_lifetimes.rs:17:27
|
LL | fn inner_2(&self) -> &'b u8 {
| ^^ undeclared lifetime
|
help: consider introducing lifetime `'b` here
|
LL | impl<'b, 'a> X<'b> {
| ^^^
help: consider introducing lifetime `'b` here
|
LL | fn inner_2<'b>(&self) -> &'b u8 {
| ^^^^
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/feature-gate-in_band_lifetimes.rs:23:8
|
LL | impl X<'b> {
| ^^ undeclared lifetime
| - ^^ undeclared lifetime
| |
| help: consider introducing lifetime `'b` here: `<'b>`
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/feature-gate-in_band_lifetimes.rs:25:27
|
LL | fn inner_3(&self) -> &'b u8 {
| ^^ undeclared lifetime
|
help: consider introducing lifetime `'b` here
|
LL | impl<'b> X<'b> {
| ^^^^
help: consider introducing lifetime `'b` here
|
LL | fn inner_3<'b>(&self) -> &'b u8 {
| ^^^^
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/feature-gate-in_band_lifetimes.rs:33:9
|
LL | impl Y<&'a u8> {
| ^^ undeclared lifetime
| - ^^ undeclared lifetime
| |
| help: consider introducing lifetime `'a` here: `<'a>`
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/feature-gate-in_band_lifetimes.rs:35:25
|
LL | fn inner(&self) -> &'a u8 {
| ^^ undeclared lifetime
|
help: consider introducing lifetime `'a` here
|
LL | impl<'a> Y<&'a u8> {
| ^^^^
help: consider introducing lifetime `'a` here
|
LL | fn inner<'a>(&self) -> &'a u8 {
| ^^^^
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/feature-gate-in_band_lifetimes.rs:43:27
|
LL | fn any_lifetime() -> &'b u8;
| ^^ undeclared lifetime
|
help: consider introducing lifetime `'b` here
|
LL | trait MyTrait<'b, 'a> {
| ^^^
help: consider introducing lifetime `'b` here
|
LL | fn any_lifetime<'b>() -> &'b u8;
| ^^^^
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/feature-gate-in_band_lifetimes.rs:45:27
|
LL | fn borrowed_lifetime(&'b self) -> &'b u8;
| ^^ undeclared lifetime
|
help: consider introducing lifetime `'b` here
|
LL | trait MyTrait<'b, 'a> {
| ^^^
help: consider introducing lifetime `'b` here
|
LL | fn borrowed_lifetime<'b>(&'b self) -> &'b u8;
| ^^^^
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/feature-gate-in_band_lifetimes.rs:45:40
|
LL | fn borrowed_lifetime(&'b self) -> &'b u8;
| ^^ undeclared lifetime
|
help: consider introducing lifetime `'b` here
|
LL | trait MyTrait<'b, 'a> {
| ^^^
help: consider introducing lifetime `'b` here
|
LL | fn borrowed_lifetime<'b>(&'b self) -> &'b u8;
| ^^^^
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/feature-gate-in_band_lifetimes.rs:50:14
|
LL | impl MyTrait<'a> for Y<&'a u8> {
| ^^ undeclared lifetime
| - ^^ undeclared lifetime
| |
| help: consider introducing lifetime `'a` here: `<'a>`
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/feature-gate-in_band_lifetimes.rs:50:25
|
LL | impl MyTrait<'a> for Y<&'a u8> {
| ^^ undeclared lifetime
| - ^^ undeclared lifetime
| |
| help: consider introducing lifetime `'a` here: `<'a>`
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/feature-gate-in_band_lifetimes.rs:53:31
|
LL | fn my_lifetime(&self) -> &'a u8 { self.0 }
| ^^ undeclared lifetime
|
help: consider introducing lifetime `'a` here
|
LL | impl<'a> MyTrait<'a> for Y<&'a u8> {
| ^^^^
help: consider introducing lifetime `'a` here
|
LL | fn my_lifetime<'a>(&self) -> &'a u8 { self.0 }
| ^^^^
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/feature-gate-in_band_lifetimes.rs:55:27
|
LL | fn any_lifetime() -> &'b u8 { &0 }
| ^^ undeclared lifetime
|
help: consider introducing lifetime `'b` here
|
LL | impl<'b> MyTrait<'a> for Y<&'a u8> {
| ^^^^
help: consider introducing lifetime `'b` here
|
LL | fn any_lifetime<'b>() -> &'b u8 { &0 }
| ^^^^
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/feature-gate-in_band_lifetimes.rs:57:27
|
LL | fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 }
| ^^ undeclared lifetime
|
help: consider introducing lifetime `'b` here
|
LL | impl<'b> MyTrait<'a> for Y<&'a u8> {
| ^^^^
help: consider introducing lifetime `'b` here
|
LL | fn borrowed_lifetime<'b>(&'b self) -> &'b u8 { &*self.0 }
| ^^^^
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/feature-gate-in_band_lifetimes.rs:57:40
|
LL | fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 }
| ^^ undeclared lifetime
|
help: consider introducing lifetime `'b` here
|
LL | impl<'b> MyTrait<'a> for Y<&'a u8> {
| ^^^^
help: consider introducing lifetime `'b` here
|
LL | fn borrowed_lifetime<'b>(&'b self) -> &'b u8 { &*self.0 }
| ^^^^
error: aborting due to 17 previous errors

View File

@ -3,12 +3,30 @@ error[E0261]: use of undeclared lifetime name `'b`
|
LL | + Deref<Target = Self::Item<'b>>;
| ^^ undeclared lifetime
|
help: consider introducing lifetime `'b` here
|
LL | trait Iterable<'b> {
| ^^^^
help: consider introducing lifetime `'b` here
|
LL | type Iter<'b, 'a>: Iterator<Item = Self::Item<'a>>
| ^^^
error[E0261]: use of undeclared lifetime name `'undeclared`
--> $DIR/generic_associated_type_undeclared_lifetimes.rs:12:41
|
LL | fn iter<'a>(&'a self) -> Self::Iter<'undeclared>;
| ^^^^^^^^^^^ undeclared lifetime
|
help: consider introducing lifetime `'undeclared` here
|
LL | trait Iterable<'undeclared> {
| ^^^^^^^^^^^^^
help: consider introducing lifetime `'undeclared` here
|
LL | fn iter<'undeclared, 'a>(&'a self) -> Self::Iter<'undeclared>;
| ^^^^^^^^^^^^
error: aborting due to 2 previous errors

View File

@ -1,12 +1,16 @@
error[E0261]: use of undeclared lifetime name `'test`
--> $DIR/no_in_band_in_struct.rs:5:9
|
LL | struct Foo {
| - help: consider introducing lifetime `'test` here: `<'test>`
LL | x: &'test u32,
| ^^^^^ undeclared lifetime
error[E0261]: use of undeclared lifetime name `'test`
--> $DIR/no_in_band_in_struct.rs:9:10
|
LL | enum Bar {
| - help: consider introducing lifetime `'test` here: `<'test>`
LL | Baz(&'test u32),
| ^^^^^ undeclared lifetime

View File

@ -1,6 +1,8 @@
error[E0261]: use of undeclared lifetime name `'test`
--> $DIR/no_introducing_in_band_in_locals.rs:5:13
|
LL | fn foo(x: &u32) {
| - help: consider introducing lifetime `'test` here: `<'test>`
LL | let y: &'test u32 = x;
| ^^^^^ undeclared lifetime

View File

@ -1,6 +1,8 @@
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/method-call-lifetime-args-unresolved.rs:2:15
|
LL | fn main() {
| - help: consider introducing lifetime `'a` here: `<'a>`
LL | 0.clone::<'a>();
| ^^ undeclared lifetime

View File

@ -33,6 +33,9 @@ LL | let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>;
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/trait-object-trait-parens.rs:11:31
|
LL | fn main() {
| - help: consider introducing lifetime `'a` here: `<'a>`
...
LL | let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>;
| ^^ undeclared lifetime

View File

@ -1,12 +1,16 @@
error[E0261]: use of undeclared lifetime name `'foo`
--> $DIR/regions-in-enums.rs:13:9
|
LL | enum No0 {
| - help: consider introducing lifetime `'foo` here: `<'foo>`
LL | X5(&'foo usize)
| ^^^^ undeclared lifetime
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/regions-in-enums.rs:17:9
|
LL | enum No1 {
| - help: consider introducing lifetime `'a` here: `<'a>`
LL | X6(&'a usize)
| ^^ undeclared lifetime

View File

@ -1,12 +1,17 @@
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/regions-in-structs.rs:10:9
|
LL | struct StructDecl {
| - help: consider introducing lifetime `'a` here: `<'a>`
LL | a: &'a isize,
| ^^ undeclared lifetime
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/regions-in-structs.rs:11:9
|
LL | struct StructDecl {
| - help: consider introducing lifetime `'a` here: `<'a>`
LL | a: &'a isize,
LL | b: &'a isize,
| ^^ undeclared lifetime

View File

@ -3,34 +3,67 @@ error[E0261]: use of undeclared lifetime name `'b`
|
LL | fn m4(&self, arg: &'b isize) { }
| ^^ undeclared lifetime
|
help: consider introducing lifetime `'b` here
|
LL | impl<'b, 'a> Foo<'a> {
| ^^^
help: consider introducing lifetime `'b` here
|
LL | fn m4<'b>(&self, arg: &'b isize) { }
| ^^^^
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/regions-name-undeclared.rs:16:12
|
LL | fn m5(&'b self) { }
| ^^ undeclared lifetime
|
help: consider introducing lifetime `'b` here
|
LL | impl<'b, 'a> Foo<'a> {
| ^^^
help: consider introducing lifetime `'b` here
|
LL | fn m5<'b>(&'b self) { }
| ^^^^
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/regions-name-undeclared.rs:17:27
|
LL | fn m6(&self, arg: Foo<'b>) { }
| ^^ undeclared lifetime
|
help: consider introducing lifetime `'b` here
|
LL | impl<'b, 'a> Foo<'a> {
| ^^^
help: consider introducing lifetime `'b` here
|
LL | fn m6<'b>(&self, arg: Foo<'b>) { }
| ^^^^
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/regions-name-undeclared.rs:25:22
|
LL | type X = Option<&'a isize>;
| ^^ undeclared lifetime
| - ^^ undeclared lifetime
| |
| help: consider introducing lifetime `'a` here: `<'a>`
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/regions-name-undeclared.rs:27:13
|
LL | enum E {
| - help: consider introducing lifetime `'a` here: `<'a>`
LL | E1(&'a isize)
| ^^ undeclared lifetime
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/regions-name-undeclared.rs:30:13
|
LL | struct S {
| - help: consider introducing lifetime `'a` here: `<'a>`
LL | f: &'a isize
| ^^ undeclared lifetime
@ -38,13 +71,17 @@ error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/regions-name-undeclared.rs:32:14
|
LL | fn f(a: &'a isize) { }
| ^^ undeclared lifetime
| - ^^ undeclared lifetime
| |
| help: consider introducing lifetime `'a` here: `<'a>`
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/regions-name-undeclared.rs:40:17
|
LL | fn fn_types(a: &'a isize,
| ^^ undeclared lifetime
| - ^^ undeclared lifetime
| |
| help: consider introducing lifetime `'a` here: `<'a>`
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/regions-name-undeclared.rs:42:36
@ -61,6 +98,9 @@ LL | ... &'b isize)>,
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/regions-name-undeclared.rs:46:17
|
LL | fn fn_types(a: &'a isize,
| - help: consider introducing lifetime `'a` here: `<'a>`
...
LL | c: &'a isize)
| ^^ undeclared lifetime

View File

@ -7,12 +7,17 @@ LL | static c_x: &'blk isize = &22;
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/regions-undeclared.rs:4:10
|
LL | enum EnumDecl {
| - help: consider introducing lifetime `'a` here: `<'a>`
LL | Foo(&'a isize),
| ^^ undeclared lifetime
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/regions-undeclared.rs:5:10
|
LL | enum EnumDecl {
| - help: consider introducing lifetime `'a` here: `<'a>`
LL | Foo(&'a isize),
LL | Bar(&'a isize),
| ^^ undeclared lifetime
@ -20,11 +25,15 @@ error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/regions-undeclared.rs:8:15
|
LL | fn fnDecl(x: &'a isize,
| ^^ undeclared lifetime
| - ^^ undeclared lifetime
| |
| help: consider introducing lifetime `'a` here: `<'a>`
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/regions-undeclared.rs:9:15
|
LL | fn fnDecl(x: &'a isize,
| - help: consider introducing lifetime `'a` here: `<'a>`
LL | y: &'a isize)
| ^^ undeclared lifetime

View File

@ -1,6 +1,9 @@
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/where-lifetime-resolution.rs:6:38
|
LL | fn f() where
| - help: consider introducing lifetime `'a` here: `<'a>`
LL | for<'a> dyn Trait1<'a>: Trait1<'a>, // OK
LL | (dyn for<'a> Trait1<'a>): Trait1<'a>,
| ^^ undeclared lifetime
@ -13,6 +16,9 @@ LL | for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>,
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/where-lifetime-resolution.rs:8:52
|
LL | fn f() where
| - help: consider introducing lifetime `'b` here: `<'b>`
...
LL | for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>,
| ^^ undeclared lifetime