From 6ba08755dfd9ddbb55248a0263a4e81d3602b410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 15 Jan 2020 18:34:30 -0800 Subject: [PATCH 1/6] 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. --- src/librustc_resolve/lib.rs | 1 + src/librustc_resolve/lifetimes.rs | 41 +++++- src/test/ui/error-codes/E0261.stderr | 6 +- .../feature-gate-in_band_lifetimes.stderr | 118 ++++++++++++++++-- ...ssociated_type_undeclared_lifetimes.stderr | 18 +++ .../no_in_band_in_struct.stderr | 4 + .../no_introducing_in_band_in_locals.stderr | 2 + ...ethod-call-lifetime-args-unresolved.stderr | 2 + .../parser/trait-object-trait-parens.stderr | 3 + src/test/ui/regions/regions-in-enums.stderr | 4 + src/test/ui/regions/regions-in-structs.stderr | 5 + .../ui/regions/regions-name-undeclared.stderr | 46 ++++++- src/test/ui/regions/regions-undeclared.stderr | 11 +- .../where-lifetime-resolution.stderr | 6 + 14 files changed, 249 insertions(+), 18 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 60a0049f5da37..29872be47c2f3 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -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}; diff --git a/src/librustc_resolve/lifetimes.rs b/src/librustc_resolve/lifetimes.rs index 5fae8f3318743..f8e2f0cafff02 100644 --- a/src/librustc_resolve/lifetimes.rs +++ b/src/librustc_resolve/lifetimes.rs @@ -183,6 +183,10 @@ struct LifetimeContext<'a, 'tcx> { xcrate_object_lifetime_defaults: DefIdMap>, lifetime_uses: &'a mut DefIdMap>, + + /// 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(); } } diff --git a/src/test/ui/error-codes/E0261.stderr b/src/test/ui/error-codes/E0261.stderr index 3bf5e9d815485..0eab2dc0ee05f 100644 --- a/src/test/ui/error-codes/E0261.stderr +++ b/src/test/ui/error-codes/E0261.stderr @@ -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 diff --git a/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr b/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr index 5c64bf6539c91..bbf3ea8a89f23 100644 --- a/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr +++ b/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr @@ -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 diff --git a/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr b/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr index 81137e81dc489..fc2ce1cb866bb 100644 --- a/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr +++ b/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr @@ -3,12 +3,30 @@ error[E0261]: use of undeclared lifetime name `'b` | LL | + Deref>; | ^^ undeclared lifetime + | +help: consider introducing lifetime `'b` here + | +LL | trait Iterable<'b> { + | ^^^^ +help: consider introducing lifetime `'b` here + | +LL | type Iter<'b, 'a>: Iterator> + | ^^^ 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 diff --git a/src/test/ui/in-band-lifetimes/no_in_band_in_struct.stderr b/src/test/ui/in-band-lifetimes/no_in_band_in_struct.stderr index a270dd03926dc..fe656f7af7e01 100644 --- a/src/test/ui/in-band-lifetimes/no_in_band_in_struct.stderr +++ b/src/test/ui/in-band-lifetimes/no_in_band_in_struct.stderr @@ -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 diff --git a/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr b/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr index c307066be6b46..bfb20ade035cf 100644 --- a/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr +++ b/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr @@ -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 diff --git a/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr b/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr index 67fd8d7a13eb1..c9f235c4f7df7 100644 --- a/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr +++ b/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr @@ -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 diff --git a/src/test/ui/parser/trait-object-trait-parens.stderr b/src/test/ui/parser/trait-object-trait-parens.stderr index 03fb764ee0384..4b9f49423cbf4 100644 --- a/src/test/ui/parser/trait-object-trait-parens.stderr +++ b/src/test/ui/parser/trait-object-trait-parens.stderr @@ -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 diff --git a/src/test/ui/regions/regions-in-enums.stderr b/src/test/ui/regions/regions-in-enums.stderr index cfed9feba4b82..66537653291c7 100644 --- a/src/test/ui/regions/regions-in-enums.stderr +++ b/src/test/ui/regions/regions-in-enums.stderr @@ -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 diff --git a/src/test/ui/regions/regions-in-structs.stderr b/src/test/ui/regions/regions-in-structs.stderr index 8314942759d1a..5dfdc2ee93b43 100644 --- a/src/test/ui/regions/regions-in-structs.stderr +++ b/src/test/ui/regions/regions-in-structs.stderr @@ -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 diff --git a/src/test/ui/regions/regions-name-undeclared.stderr b/src/test/ui/regions/regions-name-undeclared.stderr index 5f6a48a35f368..79ebef41dccd6 100644 --- a/src/test/ui/regions/regions-name-undeclared.stderr +++ b/src/test/ui/regions/regions-name-undeclared.stderr @@ -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 diff --git a/src/test/ui/regions/regions-undeclared.stderr b/src/test/ui/regions/regions-undeclared.stderr index 495aec3fde5f1..6bfde5524ac49 100644 --- a/src/test/ui/regions/regions-undeclared.stderr +++ b/src/test/ui/regions/regions-undeclared.stderr @@ -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 diff --git a/src/test/ui/where-clauses/where-lifetime-resolution.stderr b/src/test/ui/where-clauses/where-lifetime-resolution.stderr index 0081ae07163b3..49799a93017eb 100644 --- a/src/test/ui/where-clauses/where-lifetime-resolution.stderr +++ b/src/test/ui/where-clauses/where-lifetime-resolution.stderr @@ -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 From 78d3ea5484c3ebcc49bddba39f5b5be5f99b8c65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 15 Jan 2020 18:35:48 -0800 Subject: [PATCH 2/6] When encountering an expected named lifetime and none are present, suggest adding one --- src/librustc_resolve/lifetimes.rs | 82 ++++++++++++++++--- src/test/ui/error-codes/E0106.rs | 2 +- src/test/ui/error-codes/E0106.stderr | 32 +++++++- .../assoc-type.stderr | 14 +++- ...anon-lifetime-in-struct-declaration.stderr | 7 +- src/test/ui/issues/issue-19707.stderr | 12 ++- src/test/ui/issues/issue-26638.stderr | 6 +- src/test/ui/issues/issue-30255.stderr | 18 +++- ...urn-type-requires-explicit-lifetime.stderr | 12 ++- .../ex1b-return-no-names-if-else.stderr | 6 +- src/test/ui/proc-macro/item-error.stderr | 8 +- .../ui/regions/regions-in-enums-anon.stderr | 8 +- .../ui/regions/regions-in-structs-anon.stderr | 8 +- src/test/ui/rfc1623.stderr | 4 +- ...oxed-closure-sugar-lifetime-elision.stderr | 11 ++- .../dyn-trait-underscore-in-struct.stderr | 8 +- .../in-fn-return-illegal.stderr | 6 +- .../ui/underscore-lifetime/in-struct.stderr | 16 +++- .../underscore-lifetime-binders.stderr | 8 +- 19 files changed, 229 insertions(+), 39 deletions(-) diff --git a/src/librustc_resolve/lifetimes.rs b/src/librustc_resolve/lifetimes.rs index f8e2f0cafff02..345e5184e84b6 100644 --- a/src/librustc_resolve/lifetimes.rs +++ b/src/librustc_resolve/lifetimes.rs @@ -2398,6 +2398,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { lifetime_refs.len(), &lifetime_names, self.tcx.sess.source_map().span_to_snippet(span).ok().as_ref().map(|s| s.as_str()), + &self.missing_named_lifetime_spots, ); } @@ -2908,19 +2909,80 @@ fn add_missing_lifetime_specifiers_label( count: usize, lifetime_names: &FxHashSet, snippet: Option<&str>, + missing_named_lifetime_spots: &[&hir::Generics<'_>], ) { if count > 1 { err.span_label(span, format!("expected {} lifetime parameters", count)); - } else if let (1, Some(name), Some("&")) = - (lifetime_names.len(), lifetime_names.iter().next(), snippet) - { - err.span_suggestion( - span, - "consider using the named lifetime", - format!("&{} ", name), - Applicability::MaybeIncorrect, - ); } else { - err.span_label(span, "expected lifetime parameter"); + let mut introduce_suggestion = vec![]; + if let Some(generics) = missing_named_lifetime_spots.iter().last() { + introduce_suggestion.push(match &generics.params { + [] => (generics.span, "<'lifetime>".to_string()), + [param, ..] => (param.span.shrink_to_lo(), "'lifetime, ".to_string()), + }); + } + + match (lifetime_names.len(), lifetime_names.iter().next(), snippet) { + (1, Some(name), Some("&")) => { + err.span_suggestion( + span, + "consider using the named lifetime", + format!("&{} ", name), + Applicability::MaybeIncorrect, + ); + } + (1, Some(name), Some("'_")) => { + err.span_suggestion( + span, + "consider using the named lifetime", + name.to_string(), + Applicability::MaybeIncorrect, + ); + } + (1, Some(name), Some(snippet)) if !snippet.ends_with(">") => { + err.span_suggestion( + span, + "consider using the named lifetime", + format!("{}<{}>", snippet, name), + Applicability::MaybeIncorrect, + ); + } + (0, _, Some("&")) => { + err.span_label(span, "expected named lifetime parameter"); + if !introduce_suggestion.is_empty() { + introduce_suggestion.push((span, "&'lifetime ".to_string())); + err.multipart_suggestion( + "consider introducing a named lifetime", + introduce_suggestion, + Applicability::MaybeIncorrect, + ); + } + } + (0, _, Some("'_")) => { + err.span_label(span, "expected named lifetime parameter"); + if !introduce_suggestion.is_empty() { + introduce_suggestion.push((span, "'lifetime".to_string())); + err.multipart_suggestion( + "consider introducing a named lifetime", + introduce_suggestion, + Applicability::MaybeIncorrect, + ); + } + } + (0, _, Some(snippet)) if !snippet.ends_with(">") => { + err.span_label(span, "expected named lifetime parameter"); + if !introduce_suggestion.is_empty() { + introduce_suggestion.push((span, format!("{}<'lifetime>", snippet))); + err.multipart_suggestion( + "consider introducing a named lifetime", + introduce_suggestion, + Applicability::MaybeIncorrect, + ); + } + } + _ => { + err.span_label(span, "expected lifetime parameter"); + } + } } } diff --git a/src/test/ui/error-codes/E0106.rs b/src/test/ui/error-codes/E0106.rs index d6537d123637c..cc3438727a817 100644 --- a/src/test/ui/error-codes/E0106.rs +++ b/src/test/ui/error-codes/E0106.rs @@ -16,7 +16,7 @@ struct Buzz<'a, 'b>(&'a str, &'b str); struct Quux { baz: Baz, //~^ ERROR E0106 - //~| expected lifetime parameter + //~| expected named lifetime parameter buzz: Buzz, //~^ ERROR E0106 //~| expected 2 lifetime parameters diff --git a/src/test/ui/error-codes/E0106.stderr b/src/test/ui/error-codes/E0106.stderr index cea9581e70138..bb7efa90c8002 100644 --- a/src/test/ui/error-codes/E0106.stderr +++ b/src/test/ui/error-codes/E0106.stderr @@ -2,25 +2,49 @@ error[E0106]: missing lifetime specifier --> $DIR/E0106.rs:2:8 | LL | x: &bool, - | ^ expected lifetime parameter + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | struct Foo<'lifetime> { +LL | x: &'lifetime bool, + | error[E0106]: missing lifetime specifier --> $DIR/E0106.rs:7:7 | LL | B(&bool), - | ^ expected lifetime parameter + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | enum Bar<'lifetime> { +LL | A(u8), +LL | B(&'lifetime bool), + | error[E0106]: missing lifetime specifier --> $DIR/E0106.rs:10:14 | LL | type MyStr = &str; - | ^ expected lifetime parameter + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | type MyStr<'lifetime> = &'lifetime str; + | ^^^^^^^^^^^ ^^^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/E0106.rs:17:10 | LL | baz: Baz, - | ^^^ expected lifetime parameter + | ^^^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | struct Quux<'lifetime> { +LL | baz: Baz<'lifetime>, + | error[E0106]: missing lifetime specifiers --> $DIR/E0106.rs:20:11 diff --git a/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr b/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr index 492ca872187e0..0835970df40f5 100644 --- a/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr +++ b/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr @@ -2,13 +2,23 @@ error[E0106]: missing lifetime specifier --> $DIR/assoc-type.rs:11:19 | LL | type Output = &i32; - | ^ expected lifetime parameter + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | type Output<'lifetime> = &'lifetime i32; + | ^^^^^^^^^^^ ^^^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/assoc-type.rs:16:20 | LL | type Output = &'_ i32; - | ^^ expected lifetime parameter + | ^^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | type Output<'lifetime> = &'lifetime i32; + | ^^^^^^^^^^^ ^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr b/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr index 9579abb76b32f..32507e21d27b5 100644 --- a/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr +++ b/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr @@ -2,7 +2,12 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-61124-anon-lifetime-in-struct-declaration.rs:8:19 | LL | struct Heartbreak(Betrayal); - | ^^^^^^^^ expected lifetime parameter + | ^^^^^^^^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | struct Heartbreak<'lifetime>(Betrayal<'lifetime>); + | ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-19707.stderr b/src/test/ui/issues/issue-19707.stderr index c85ce0eb3a75e..51a8aabb48307 100644 --- a/src/test/ui/issues/issue-19707.stderr +++ b/src/test/ui/issues/issue-19707.stderr @@ -2,17 +2,25 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-19707.rs:3:28 | LL | type Foo = fn(&u8, &u8) -> &u8; - | ^ expected lifetime parameter + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 +help: consider introducing a named lifetime + | +LL | type Foo<'lifetime> = fn(&u8, &u8) -> &'lifetime u8; + | ^^^^^^^^^^^ ^^^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/issue-19707.rs:5:27 | LL | fn bar &u8>(f: &F) {} - | ^ expected lifetime parameter + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 +help: consider introducing a named lifetime + | +LL | fn bar<'lifetime, F: Fn(&u8, &u8) -> &'lifetime u8>(f: &F) {} + | ^^^^^^^^^^ ^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-26638.stderr b/src/test/ui/issues/issue-26638.stderr index 6d7c1b0c43fce..8396c932c5b43 100644 --- a/src/test/ui/issues/issue-26638.stderr +++ b/src/test/ui/issues/issue-26638.stderr @@ -2,9 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-26638.rs:1:62 | LL | fn parse_type(iter: Box+'static>) -> &str { iter.next() } - | ^ expected lifetime parameter + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say which one of `iter`'s 2 lifetimes it is borrowed from +help: consider introducing a named lifetime + | +LL | fn parse_type<'lifetime>(iter: Box+'static>) -> &'lifetime str { iter.next() } + | ^^^^^^^^^^^ ^^^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/issue-26638.rs:4:40 diff --git a/src/test/ui/issues/issue-30255.stderr b/src/test/ui/issues/issue-30255.stderr index c53129b7f2967..64f89496caaa3 100644 --- a/src/test/ui/issues/issue-30255.stderr +++ b/src/test/ui/issues/issue-30255.stderr @@ -2,25 +2,37 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-30255.rs:9:24 | LL | fn f(a: &S, b: i32) -> &i32 { - | ^ expected lifetime parameter + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say which one of `a`'s 2 lifetimes it is borrowed from +help: consider introducing a named lifetime + | +LL | fn f<'lifetime>(a: &S, b: i32) -> &'lifetime i32 { + | ^^^^^^^^^^^ ^^^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/issue-30255.rs:14:34 | LL | fn g(a: &S, b: bool, c: &i32) -> &i32 { - | ^ expected lifetime parameter + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `a`'s 2 lifetimes or `c` +help: consider introducing a named lifetime + | +LL | fn g<'lifetime>(a: &S, b: bool, c: &i32) -> &'lifetime i32 { + | ^^^^^^^^^^^ ^^^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/issue-30255.rs:19:44 | LL | fn h(a: &bool, b: bool, c: &S, d: &i32) -> &i32 { - | ^ expected lifetime parameter + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a`, one of `c`'s 2 lifetimes, or `d` +help: consider introducing a named lifetime + | +LL | fn h<'lifetime>(a: &bool, b: bool, c: &S, d: &i32) -> &'lifetime i32 { + | ^^^^^^^^^^^ ^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr index 3f7c3934a0ba2..075ea3c691fca 100644 --- a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr +++ b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr @@ -10,17 +10,25 @@ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:7:33 | LL | fn g(_x: &isize, _y: &isize) -> &isize { - | ^ expected lifetime parameter + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `_x` or `_y` +help: consider introducing a named lifetime + | +LL | fn g<'lifetime>(_x: &isize, _y: &isize) -> &'lifetime isize { + | ^^^^^^^^^^^ ^^^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:17:19 | LL | fn h(_x: &Foo) -> &isize { - | ^ expected lifetime parameter + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say which one of `_x`'s 2 lifetimes it is borrowed from +help: consider introducing a named lifetime + | +LL | fn h<'lifetime>(_x: &Foo) -> &'lifetime isize { + | ^^^^^^^^^^^ ^^^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:21:20 diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr index a4e0d71a3fa6b..f95b4cb16be2f 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr @@ -2,9 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/ex1b-return-no-names-if-else.rs:1:29 | LL | fn foo(x: &i32, y: &i32) -> &i32 { - | ^ expected lifetime parameter + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` +help: consider introducing a named lifetime + | +LL | fn foo<'lifetime>(x: &i32, y: &i32) -> &'lifetime i32 { + | ^^^^^^^^^^^ ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/proc-macro/item-error.stderr b/src/test/ui/proc-macro/item-error.stderr index e801c26c43b9c..19bbadbcd4177 100644 --- a/src/test/ui/proc-macro/item-error.stderr +++ b/src/test/ui/proc-macro/item-error.stderr @@ -2,7 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/item-error.rs:10:8 | LL | a: &u64 - | ^ expected lifetime parameter + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | struct A<'lifetime> { +LL | a: &'lifetime u64 + | error: aborting due to previous error diff --git a/src/test/ui/regions/regions-in-enums-anon.stderr b/src/test/ui/regions/regions-in-enums-anon.stderr index ae06e7653dbeb..6e653452f552b 100644 --- a/src/test/ui/regions/regions-in-enums-anon.stderr +++ b/src/test/ui/regions/regions-in-enums-anon.stderr @@ -2,7 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/regions-in-enums-anon.rs:4:9 | LL | Bar(&isize) - | ^ expected lifetime parameter + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | enum Foo<'lifetime> { +LL | Bar(&'lifetime isize) + | error: aborting due to previous error diff --git a/src/test/ui/regions/regions-in-structs-anon.stderr b/src/test/ui/regions/regions-in-structs-anon.stderr index a1d4ebb597b4c..b40990e3edbed 100644 --- a/src/test/ui/regions/regions-in-structs-anon.stderr +++ b/src/test/ui/regions/regions-in-structs-anon.stderr @@ -2,7 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/regions-in-structs-anon.rs:4:8 | LL | x: &isize - | ^ expected lifetime parameter + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | struct Foo<'lifetime> { +LL | x: &'lifetime isize + | error: aborting due to previous error diff --git a/src/test/ui/rfc1623.stderr b/src/test/ui/rfc1623.stderr index 171c00ba7b813..5b665e181412a 100644 --- a/src/test/ui/rfc1623.stderr +++ b/src/test/ui/rfc1623.stderr @@ -2,7 +2,7 @@ error[E0106]: missing lifetime specifier --> $DIR/rfc1623.rs:8:42 | LL | static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = - | ^ expected lifetime parameter + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 @@ -10,7 +10,7 @@ error[E0106]: missing lifetime specifier --> $DIR/rfc1623.rs:10:39 | LL | &(non_elidable as fn(&u8, &u8) -> &u8); - | ^ expected lifetime parameter + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr index 9fb9a07166f84..3b101bf304a7d 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr @@ -2,9 +2,18 @@ error[E0106]: missing lifetime specifier --> $DIR/unboxed-closure-sugar-lifetime-elision.rs:26:39 | LL | let _: dyn Foo(&isize, &usize) -> &usize; - | ^ expected lifetime parameter + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 +help: consider introducing a named lifetime + | +LL | fn main<'lifetime>() { +LL | eq::< dyn for<'a> Foo<(&'a isize,), Output=&'a isize>, +LL | dyn Foo(&isize) -> &isize >(); +LL | eq::< dyn for<'a> Foo<(&'a isize,), Output=(&'a isize, &'a isize)>, +LL | dyn Foo(&isize) -> (&isize, &isize) >(); +LL | + ... error: aborting due to previous error diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr index b20c23ade2b78..c06891d2308ca 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr @@ -2,7 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/dyn-trait-underscore-in-struct.rs:9:24 | LL | x: Box, - | ^^ expected lifetime parameter + | ^^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | struct Foo<'lifetime> { +LL | x: Box, + | error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound --> $DIR/dyn-trait-underscore-in-struct.rs:9:12 diff --git a/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr b/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr index ed61bdfdddab3..bdfb8ce4d83d4 100644 --- a/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr +++ b/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr @@ -2,9 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/in-fn-return-illegal.rs:5:30 | LL | fn foo(x: &u32, y: &u32) -> &'_ u32 { loop { } } - | ^^ expected lifetime parameter + | ^^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` +help: consider introducing a named lifetime + | +LL | fn foo<'lifetime>(x: &u32, y: &u32) -> &'lifetime u32 { loop { } } + | ^^^^^^^^^^^ ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/underscore-lifetime/in-struct.stderr b/src/test/ui/underscore-lifetime/in-struct.stderr index 6bbdc71195a50..46dc3f899a140 100644 --- a/src/test/ui/underscore-lifetime/in-struct.stderr +++ b/src/test/ui/underscore-lifetime/in-struct.stderr @@ -2,13 +2,25 @@ error[E0106]: missing lifetime specifier --> $DIR/in-struct.rs:6:9 | LL | x: &'_ u32, - | ^^ expected lifetime parameter + | ^^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | struct Foo<'lifetime> { +LL | x: &'lifetime u32, + | error[E0106]: missing lifetime specifier --> $DIR/in-struct.rs:10:14 | LL | Variant(&'_ u32), - | ^^ expected lifetime parameter + | ^^ expected named lifetime parameter + | +help: consider introducing a named lifetime + | +LL | enum Bar<'lifetime> { +LL | Variant(&'lifetime u32), + | error: aborting due to 2 previous errors diff --git a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr index ef9e7e39df0bc..6c2159bc66169 100644 --- a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr +++ b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr @@ -14,7 +14,7 @@ error[E0106]: missing lifetime specifier --> $DIR/underscore-lifetime-binders.rs:2:17 | LL | struct Baz<'a>(&'_ &'a u8); - | ^^ expected lifetime parameter + | ^^ help: consider using the named lifetime: `'a` error[E0106]: missing lifetime specifier --> $DIR/underscore-lifetime-binders.rs:10:33 @@ -28,9 +28,13 @@ error[E0106]: missing lifetime specifier --> $DIR/underscore-lifetime-binders.rs:16:35 | LL | fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y } - | ^^ expected lifetime parameter + | ^^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or `y` +help: consider introducing a named lifetime + | +LL | fn foo2<'lifetime>(_: &'_ u8, y: &'_ u8) -> &'lifetime u8 { y } + | ^^^^^^^^^^^ ^^^^^^^^^ error: aborting due to 5 previous errors From 2102723887cbd3253dace65f4574422be516259c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 16 Jan 2020 22:05:31 -0800 Subject: [PATCH 3/6] review comments --- src/librustc_resolve/lifetimes.rs | 6 +++--- src/test/ui/error-codes/E0106.stderr | 8 ++++---- .../ui/impl-header-lifetime-elision/assoc-type.stderr | 4 ++-- ...issue-61124-anon-lifetime-in-struct-declaration.stderr | 2 +- src/test/ui/issues/issue-19707.stderr | 4 ++-- src/test/ui/issues/issue-26638.stderr | 2 +- src/test/ui/issues/issue-30255.stderr | 6 +++--- ...-elision-return-type-requires-explicit-lifetime.stderr | 4 ++-- .../lifetime-errors/ex1b-return-no-names-if-else.stderr | 2 +- src/test/ui/proc-macro/item-error.stderr | 2 +- src/test/ui/regions/regions-in-enums-anon.stderr | 2 +- src/test/ui/regions/regions-in-structs-anon.stderr | 2 +- .../unboxed-closure-sugar-lifetime-elision.stderr | 2 +- .../dyn-trait-underscore-in-struct.stderr | 2 +- .../ui/underscore-lifetime/in-fn-return-illegal.stderr | 2 +- src/test/ui/underscore-lifetime/in-struct.stderr | 4 ++-- .../underscore-lifetime-binders.stderr | 2 +- 17 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/librustc_resolve/lifetimes.rs b/src/librustc_resolve/lifetimes.rs index 345e5184e84b6..1fb35ca26d6f8 100644 --- a/src/librustc_resolve/lifetimes.rs +++ b/src/librustc_resolve/lifetimes.rs @@ -2952,7 +2952,7 @@ fn add_missing_lifetime_specifiers_label( if !introduce_suggestion.is_empty() { introduce_suggestion.push((span, "&'lifetime ".to_string())); err.multipart_suggestion( - "consider introducing a named lifetime", + "consider introducing a named lifetime parameter", introduce_suggestion, Applicability::MaybeIncorrect, ); @@ -2963,7 +2963,7 @@ fn add_missing_lifetime_specifiers_label( if !introduce_suggestion.is_empty() { introduce_suggestion.push((span, "'lifetime".to_string())); err.multipart_suggestion( - "consider introducing a named lifetime", + "consider introducing a named lifetime parameter", introduce_suggestion, Applicability::MaybeIncorrect, ); @@ -2974,7 +2974,7 @@ fn add_missing_lifetime_specifiers_label( if !introduce_suggestion.is_empty() { introduce_suggestion.push((span, format!("{}<'lifetime>", snippet))); err.multipart_suggestion( - "consider introducing a named lifetime", + "consider introducing a named lifetime parameter", introduce_suggestion, Applicability::MaybeIncorrect, ); diff --git a/src/test/ui/error-codes/E0106.stderr b/src/test/ui/error-codes/E0106.stderr index bb7efa90c8002..e01e0a6f54b07 100644 --- a/src/test/ui/error-codes/E0106.stderr +++ b/src/test/ui/error-codes/E0106.stderr @@ -4,7 +4,7 @@ error[E0106]: missing lifetime specifier LL | x: &bool, | ^ expected named lifetime parameter | -help: consider introducing a named lifetime +help: consider introducing a named lifetime parameter | LL | struct Foo<'lifetime> { LL | x: &'lifetime bool, @@ -16,7 +16,7 @@ error[E0106]: missing lifetime specifier LL | B(&bool), | ^ expected named lifetime parameter | -help: consider introducing a named lifetime +help: consider introducing a named lifetime parameter | LL | enum Bar<'lifetime> { LL | A(u8), @@ -29,7 +29,7 @@ error[E0106]: missing lifetime specifier LL | type MyStr = &str; | ^ expected named lifetime parameter | -help: consider introducing a named lifetime +help: consider introducing a named lifetime parameter | LL | type MyStr<'lifetime> = &'lifetime str; | ^^^^^^^^^^^ ^^^^^^^^^^ @@ -40,7 +40,7 @@ error[E0106]: missing lifetime specifier LL | baz: Baz, | ^^^ expected named lifetime parameter | -help: consider introducing a named lifetime +help: consider introducing a named lifetime parameter | LL | struct Quux<'lifetime> { LL | baz: Baz<'lifetime>, diff --git a/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr b/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr index 0835970df40f5..14c53f906654b 100644 --- a/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr +++ b/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr @@ -4,7 +4,7 @@ error[E0106]: missing lifetime specifier LL | type Output = &i32; | ^ expected named lifetime parameter | -help: consider introducing a named lifetime +help: consider introducing a named lifetime parameter | LL | type Output<'lifetime> = &'lifetime i32; | ^^^^^^^^^^^ ^^^^^^^^^^ @@ -15,7 +15,7 @@ error[E0106]: missing lifetime specifier LL | type Output = &'_ i32; | ^^ expected named lifetime parameter | -help: consider introducing a named lifetime +help: consider introducing a named lifetime parameter | LL | type Output<'lifetime> = &'lifetime i32; | ^^^^^^^^^^^ ^^^^^^^^^ diff --git a/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr b/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr index 32507e21d27b5..5f101a24c1d43 100644 --- a/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr +++ b/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr @@ -4,7 +4,7 @@ error[E0106]: missing lifetime specifier LL | struct Heartbreak(Betrayal); | ^^^^^^^^ expected named lifetime parameter | -help: consider introducing a named lifetime +help: consider introducing a named lifetime parameter | LL | struct Heartbreak<'lifetime>(Betrayal<'lifetime>); | ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/issues/issue-19707.stderr b/src/test/ui/issues/issue-19707.stderr index 51a8aabb48307..8a627bc0bd4de 100644 --- a/src/test/ui/issues/issue-19707.stderr +++ b/src/test/ui/issues/issue-19707.stderr @@ -5,7 +5,7 @@ LL | type Foo = fn(&u8, &u8) -> &u8; | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 -help: consider introducing a named lifetime +help: consider introducing a named lifetime parameter | LL | type Foo<'lifetime> = fn(&u8, &u8) -> &'lifetime u8; | ^^^^^^^^^^^ ^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | fn bar &u8>(f: &F) {} | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 -help: consider introducing a named lifetime +help: consider introducing a named lifetime parameter | LL | fn bar<'lifetime, F: Fn(&u8, &u8) -> &'lifetime u8>(f: &F) {} | ^^^^^^^^^^ ^^^^^^^^^^ diff --git a/src/test/ui/issues/issue-26638.stderr b/src/test/ui/issues/issue-26638.stderr index 8396c932c5b43..85d5d9cc42e9a 100644 --- a/src/test/ui/issues/issue-26638.stderr +++ b/src/test/ui/issues/issue-26638.stderr @@ -5,7 +5,7 @@ LL | fn parse_type(iter: Box+'static>) -> &str { iter.ne | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say which one of `iter`'s 2 lifetimes it is borrowed from -help: consider introducing a named lifetime +help: consider introducing a named lifetime parameter | LL | fn parse_type<'lifetime>(iter: Box+'static>) -> &'lifetime str { iter.next() } | ^^^^^^^^^^^ ^^^^^^^^^^ diff --git a/src/test/ui/issues/issue-30255.stderr b/src/test/ui/issues/issue-30255.stderr index 64f89496caaa3..c940227764099 100644 --- a/src/test/ui/issues/issue-30255.stderr +++ b/src/test/ui/issues/issue-30255.stderr @@ -5,7 +5,7 @@ LL | fn f(a: &S, b: i32) -> &i32 { | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say which one of `a`'s 2 lifetimes it is borrowed from -help: consider introducing a named lifetime +help: consider introducing a named lifetime parameter | LL | fn f<'lifetime>(a: &S, b: i32) -> &'lifetime i32 { | ^^^^^^^^^^^ ^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | fn g(a: &S, b: bool, c: &i32) -> &i32 { | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `a`'s 2 lifetimes or `c` -help: consider introducing a named lifetime +help: consider introducing a named lifetime parameter | LL | fn g<'lifetime>(a: &S, b: bool, c: &i32) -> &'lifetime i32 { | ^^^^^^^^^^^ ^^^^^^^^^^ @@ -29,7 +29,7 @@ LL | fn h(a: &bool, b: bool, c: &S, d: &i32) -> &i32 { | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a`, one of `c`'s 2 lifetimes, or `d` -help: consider introducing a named lifetime +help: consider introducing a named lifetime parameter | LL | fn h<'lifetime>(a: &bool, b: bool, c: &S, d: &i32) -> &'lifetime i32 { | ^^^^^^^^^^^ ^^^^^^^^^^ diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr index 075ea3c691fca..1d5eeac23f96a 100644 --- a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr +++ b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr @@ -13,7 +13,7 @@ LL | fn g(_x: &isize, _y: &isize) -> &isize { | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `_x` or `_y` -help: consider introducing a named lifetime +help: consider introducing a named lifetime parameter | LL | fn g<'lifetime>(_x: &isize, _y: &isize) -> &'lifetime isize { | ^^^^^^^^^^^ ^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | fn h(_x: &Foo) -> &isize { | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say which one of `_x`'s 2 lifetimes it is borrowed from -help: consider introducing a named lifetime +help: consider introducing a named lifetime parameter | LL | fn h<'lifetime>(_x: &Foo) -> &'lifetime isize { | ^^^^^^^^^^^ ^^^^^^^^^^ diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr index f95b4cb16be2f..2990ab8682434 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr @@ -5,7 +5,7 @@ LL | fn foo(x: &i32, y: &i32) -> &i32 { | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` -help: consider introducing a named lifetime +help: consider introducing a named lifetime parameter | LL | fn foo<'lifetime>(x: &i32, y: &i32) -> &'lifetime i32 { | ^^^^^^^^^^^ ^^^^^^^^^^ diff --git a/src/test/ui/proc-macro/item-error.stderr b/src/test/ui/proc-macro/item-error.stderr index 19bbadbcd4177..01eadbe252e9f 100644 --- a/src/test/ui/proc-macro/item-error.stderr +++ b/src/test/ui/proc-macro/item-error.stderr @@ -4,7 +4,7 @@ error[E0106]: missing lifetime specifier LL | a: &u64 | ^ expected named lifetime parameter | -help: consider introducing a named lifetime +help: consider introducing a named lifetime parameter | LL | struct A<'lifetime> { LL | a: &'lifetime u64 diff --git a/src/test/ui/regions/regions-in-enums-anon.stderr b/src/test/ui/regions/regions-in-enums-anon.stderr index 6e653452f552b..41655a210b3c0 100644 --- a/src/test/ui/regions/regions-in-enums-anon.stderr +++ b/src/test/ui/regions/regions-in-enums-anon.stderr @@ -4,7 +4,7 @@ error[E0106]: missing lifetime specifier LL | Bar(&isize) | ^ expected named lifetime parameter | -help: consider introducing a named lifetime +help: consider introducing a named lifetime parameter | LL | enum Foo<'lifetime> { LL | Bar(&'lifetime isize) diff --git a/src/test/ui/regions/regions-in-structs-anon.stderr b/src/test/ui/regions/regions-in-structs-anon.stderr index b40990e3edbed..fbe8036880f48 100644 --- a/src/test/ui/regions/regions-in-structs-anon.stderr +++ b/src/test/ui/regions/regions-in-structs-anon.stderr @@ -4,7 +4,7 @@ error[E0106]: missing lifetime specifier LL | x: &isize | ^ expected named lifetime parameter | -help: consider introducing a named lifetime +help: consider introducing a named lifetime parameter | LL | struct Foo<'lifetime> { LL | x: &'lifetime isize diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr index 3b101bf304a7d..0a028e44919a6 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr @@ -5,7 +5,7 @@ LL | let _: dyn Foo(&isize, &usize) -> &usize; | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 -help: consider introducing a named lifetime +help: consider introducing a named lifetime parameter | LL | fn main<'lifetime>() { LL | eq::< dyn for<'a> Foo<(&'a isize,), Output=&'a isize>, diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr index c06891d2308ca..04df2e4570396 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr @@ -4,7 +4,7 @@ error[E0106]: missing lifetime specifier LL | x: Box, | ^^ expected named lifetime parameter | -help: consider introducing a named lifetime +help: consider introducing a named lifetime parameter | LL | struct Foo<'lifetime> { LL | x: Box, diff --git a/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr b/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr index bdfb8ce4d83d4..cf820249c80af 100644 --- a/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr +++ b/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr @@ -5,7 +5,7 @@ LL | fn foo(x: &u32, y: &u32) -> &'_ u32 { loop { } } | ^^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` -help: consider introducing a named lifetime +help: consider introducing a named lifetime parameter | LL | fn foo<'lifetime>(x: &u32, y: &u32) -> &'lifetime u32 { loop { } } | ^^^^^^^^^^^ ^^^^^^^^^ diff --git a/src/test/ui/underscore-lifetime/in-struct.stderr b/src/test/ui/underscore-lifetime/in-struct.stderr index 46dc3f899a140..e01b39a4b64f4 100644 --- a/src/test/ui/underscore-lifetime/in-struct.stderr +++ b/src/test/ui/underscore-lifetime/in-struct.stderr @@ -4,7 +4,7 @@ error[E0106]: missing lifetime specifier LL | x: &'_ u32, | ^^ expected named lifetime parameter | -help: consider introducing a named lifetime +help: consider introducing a named lifetime parameter | LL | struct Foo<'lifetime> { LL | x: &'lifetime u32, @@ -16,7 +16,7 @@ error[E0106]: missing lifetime specifier LL | Variant(&'_ u32), | ^^ expected named lifetime parameter | -help: consider introducing a named lifetime +help: consider introducing a named lifetime parameter | LL | enum Bar<'lifetime> { LL | Variant(&'lifetime u32), diff --git a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr index 6c2159bc66169..517904ee62869 100644 --- a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr +++ b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr @@ -31,7 +31,7 @@ LL | fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y } | ^^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or `y` -help: consider introducing a named lifetime +help: consider introducing a named lifetime parameter | LL | fn foo2<'lifetime>(_: &'_ u8, y: &'_ u8) -> &'lifetime u8 { y } | ^^^^^^^^^^^ ^^^^^^^^^ From 12ff4d0bd633b44939b6bca4ec67b0eac2d8be42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 17 Jan 2020 15:59:07 -0800 Subject: [PATCH 4/6] review comments: use closures --- src/librustc_resolve/lifetimes.rs | 83 ++++++++++++------------------- 1 file changed, 31 insertions(+), 52 deletions(-) diff --git a/src/librustc_resolve/lifetimes.rs b/src/librustc_resolve/lifetimes.rs index 1fb35ca26d6f8..528f5aaf034c7 100644 --- a/src/librustc_resolve/lifetimes.rs +++ b/src/librustc_resolve/lifetimes.rs @@ -2914,71 +2914,50 @@ fn add_missing_lifetime_specifiers_label( if count > 1 { err.span_label(span, format!("expected {} lifetime parameters", count)); } else { - let mut introduce_suggestion = vec![]; - if let Some(generics) = missing_named_lifetime_spots.iter().last() { - introduce_suggestion.push(match &generics.params { - [] => (generics.span, "<'lifetime>".to_string()), - [param, ..] => (param.span.shrink_to_lo(), "'lifetime, ".to_string()), - }); - } + let suggest_existing = |err: &mut DiagnosticBuilder<'_>, sugg| { + err.span_suggestion( + span, + "consider using the named lifetime", + sugg, + Applicability::MaybeIncorrect, + ); + }; + let suggest_new = |err: &mut DiagnosticBuilder<'_>, sugg| { + err.span_label(span, "expected named lifetime parameter"); + + if let Some(generics) = missing_named_lifetime_spots.iter().last() { + let mut introduce_suggestion = vec![]; + introduce_suggestion.push(match &generics.params { + [] => (generics.span, "<'lifetime>".to_string()), + [param, ..] => (param.span.shrink_to_lo(), "'lifetime, ".to_string()), + }); + introduce_suggestion.push((span, sugg)); + err.multipart_suggestion( + "consider introducing a named lifetime parameter", + introduce_suggestion, + Applicability::MaybeIncorrect, + ); + } + }; match (lifetime_names.len(), lifetime_names.iter().next(), snippet) { (1, Some(name), Some("&")) => { - err.span_suggestion( - span, - "consider using the named lifetime", - format!("&{} ", name), - Applicability::MaybeIncorrect, - ); + suggest_existing(err, format!("&{} ", name)); } (1, Some(name), Some("'_")) => { - err.span_suggestion( - span, - "consider using the named lifetime", - name.to_string(), - Applicability::MaybeIncorrect, - ); + suggest_existing(err, name.to_string()); } (1, Some(name), Some(snippet)) if !snippet.ends_with(">") => { - err.span_suggestion( - span, - "consider using the named lifetime", - format!("{}<{}>", snippet, name), - Applicability::MaybeIncorrect, - ); + suggest_existing(err, format!("{}<{}>", snippet, name)); } (0, _, Some("&")) => { - err.span_label(span, "expected named lifetime parameter"); - if !introduce_suggestion.is_empty() { - introduce_suggestion.push((span, "&'lifetime ".to_string())); - err.multipart_suggestion( - "consider introducing a named lifetime parameter", - introduce_suggestion, - Applicability::MaybeIncorrect, - ); - } + suggest_new(err, "&'lifetime ".to_string()); } (0, _, Some("'_")) => { - err.span_label(span, "expected named lifetime parameter"); - if !introduce_suggestion.is_empty() { - introduce_suggestion.push((span, "'lifetime".to_string())); - err.multipart_suggestion( - "consider introducing a named lifetime parameter", - introduce_suggestion, - Applicability::MaybeIncorrect, - ); - } + suggest_new(err, "'lifetime".to_string()); } (0, _, Some(snippet)) if !snippet.ends_with(">") => { - err.span_label(span, "expected named lifetime parameter"); - if !introduce_suggestion.is_empty() { - introduce_suggestion.push((span, format!("{}<'lifetime>", snippet))); - err.multipart_suggestion( - "consider introducing a named lifetime parameter", - introduce_suggestion, - Applicability::MaybeIncorrect, - ); - } + suggest_new(err, format!("{}<'lifetime>", snippet)); } _ => { err.span_label(span, "expected lifetime parameter"); From 0a6b5538ad2bbe0eba55f35e120e896ef6c5c83f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 17 Jan 2020 16:03:11 -0800 Subject: [PATCH 5/6] Deal with stabilization of `feature(slice_patterns)` --- src/librustc_resolve/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 29872be47c2f3..96406bc9a8c81 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -11,7 +11,7 @@ #![feature(crate_visibility_modifier)] #![feature(label_break_value)] #![feature(nll)] -#![feature(slice_patterns)] +#![cfg_attr(bootstrap, feature(slice_patterns))] #![recursion_limit = "256"] pub use rustc_hir::def::{Namespace, PerNS}; From 03d7fed165a350c0b9acfbbaf76feae7014c97d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 19 Jan 2020 17:48:47 -0800 Subject: [PATCH 6/6] review comments --- src/librustc_resolve/diagnostics.rs | 74 ++++++++++++++++++++++++- src/librustc_resolve/lifetimes.rs | 83 +++-------------------------- 2 files changed, 81 insertions(+), 76 deletions(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index a433ae8ed676a..a85f787b67789 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -5,8 +5,9 @@ use rustc::bug; use rustc::session::Session; use rustc::ty::{self, DefIdTree}; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_feature::BUILTIN_ATTRIBUTES; +use rustc_hir as hir; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; @@ -1447,3 +1448,74 @@ crate fn show_candidates( } } } + +crate fn report_missing_lifetime_specifiers( + sess: &Session, + span: Span, + count: usize, +) -> DiagnosticBuilder<'_> { + struct_span_err!(sess, span, E0106, "missing lifetime specifier{}", pluralize!(count)) +} + +crate fn add_missing_lifetime_specifiers_label( + err: &mut DiagnosticBuilder<'_>, + span: Span, + count: usize, + lifetime_names: &FxHashSet, + snippet: Option<&str>, + missing_named_lifetime_spots: &[&hir::Generics<'_>], +) { + if count > 1 { + err.span_label(span, format!("expected {} lifetime parameters", count)); + } else { + let suggest_existing = |err: &mut DiagnosticBuilder<'_>, sugg| { + err.span_suggestion( + span, + "consider using the named lifetime", + sugg, + Applicability::MaybeIncorrect, + ); + }; + let suggest_new = |err: &mut DiagnosticBuilder<'_>, sugg| { + err.span_label(span, "expected named lifetime parameter"); + + if let Some(generics) = missing_named_lifetime_spots.iter().last() { + let mut introduce_suggestion = vec![]; + introduce_suggestion.push(match &generics.params { + [] => (generics.span, "<'lifetime>".to_string()), + [param, ..] => (param.span.shrink_to_lo(), "'lifetime, ".to_string()), + }); + introduce_suggestion.push((span, sugg)); + err.multipart_suggestion( + "consider introducing a named lifetime parameter", + introduce_suggestion, + Applicability::MaybeIncorrect, + ); + } + }; + + match (lifetime_names.len(), lifetime_names.iter().next(), snippet) { + (1, Some(name), Some("&")) => { + suggest_existing(err, format!("&{} ", name)); + } + (1, Some(name), Some("'_")) => { + suggest_existing(err, name.to_string()); + } + (1, Some(name), Some(snippet)) if !snippet.ends_with(">") => { + suggest_existing(err, format!("{}<{}>", snippet, name)); + } + (0, _, Some("&")) => { + suggest_new(err, "&'lifetime ".to_string()); + } + (0, _, Some("'_")) => { + suggest_new(err, "'lifetime".to_string()); + } + (0, _, Some(snippet)) if !snippet.ends_with(">") => { + suggest_new(err, format!("{}<'lifetime>", snippet)); + } + _ => { + err.span_label(span, "expected lifetime parameter"); + } + } + } +} diff --git a/src/librustc_resolve/lifetimes.rs b/src/librustc_resolve/lifetimes.rs index 528f5aaf034c7..1c667d1467de0 100644 --- a/src/librustc_resolve/lifetimes.rs +++ b/src/librustc_resolve/lifetimes.rs @@ -5,14 +5,16 @@ //! used between functions, and they operate in a purely top-down //! way. Therefore, we break lifetime name resolution into a separate pass. +use crate::diagnostics::{ + add_missing_lifetime_specifiers_label, report_missing_lifetime_specifiers, +}; use rustc::hir::map::Map; use rustc::lint; use rustc::middle::resolve_lifetime::*; -use rustc::session::Session; use rustc::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt}; use rustc::{bug, span_bug}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; @@ -1320,9 +1322,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { where F: for<'b> FnOnce(ScopeRef<'_>, &mut LifetimeContext<'b, 'tcx>), { - let LifetimeContext { tcx, map, lifetime_uses, missing_named_lifetime_spots, .. } = self; + let LifetimeContext { tcx, map, lifetime_uses, .. } = self; let labels_in_fn = take(&mut self.labels_in_fn); let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults); + let missing_named_lifetime_spots = take(&mut self.missing_named_lifetime_spots); let mut this = LifetimeContext { tcx: *tcx, map: map, @@ -1332,7 +1335,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { labels_in_fn, xcrate_object_lifetime_defaults, lifetime_uses, - missing_named_lifetime_spots: missing_named_lifetime_spots.to_vec(), + missing_named_lifetime_spots, }; debug!("entering scope {:?}", this.scope); f(self.scope, &mut this); @@ -1340,6 +1343,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { debug!("exiting scope {:?}", this.scope); self.labels_in_fn = this.labels_in_fn; self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults; + self.missing_named_lifetime_spots = this.missing_named_lifetime_spots; } /// helper method to determine the span to remove when suggesting the @@ -2894,74 +2898,3 @@ fn insert_late_bound_lifetimes( } } } - -fn report_missing_lifetime_specifiers( - sess: &Session, - span: Span, - count: usize, -) -> DiagnosticBuilder<'_> { - struct_span_err!(sess, span, E0106, "missing lifetime specifier{}", pluralize!(count)) -} - -fn add_missing_lifetime_specifiers_label( - err: &mut DiagnosticBuilder<'_>, - span: Span, - count: usize, - lifetime_names: &FxHashSet, - snippet: Option<&str>, - missing_named_lifetime_spots: &[&hir::Generics<'_>], -) { - if count > 1 { - err.span_label(span, format!("expected {} lifetime parameters", count)); - } else { - let suggest_existing = |err: &mut DiagnosticBuilder<'_>, sugg| { - err.span_suggestion( - span, - "consider using the named lifetime", - sugg, - Applicability::MaybeIncorrect, - ); - }; - let suggest_new = |err: &mut DiagnosticBuilder<'_>, sugg| { - err.span_label(span, "expected named lifetime parameter"); - - if let Some(generics) = missing_named_lifetime_spots.iter().last() { - let mut introduce_suggestion = vec![]; - introduce_suggestion.push(match &generics.params { - [] => (generics.span, "<'lifetime>".to_string()), - [param, ..] => (param.span.shrink_to_lo(), "'lifetime, ".to_string()), - }); - introduce_suggestion.push((span, sugg)); - err.multipart_suggestion( - "consider introducing a named lifetime parameter", - introduce_suggestion, - Applicability::MaybeIncorrect, - ); - } - }; - - match (lifetime_names.len(), lifetime_names.iter().next(), snippet) { - (1, Some(name), Some("&")) => { - suggest_existing(err, format!("&{} ", name)); - } - (1, Some(name), Some("'_")) => { - suggest_existing(err, name.to_string()); - } - (1, Some(name), Some(snippet)) if !snippet.ends_with(">") => { - suggest_existing(err, format!("{}<{}>", snippet, name)); - } - (0, _, Some("&")) => { - suggest_new(err, "&'lifetime ".to_string()); - } - (0, _, Some("'_")) => { - suggest_new(err, "'lifetime".to_string()); - } - (0, _, Some(snippet)) if !snippet.ends_with(">") => { - suggest_new(err, format!("{}<'lifetime>", snippet)); - } - _ => { - err.span_label(span, "expected lifetime parameter"); - } - } - } -}