diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2020-08-11 13:02:14 -0700 |
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2020-08-11 13:02:14 -0700 |
| commit | 6a3deb0ae04c4cb6400b30fecd1cbbee0506348b (patch) | |
| tree | f8fbe36545beda6580ad94cc5f0742cfb7d95965 | |
| parent | becd479482935a63633861595e276bae6533b25b (diff) | |
| download | rust-6a3deb0ae04c4cb6400b30fecd1cbbee0506348b.tar.gz rust-6a3deb0ae04c4cb6400b30fecd1cbbee0506348b.zip | |
Suggest using `'static` in assoc consts and suggest when multiple lts are needed
| -rw-r--r-- | src/librustc_resolve/late/diagnostics.rs | 54 | ||||
| -rw-r--r-- | src/librustc_resolve/late/lifetimes.rs | 12 | ||||
| -rw-r--r-- | src/test/ui/error-codes/E0106.stderr | 9 | ||||
| -rw-r--r-- | src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.rs | 13 | ||||
| -rw-r--r-- | src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr | 68 |
5 files changed, 144 insertions, 12 deletions
diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs index 9dbde5e7852..6e7a004f853 100644 --- a/src/librustc_resolve/late/diagnostics.rs +++ b/src/librustc_resolve/late/diagnostics.rs @@ -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 { @@ -1186,6 +1187,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { https://doc.rust-lang.org/nomicon/hrtb.html", ); } + _ => {} } } if nightly_options::is_nightly_build() @@ -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) { @@ -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 => { diff --git a/src/librustc_resolve/late/lifetimes.rs b/src/librustc_resolve/late/lifetimes.rs index e5accc7fde9..2046419d984 100644 --- a/src/librustc_resolve/late/lifetimes.rs +++ b/src/librustc_resolve/late/lifetimes.rs @@ -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); @@ -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) { diff --git a/src/test/ui/error-codes/E0106.stderr b/src/test/ui/error-codes/E0106.stderr index a23bcbfd71a..ac70e887626 100644 --- a/src/test/ui/error-codes/E0106.stderr +++ b/src/test/ui/error-codes/E0106.stderr @@ -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 diff --git a/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.rs b/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.rs index b9e0108fe71..38332627f4c 100644 --- a/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.rs +++ b/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() {} diff --git a/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr b/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr index ee9d1a15d2a..b20778ce208 100644 --- a/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr +++ b/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr @@ -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`. |
