Skip to content

Commit 6a3deb0

Browse files
committed
Suggest using 'static in assoc consts and suggest when multiple lts are needed
1 parent becd479 commit 6a3deb0

File tree

5 files changed

+144
-12
lines changed

5 files changed

+144
-12
lines changed

src/librustc_resolve/late/diagnostics.rs

+51-3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ enum AssocSuggestion {
3333
crate enum MissingLifetimeSpot<'tcx> {
3434
Generics(&'tcx hir::Generics<'tcx>),
3535
HigherRanked { span: Span, span_type: ForLifetimeSpanType },
36+
Static,
3637
}
3738

3839
crate enum ForLifetimeSpanType {
@@ -1186,6 +1187,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
11861187
https://doc.rust-lang.org/nomicon/hrtb.html",
11871188
);
11881189
}
1190+
_ => {}
11891191
}
11901192
}
11911193
if nightly_options::is_nightly_build()
@@ -1358,6 +1360,42 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
13581360
);
13591361
(*span, span_type.suggestion("'a"))
13601362
}
1363+
MissingLifetimeSpot::Static => {
1364+
let (span, sugg) = match snippet.as_deref() {
1365+
Some("&") => (span.shrink_to_hi(), "'static ".to_owned()),
1366+
Some("'_") => (span, "'static".to_owned()),
1367+
Some(snippet) if !snippet.ends_with('>') => {
1368+
if snippet == "" {
1369+
(
1370+
span,
1371+
std::iter::repeat("'static")
1372+
.take(count)
1373+
.collect::<Vec<_>>()
1374+
.join(", "),
1375+
)
1376+
} else {
1377+
(
1378+
span.shrink_to_hi(),
1379+
format!(
1380+
"<{}>",
1381+
std::iter::repeat("'static")
1382+
.take(count)
1383+
.collect::<Vec<_>>()
1384+
.join(", ")
1385+
),
1386+
)
1387+
}
1388+
}
1389+
_ => continue,
1390+
};
1391+
err.span_suggestion_verbose(
1392+
span,
1393+
"consider using the `'static` lifetime",
1394+
sugg.to_string(),
1395+
Applicability::MaybeIncorrect,
1396+
);
1397+
continue;
1398+
}
13611399
});
13621400
for param in params {
13631401
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span) {
@@ -1408,13 +1446,23 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
14081446
([], Some("'_")) if count == 1 => {
14091447
suggest_new(err, "'a");
14101448
}
1411-
([], Some(snippet)) if !snippet.ends_with('>') && count == 1 => {
1449+
([], Some(snippet)) if !snippet.ends_with('>') => {
14121450
if snippet == "" {
14131451
// This happens when we have `type Bar<'a> = Foo<T>` where we point at the space
14141452
// before `T`. We will suggest `type Bar<'a> = Foo<'a, T>`.
1415-
suggest_new(err, "'a, ");
1453+
suggest_new(
1454+
err,
1455+
&std::iter::repeat("'a, ").take(count).collect::<Vec<_>>().join(""),
1456+
);
14161457
} else {
1417-
suggest_new(err, &format!("{}<'a>", snippet));
1458+
suggest_new(
1459+
err,
1460+
&format!(
1461+
"{}<{}>",
1462+
snippet,
1463+
std::iter::repeat("'a").take(count).collect::<Vec<_>>().join(", ")
1464+
),
1465+
);
14181466
}
14191467
}
14201468
(lts, ..) if lts.len() > 1 => {

src/librustc_resolve/late/lifetimes.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -764,26 +764,30 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
764764
Const(_, _) => {
765765
// Only methods and types support generics.
766766
assert!(trait_item.generics.params.is_empty());
767+
self.missing_named_lifetime_spots.push(MissingLifetimeSpot::Static);
767768
intravisit::walk_trait_item(self, trait_item);
769+
self.missing_named_lifetime_spots.pop();
768770
}
769771
}
770772
}
771773

772774
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
773775
use self::hir::ImplItemKind::*;
774-
self.missing_named_lifetime_spots.push((&impl_item.generics).into());
775776
match impl_item.kind {
776777
Fn(ref sig, _) => {
778+
self.missing_named_lifetime_spots.push((&impl_item.generics).into());
777779
let tcx = self.tcx;
778780
self.visit_early_late(
779781
Some(tcx.hir().get_parent_item(impl_item.hir_id)),
780782
&sig.decl,
781783
&impl_item.generics,
782784
|this| intravisit::walk_impl_item(this, impl_item),
783-
)
785+
);
786+
self.missing_named_lifetime_spots.pop();
784787
}
785788
TyAlias(ref ty) => {
786789
let generics = &impl_item.generics;
790+
self.missing_named_lifetime_spots.push(generics.into());
787791
let mut index = self.next_early_index();
788792
let mut non_lifetime_count = 0;
789793
debug!("visit_ty: index = {}", index);
@@ -812,14 +816,16 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
812816
this.visit_generics(generics);
813817
this.visit_ty(ty);
814818
});
819+
self.missing_named_lifetime_spots.pop();
815820
}
816821
Const(_, _) => {
817822
// Only methods and types support generics.
818823
assert!(impl_item.generics.params.is_empty());
824+
self.missing_named_lifetime_spots.push(MissingLifetimeSpot::Static);
819825
intravisit::walk_impl_item(self, impl_item);
826+
self.missing_named_lifetime_spots.pop();
820827
}
821828
}
822-
self.missing_named_lifetime_spots.pop();
823829
}
824830

