Skip to content

Commit

Permalink
Suggest using 'static in assoc consts and suggest when multiple lts…
Browse files Browse the repository at this point in the history
… are needed
  • Loading branch information
estebank committed Aug 11, 2020
1 parent becd479 commit 6a3deb0
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 12 deletions.
54 changes: 51 additions & 3 deletions src/librustc_resolve/late/diagnostics.rs
Expand Up @@ -33,6 +33,7 @@ enum AssocSuggestion {
crate enum MissingLifetimeSpot<'tcx> {
Generics(&'tcx hir::Generics<'tcx>),
HigherRanked { span: Span, span_type: ForLifetimeSpanType },
Static,
}

crate enum ForLifetimeSpanType {
Expand Down Expand Up @@ -1186,6 +1187,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
https://doc.rust-lang.org/nomicon/hrtb.html",
);
}
_ => {}
}
}
if nightly_options::is_nightly_build()
Expand Down Expand Up @@ -1358,6 +1360,42 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
);
(*span, span_type.suggestion("'a"))
}
MissingLifetimeSpot::Static => {
let (span, sugg) = match snippet.as_deref() {
Some("&") => (span.shrink_to_hi(), "'static ".to_owned()),
Some("'_") => (span, "'static".to_owned()),
Some(snippet) if !snippet.ends_with('>') => {
if snippet == "" {
(
span,
std::iter::repeat("'static")
.take(count)
.collect::<Vec<_>>()
.join(", "),
)
} else {
(
span.shrink_to_hi(),
format!(
"<{}>",
std::iter::repeat("'static")
.take(count)
.collect::<Vec<_>>()
.join(", ")
),
)
}
}
_ => continue,
};
err.span_suggestion_verbose(
span,
"consider using the `'static` lifetime",
sugg.to_string(),
Applicability::MaybeIncorrect,
);
continue;
}
});
for param in params {
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span) {
Expand Down Expand Up @@ -1408,13 +1446,23 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
([], Some("'_")) if count == 1 => {
suggest_new(err, "'a");
}
([], Some(snippet)) if !snippet.ends_with('>') && count == 1 => {
([], Some(snippet)) if !snippet.ends_with('>') => {
if snippet == "" {
// This happens when we have `type Bar<'a> = Foo<T>` where we point at the space
// before `T`. We will suggest `type Bar<'a> = Foo<'a, T>`.
suggest_new(err, "'a, ");
suggest_new(
err,
&std::iter::repeat("'a, ").take(count).collect::<Vec<_>>().join(""),
);
} else {
suggest_new(err, &format!("{}<'a>", snippet));
suggest_new(
err,
&format!(
"{}<{}>",
snippet,
std::iter::repeat("'a").take(count).collect::<Vec<_>>().join(", ")
),
);
}
}
(lts, ..) if lts.len() > 1 => {
Expand Down
12 changes: 9 additions & 3 deletions src/librustc_resolve/late/lifetimes.rs
Expand Up @@ -764,26 +764,30 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
Const(_, _) => {
// Only methods and types support generics.
assert!(trait_item.generics.params.is_empty());
self.missing_named_lifetime_spots.push(MissingLifetimeSpot::Static);
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).into());
match impl_item.kind {
Fn(ref sig, _) => {
self.missing_named_lifetime_spots.push((&impl_item.generics).into());
let tcx = self.tcx;
self.visit_early_late(
Some(tcx.hir().get_parent_item(impl_item.hir_id)),
&sig.decl,
&impl_item.generics,
|this| intravisit::walk_impl_item(this, impl_item),
)
);
self.missing_named_lifetime_spots.pop();
}
TyAlias(ref ty) => {
let generics = &impl_item.generics;
self.missing_named_lifetime_spots.push(generics.into());
let mut index = self.next_early_index();
let mut non_lifetime_count = 0;
debug!("visit_ty: index = {}", index);
Expand Down Expand Up @@ -812,14 +816,16 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
this.visit_generics(generics);
this.visit_ty(ty);
});
self.missing_named_lifetime_spots.pop();
}
Const(_, _) => {
// Only methods and types support generics.
assert!(impl_item.generics.params.is_empty());
self.missing_named_lifetime_spots.push(MissingLifetimeSpot::Static);
intravisit::walk_impl_item(self, impl_item);
self.missing_named_lifetime_spots.pop();
}
}
self.missing_named_lifetime_spots.pop();
}

fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
Expand Down
9 changes: 9 additions & 0 deletions src/test/ui/error-codes/E0106.stderr
Expand Up @@ -51,6 +51,15 @@ error[E0106]: missing lifetime specifiers
|
LL | buzz: Buzz,
| ^^^^ expected 2 lifetime parameters
|
help: consider introducing a named lifetime parameter
|
LL | struct Quux<'a> {
LL | baz: Baz,
LL |
LL |
LL | buzz: Buzz<'a, 'a>,
|

error: aborting due to 5 previous errors

Expand Down
13 changes: 12 additions & 1 deletion src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.rs
@@ -1,5 +1,16 @@
trait ZstAssert: Sized {
const TYPE_NAME: &str = ""; //~ ERROR missing lifetime specifier
const A: &str = ""; //~ ERROR missing lifetime specifier
const B: S = S { s: &() }; //~ ERROR missing lifetime specifier
const C: &'_ str = ""; //~ ERROR missing lifetime specifier
const D: T = T { a: &(), b: &() }; //~ ERROR missing lifetime specifier
}

struct S<'a> {
s: &'a (),
}
struct T<'a, 'b> {
a: &'a (),
b: &'b (),
}

fn main() {}
@@ -1,15 +1,73 @@
error[E0106]: missing lifetime specifier
--> $DIR/missing-lifetime-in-assoc-const-type.rs:2:22
--> $DIR/missing-lifetime-in-assoc-const-type.rs:2:14
|
LL | const TYPE_NAME: &str = "";
| ^ expected named lifetime parameter
LL | const A: &str = "";
| ^ expected named lifetime parameter
|
help: consider using the `'static` lifetime
|
LL | const A: &'static str = "";
| ^^^^^^^
help: consider introducing a named lifetime parameter
|
LL | trait ZstAssert<'a>: Sized {
LL | const A: &'a str = "";
|

error[E0106]: missing lifetime specifier
--> $DIR/missing-lifetime-in-assoc-const-type.rs:3:14
|
LL | const B: S = S { s: &() };
| ^ expected named lifetime parameter
|
help: consider using the `'static` lifetime
|
LL | const B: S<'static> = S { s: &() };
| ^^^^^^^^^
help: consider introducing a named lifetime parameter
|
LL | trait ZstAssert<'a>: Sized {
LL | const A: &str = "";
LL | const B: S<'a> = S { s: &() };
|

error[E0106]: missing lifetime specifier
--> $DIR/missing-lifetime-in-assoc-const-type.rs:4:15
|
LL | const C: &'_ str = "";
| ^^ expected named lifetime parameter
|
help: consider using the `'static` lifetime
|
LL | const C: &'static str = "";
| ^^^^^^^
help: consider introducing a named lifetime parameter
|
LL | trait ZstAssert<'a>: Sized {
LL | const A: &str = "";
LL | const B: S = S { s: &() };
LL | const C: &'a str = "";
|

error[E0106]: missing lifetime specifiers
--> $DIR/missing-lifetime-in-assoc-const-type.rs:5:14
|
LL | const D: T = T { a: &(), b: &() };
| ^ expected 2 lifetime parameters
|
help: consider using the `'static` lifetime
|
LL | const D: T<'static, 'static> = T { a: &(), b: &() };
| ^^^^^^^^^^^^^^^^^^
help: consider introducing a named lifetime parameter
|
LL | trait ZstAssert<'a>: Sized {
LL | const TYPE_NAME: &'a str = "";
LL | const A: &str = "";
LL | const B: S = S { s: &() };
LL | const C: &'_ str = "";
LL | const D: T<'a, 'a> = T { a: &(), b: &() };
|

error: aborting due to previous error
error: aborting due to 4 previous errors

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

0 comments on commit 6a3deb0

Please sign in to comment.