Skip to content

Commit 6ba0875

Browse files
committed
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.
1 parent 7da653f commit 6ba0875

14 files changed

+249
-18
lines changed

src/librustc_resolve/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#![feature(crate_visibility_modifier)]
1212
#![feature(label_break_value)]
1313
#![feature(nll)]
14+
#![feature(slice_patterns)]
1415
#![recursion_limit = "256"]
1516

1617
pub use rustc_hir::def::{Namespace, PerNS};

src/librustc_resolve/lifetimes.rs

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,10 @@ struct LifetimeContext<'a, 'tcx> {
183183
xcrate_object_lifetime_defaults: DefIdMap<Vec<ObjectLifetimeDefault>>,
184184

185185
lifetime_uses: &'a mut DefIdMap<LifetimeUseSet<'tcx>>,
186+
187+
/// When encountering an undefined named lifetime, we will suggest introducing it in these
188+
/// places.
189+
missing_named_lifetime_spots: Vec<&'tcx hir::Generics<'tcx>>,
186190
}
187191

188192
#[derive(Debug)]
@@ -342,6 +346,7 @@ fn krate(tcx: TyCtxt<'_>) -> NamedRegionMap {
342346
labels_in_fn: vec![],
343347
xcrate_object_lifetime_defaults: Default::default(),
344348
lifetime_uses: &mut Default::default(),
349+
missing_named_lifetime_spots: vec![],
345350
};
346351
for (_, item) in &krate.items {
347352
visitor.visit_item(item);
@@ -384,9 +389,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
384389
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
385390
match item.kind {
386391
hir::ItemKind::Fn(ref sig, ref generics, _) => {
392+
self.missing_named_lifetime_spots.push(generics);
387393
self.visit_early_late(None, &sig.decl, generics, |this| {
388394
intravisit::walk_item(this, item);
389395
});
396+
self.missing_named_lifetime_spots.pop();
390397
}
391398

392399
hir::ItemKind::ExternCrate(_)
@@ -417,6 +424,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
417424
| hir::ItemKind::Trait(_, _, ref generics, ..)
418425
| hir::ItemKind::TraitAlias(ref generics, ..)
419426
| hir::ItemKind::Impl { ref generics, .. } => {
427+
self.missing_named_lifetime_spots.push(generics);
428+
420429
// Impls permit `'_` to be used and it is equivalent to "some fresh lifetime name".
421430
// This is not true for other kinds of items.x
422431
let track_lifetime_uses = match item.kind {
@@ -454,6 +463,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
454463
this.check_lifetime_params(old_scope, &generics.params);
455464
intravisit::walk_item(this, item);
456465
});
466+
self.missing_named_lifetime_spots.pop();
457467
}
458468
}
459469
}
@@ -686,6 +696,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
686696

687697
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
688698
use self::hir::TraitItemKind::*;
699+
self.missing_named_lifetime_spots.push(&trait_item.generics);
689700
match trait_item.kind {
690701
Method(ref sig, _) => {
691702
let tcx = self.tcx;
@@ -737,10 +748,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
737748
intravisit::walk_trait_item(self, trait_item);
738749
}
739750
}
751+
self.missing_named_lifetime_spots.pop();
740752
}
741753

742754
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
743755
use self::hir::ImplItemKind::*;
756+
self.missing_named_lifetime_spots.push(&impl_item.generics);
744757
match impl_item.kind {
745758
Method(ref sig, _) => {
746759
let tcx = self.tcx;
@@ -824,6 +837,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
824837
intravisit::walk_impl_item(self, impl_item);
825838
}
826839
}
840+
self.missing_named_lifetime_spots.pop();
827841
}
828842