825831
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {

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

+9
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,15 @@ error[E0106]: missing lifetime specifiers
5151
|
5252
LL | buzz: Buzz,
5353
| ^^^^ expected 2 lifetime parameters
54+
|
55+
help: consider introducing a named lifetime parameter
56+
|
57+
LL | struct Quux<'a> {
58+
LL | baz: Baz,
59+
LL |
60+
LL |
61+
LL | buzz: Buzz<'a, 'a>,
62+
|
5463

5564
error: aborting due to 5 previous errors
5665

Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
trait ZstAssert: Sized {
2-
const TYPE_NAME: &str = ""; //~ ERROR missing lifetime specifier
2+
const A: &str = ""; //~ ERROR missing lifetime specifier
3+
const B: S = S { s: &() }; //~ ERROR missing lifetime specifier
4+
const C: &'_ str = ""; //~ ERROR missing lifetime specifier
5+
const D: T = T { a: &(), b: &() }; //~ ERROR missing lifetime specifier
6+
}
7+
8+
struct S<'a> {
9+
s: &'a (),
10+
}
11+
struct T<'a, 'b> {
12+
a: &'a (),
13+
b: &'b (),
314
}
415

516
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,73 @@
11
error[E0106]: missing lifetime specifier
2-
--> $DIR/missing-lifetime-in-assoc-const-type.rs:2:22
2+
--> $DIR/missing-lifetime-in-assoc-const-type.rs:2:14
33
|
4-
LL | const TYPE_NAME: &str = "";
5-
| ^ expected named lifetime parameter
4+
LL | const A: &str = "";
5+
| ^ expected named lifetime parameter
66
|
7+
help: consider using the `'static` lifetime
8+
|
9+
LL | const A: &'static str = "";
10+
| ^^^^^^^
11+
help: consider introducing a named lifetime parameter
12+
|
13+
LL | trait ZstAssert<'a>: Sized {
14+
LL | const A: &'a str = "";
15+
|
16+
17+
error[E0106]: missing lifetime specifier
18+
--> $DIR/missing-lifetime-in-assoc-const-type.rs:3:14
19+
|
20+
LL | const B: S = S { s: &() };
21+
| ^ expected named lifetime parameter
22+
|
23+
help: consider using the `'static` lifetime
24+
|
25+
LL | const B: S<'static> = S { s: &() };
26+
| ^^^^^^^^^
27+
help: consider introducing a named lifetime parameter
28+
|
29+
LL | trait ZstAssert<'a>: Sized {
30+
LL | const A: &str = "";
31+
LL | const B: S<'a> = S { s: &() };
32+
|
33+
34+
error[E0106]: missing lifetime specifier
35+
--> $DIR/missing-lifetime-in-assoc-const-type.rs:4:15
36+
|
37+
LL | const C: &'_ str = "";
38+
| ^^ expected named lifetime parameter
39+
|
40+
help: consider using the `'static` lifetime
41+
|
42+
LL | const C: &'static str = "";
43+
| ^^^^^^^
44+
help: consider introducing a named lifetime parameter
45+
|
46+
LL | trait ZstAssert<'a>: Sized {
47+
LL | const A: &str = "";
48+
LL | const B: S = S { s: &() };
49+
LL | const C: &'a str = "";
50+
|
51+
52+
error[E0106]: missing lifetime specifiers
53+
--> $DIR/missing-lifetime-in-assoc-const-type.rs:5:14
54+
|
55+
LL | const D: T = T { a: &(), b: &() };
56+
| ^ expected 2 lifetime parameters
57+
|
58+
help: consider using the `'static` lifetime
59+
|
60+
LL | const D: T<'static, 'static> = T { a: &(), b: &() };
61+
| ^^^^^^^^^^^^^^^^^^
762
help: consider introducing a named lifetime parameter
863
|
964
LL | trait ZstAssert<'a>: Sized {
10-
LL | const TYPE_NAME: &'a str = "";
65+
LL | const A: &str = "";
66+
LL | const B: S = S { s: &() };
67+
LL | const C: &'_ str = "";
68+
LL | const D: T<'a, 'a> = T { a: &(), b: &() };
1169
|
1270

13-
error: aborting due to previous error
71+
error: aborting due to 4 previous errors
1472

1573
For more information about this error, try `rustc --explain E0106`.

0 commit comments

Comments
 (0)