829843
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
@@ -1306,7 +1320,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
13061320
where
13071321
F: for<'b> FnOnce(ScopeRef<'_>, &mut LifetimeContext<'b, 'tcx>),
13081322
{
1309-
let LifetimeContext { tcx, map, lifetime_uses, .. } = self;
1323+
let LifetimeContext { tcx, map, lifetime_uses, missing_named_lifetime_spots, .. } = self;
13101324
let labels_in_fn = take(&mut self.labels_in_fn);
13111325
let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults);
13121326
let mut this = LifetimeContext {
@@ -1317,7 +1331,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
13171331
is_in_fn_syntax: self.is_in_fn_syntax,
13181332
labels_in_fn,
13191333
xcrate_object_lifetime_defaults,
1320-
lifetime_uses: lifetime_uses,
1334+
lifetime_uses,
1335+
missing_named_lifetime_spots: missing_named_lifetime_spots.to_vec(),
13211336
};
13221337
debug!("entering scope {:?}", this.scope);
13231338
f(self.scope, &mut this);
@@ -1807,15 +1822,29 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
18071822

18081823
self.insert_lifetime(lifetime_ref, def);
18091824
} else {
1810-
struct_span_err!(
1825+
let mut err = struct_span_err!(
18111826
self.tcx.sess,
18121827
lifetime_ref.span,
18131828
E0261,
18141829
"use of undeclared lifetime name `{}`",
18151830
lifetime_ref
1816-
)
1817-
.span_label(lifetime_ref.span, "undeclared lifetime")
1818-
.emit();
1831+
);
1832+
err.span_label(lifetime_ref.span, "undeclared lifetime");
1833+
if !self.is_in_fn_syntax {
1834+
for generics in &self.missing_named_lifetime_spots {
1835+
let (span, sugg) = match &generics.params {
1836+
[] => (generics.span, format!("<{}>", lifetime_ref)),
1837+
[param, ..] => (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref)),
1838+
};
1839+
err.span_suggestion(
1840+
span,
1841+
&format!("consider introducing lifetime `{}` here", lifetime_ref),
1842+
sugg,
1843+
Applicability::MaybeIncorrect,
1844+
);
1845+
}
1846+
}
1847+
err.emit();
18191848
}
18201849
}
18211850

src/test/ui/error-codes/E0261.stderr

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@ error[E0261]: use of undeclared lifetime name `'a`
22
--> $DIR/E0261.rs:1:12
33
|
44
LL | fn foo(x: &'a str) { }
5-
| ^^ undeclared lifetime
5+
| - ^^ undeclared lifetime
6+
| |
7+
| help: consider introducing lifetime `'a` here: `<'a>`
68

79
error[E0261]: use of undeclared lifetime name `'a`
810
--> $DIR/E0261.rs:5:9
911
|
12+
LL | struct Foo {
13+
| - help: consider introducing lifetime `'a` here: `<'a>`
1014
LL | x: &'a str,
1115
| ^^ undeclared lifetime
1216

src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr

Lines changed: 111 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,103 +2,207 @@ error[E0261]: use of undeclared lifetime name `'x`
22
--> $DIR/feature-gate-in_band_lifetimes.rs:3:12
33
|
44
LL | fn foo(x: &'x u8) -> &'x u8 { x }
5-
| ^^ undeclared lifetime
5+
| - ^^ undeclared lifetime
6+
| |
7+
| help: consider introducing lifetime `'x` here: `<'x>`
68

79
error[E0261]: use of undeclared lifetime name `'x`
810
--> $DIR/feature-gate-in_band_lifetimes.rs:3:23
911
|
1012
LL | fn foo(x: &'x u8) -> &'x u8 { x }
11-
| ^^ undeclared lifetime
13+
| - ^^ undeclared lifetime
14+
| |
15+
| help: consider introducing lifetime `'x` here: `<'x>`
1216

1317
error[E0261]: use of undeclared lifetime name `'b`
1418
--> $DIR/feature-gate-in_band_lifetimes.rs:15:12
1519
|
1620
LL | impl<'a> X<'b> {
17-
| ^^ undeclared lifetime
21+
| - ^^ undeclared lifetime
22+
| |
23+
| help: consider introducing lifetime `'b` here: `'b,`
1824

1925
error[E0261]: use of undeclared lifetime name `'b`
2026
--> $DIR/feature-gate-in_band_lifetimes.rs:17:27
2127
|
2228
LL | fn inner_2(&self) -> &'b u8 {
2329
| ^^ undeclared lifetime
30+
|
31+
help: consider introducing lifetime `'b` here
32+
|
33+
LL | impl<'b, 'a> X<'b> {
34+
| ^^^
35+
help: consider introducing lifetime `'b` here
36+
|
37+
LL | fn inner_2<'b>(&self) -> &'b u8 {
38+
| ^^^^
2439

2540
error[E0261]: use of undeclared lifetime name `'b`
2641
--> $DIR/feature-gate-in_band_lifetimes.rs:23:8
2742
|
2843
LL | impl X<'b> {
29-
| ^^ undeclared lifetime
44+
| - ^^ undeclared lifetime
45+
| |
46+
| help: consider introducing lifetime `'b` here: `<'b>`
3047

3148
error[E0261]: use of undeclared lifetime name `'b`
3249
--> $DIR/feature-gate-in_band_lifetimes.rs:25:27
3350
|
3451
LL | fn inner_3(&self) -> &'b u8 {
3552
| ^^ undeclared lifetime
53+
|
54+
help: consider introducing lifetime `'b` here
55+
|
56+
LL | impl<'b> X<'b> {
57+
| ^^^^
58+
help: consider introducing lifetime `'b` here
59+
|
60+
LL | fn inner_3<'b>(&self) -> &'b u8 {
61+
| ^^^^
3662

3763
error[E0261]: use of undeclared lifetime name `'a`
3864
--> $DIR/feature-gate-in_band_lifetimes.rs:33:9
3965
|
4066
LL | impl Y<&'a u8> {
41-
| ^^ undeclared lifetime
67+
| - ^^ undeclared lifetime
68+
| |
69+
| help: consider introducing lifetime `'a` here: `<'a>`
4270

4371
error[E0261]: use of undeclared lifetime name `'a`
4472
--> $DIR/feature-gate-in_band_lifetimes.rs:35:25
4573
|
4674
LL | fn inner(&self) -> &'a u8 {
4775
| ^^ undeclared lifetime
76+
|
77+
help: consider introducing lifetime `'a` here
78+
|
79+
LL | impl<'a> Y<&'a u8> {
80+
| ^^^^
81+
help: consider introducing lifetime `'a` here
82+
|
83+
LL | fn inner<'a>(&self) -> &'a u8 {
84+
| ^^^^
4885

4986
error[E0261]: use of undeclared lifetime name `'b`
5087
--> $DIR/feature-gate-in_band_lifetimes.rs:43:27
5188
|
5289
LL | fn any_lifetime() -> &'b u8;
5390
| ^^ undeclared lifetime
91+
|
92+
help: consider introducing lifetime `'b` here
93+
|
94+
LL | trait MyTrait<'b, 'a> {
95+
| ^^^
96+
help: consider introducing lifetime `'b` here
97+
|
98+
LL | fn any_lifetime<'b>() -> &'b u8;
99+
| ^^^^
54100

55101
error[E0261]: use of undeclared lifetime name `'b`
56102
--> $DIR/feature-gate-in_band_lifetimes.rs:45:27
57103
|
58104
LL | fn borrowed_lifetime(&'b self) -> &'b u8;
59105
| ^^ undeclared lifetime
106+
|
107+
help: consider introducing lifetime `'b` here
108+
|
109+
LL | trait MyTrait<'b, 'a> {
110+
| ^^^
111+
help: consider introducing lifetime `'b` here
112+
|
113+
LL | fn borrowed_lifetime<'b>(&'b self) -> &'b u8;
114+
| ^^^^
60115

61116
error[E0261]: use of undeclared lifetime name `'b`
62117
--> $DIR/feature-gate-in_band_lifetimes.rs:45:40
63118
|
64119
LL | fn borrowed_lifetime(&'b self) -> &'b u8;
65120
| ^^ undeclared lifetime
121+
|
122+
help: consider introducing lifetime `'b` here
123+
|
124+
LL | trait MyTrait<'b, 'a> {
125+
| ^^^
126+
help: consider introducing lifetime `'b` here
127+
|
128+
LL | fn borrowed_lifetime<'b>(&'b self) -> &'b u8;
129+
| ^^^^
66130

67131
error[E0261]: use of undeclared lifetime name `'a`
68132
--> $DIR/feature-gate-in_band_lifetimes.rs:50:14
69133
|
70134
LL | impl MyTrait<'a> for Y<&'a u8> {
71-
| ^^ undeclared lifetime
135+
| - ^^ undeclared lifetime
136+
| |
137+
| help: consider introducing lifetime `'a` here: `<'a>`
72138

73139
error[E0261]: use of undeclared lifetime name `'a`
74140
--> $DIR/feature-gate-in_band_lifetimes.rs:50:25
75141
|
76142
LL | impl MyTrait<'a> for Y<&'a u8> {
77-
| ^^ undeclared lifetime
143+
| - ^^ undeclared lifetime
144+
| |
145+
| help: consider introducing lifetime `'a` here: `<'a>`
78146

79147
error[E0261]: use of undeclared lifetime name `'a`
80148
--> $DIR/feature-gate-in_band_lifetimes.rs:53:31
81149
|
82150
LL | fn my_lifetime(&self) -> &'a u8 { self.0 }
83151
| ^^ undeclared lifetime
152+
|
153+
help: consider introducing lifetime `'a` here
154+
|
155+
LL | impl<'a> MyTrait<'a> for Y<&'a u8> {
156+
| ^^^^
157+
help: consider introducing lifetime `'a` here
158+
|
159+
LL | fn my_lifetime<'a>(&self) -> &'a u8 { self.0 }
160+
| ^^^^
84161

85162
error[E0261]: use of undeclared lifetime name `'b`
86163
--> $DIR/feature-gate-in_band_lifetimes.rs:55:27
87164
|
88165
LL | fn any_lifetime() -> &'b u8 { &0 }
89166
| ^^ undeclared lifetime
167+
|
168+
help: consider introducing lifetime `'b` here
169+
|
170+
LL | impl<'b> MyTrait<'a> for Y<&'a u8> {
171+
| ^^^^
172+
help: consider introducing lifetime `'b` here
173+
|
174+
LL | fn any_lifetime<'b>() -> &'b u8 { &0 }
175+
| ^^^^
90176

91177
error[E0261]: use of undeclared lifetime name `'b`
92178
--> $DIR/feature-gate-in_band_lifetimes.rs:57:27
93179
|
94180
LL | fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 }
95181
| ^^ undeclared lifetime
182+
|
183+
help: consider introducing lifetime `'b` here
184+
|
185+
LL | impl<'b> MyTrait<'a> for Y<&'a u8> {
186+
| ^^^^
187+
help: consider introducing lifetime `'b` here
188+
|
189+
LL | fn borrowed_lifetime<'b>(&'b self) -> &'b u8 { &*self.0 }
190+
| ^^^^
96191

97192
error[E0261]: use of undeclared lifetime name `'b`
98193
--> $DIR/feature-gate-in_band_lifetimes.rs:57:40
99194
|
100195
LL | fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 }
101196
| ^^ undeclared lifetime
197+
|
198+
help: consider introducing lifetime `'b` here
199+
|
200+
LL | impl<'b> MyTrait<'a> for Y<&'a u8> {
201+
| ^^^^
202+
help: consider introducing lifetime `'b` here
203+
|
204+
LL | fn borrowed_lifetime<'b>(&'b self) -> &'b u8 { &*self.0 }
205+
| ^^^^
102206

103207
error: aborting due to 17 previous errors
104208

0 commit comments

Comments
 (0)