From 183dfac1f31cc16975bb1f598779df5689d1e729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 27 Jan 2020 11:26:06 -0800 Subject: [PATCH 01/12] Account for HKTB when suggesting introduction of named lifetime --- src/librustc_hir/hir.rs | 4 +- src/librustc_resolve/diagnostics.rs | 52 ++++++--- src/librustc_resolve/lifetimes.rs | 103 ++++++++++++++---- src/librustc_typeck/astconv.rs | 5 +- .../no_introducing_in_band_in_locals.stderr | 2 + src/test/ui/issues/issue-19707.stderr | 5 + .../ui/regions/regions-name-undeclared.stderr | 20 ++++ 7 files changed, 153 insertions(+), 38 deletions(-) diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index 3ed0ad16eebf2..86252203f1d45 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -2260,10 +2260,10 @@ impl TraitRef<'_> { #[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] pub struct PolyTraitRef<'hir> { - /// The `'a` in `<'a> Foo<&'a T>`. + /// The `'a` in `for<'a> Foo<&'a T>`. pub bound_generic_params: &'hir [GenericParam<'hir>], - /// The `Foo<&'a T>` in `<'a> Foo<&'a T>`. + /// The `Foo<&'a T>` in `for <'a> Foo<&'a T>`. pub trait_ref: TraitRef<'hir>, pub span: Span, diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index a612ad9e783f4..fafceb1f97cee 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -8,7 +8,6 @@ use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; 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}; @@ -20,6 +19,7 @@ use syntax::ast::{self, Ident, Path}; use syntax::util::lev_distance::find_best_match_for_name; use crate::imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver}; +use crate::lifetimes::{HRLTSpanType, MissingLifetimeSpot}; use crate::path_names_to_string; use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind}; use crate::{BindingError, CrateLint, HasGenericParams, LegacyScope, Module, ModuleOrUniformRoot}; @@ -1471,7 +1471,7 @@ crate fn add_missing_lifetime_specifiers_label( count: usize, lifetime_names: &FxHashSet, snippet: Option<&str>, - missing_named_lifetime_spots: &[&hir::Generics<'_>], + missing_named_lifetime_spots: &[MissingLifetimeSpot<'_>], ) { if count > 1 { err.span_label(span, format!("expected {} lifetime parameters", count)); @@ -1484,21 +1484,41 @@ crate fn add_missing_lifetime_specifiers_label( Applicability::MaybeIncorrect, ); }; - let suggest_new = |err: &mut DiagnosticBuilder<'_>, sugg| { + let suggest_new = |err: &mut DiagnosticBuilder<'_>, sugg: &str| { err.span_label(span, "expected named lifetime parameter"); - if let Some(generics) = missing_named_lifetime_spots.iter().last() { + for missing in missing_named_lifetime_spots.iter().rev() { 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()), + let msg; + let should_break; + introduce_suggestion.push(match missing { + MissingLifetimeSpot::Generics(generics) => { + msg = "consider introducing a named lifetime parameter"; + should_break = true; + match &generics.params { + [] => (generics.span, "<'lifetime>".to_string()), + [param, ..] => (param.span.shrink_to_lo(), "'lifetime, ".to_string()), + } + } + MissingLifetimeSpot::HRLT { span, span_type } => { + msg = "consider introducing a Higher-Ranked lifetime"; + should_break = false; + err.note( + "for more information on Higher-Ranked lifetimes, visit \ + https://doc.rust-lang.org/nomicon/hrtb.html", + ); + let suggestion = match span_type { + HRLTSpanType::Empty => "for<'lifetime> ", + HRLTSpanType::Tail => ", 'lifetime", + }; + (*span, suggestion.to_string()) + } }); - introduce_suggestion.push((span, sugg)); - err.multipart_suggestion( - "consider introducing a named lifetime parameter", - introduce_suggestion, - Applicability::MaybeIncorrect, - ); + introduce_suggestion.push((span, sugg.to_string())); + err.multipart_suggestion(msg, introduce_suggestion, Applicability::MaybeIncorrect); + if should_break { + break; + } } }; @@ -1513,13 +1533,13 @@ crate fn add_missing_lifetime_specifiers_label( suggest_existing(err, format!("{}<{}>", snippet, name)); } (0, _, Some("&")) => { - suggest_new(err, "&'lifetime ".to_string()); + suggest_new(err, "&'lifetime "); } (0, _, Some("'_")) => { - suggest_new(err, "'lifetime".to_string()); + suggest_new(err, "'lifetime"); } (0, _, Some(snippet)) if !snippet.ends_with(">") => { - suggest_new(err, format!("{}<'lifetime>", snippet)); + 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 6e9ed5fdc179c..a8d6afa0e55be 100644 --- a/src/librustc_resolve/lifetimes.rs +++ b/src/librustc_resolve/lifetimes.rs @@ -153,6 +153,22 @@ struct NamedRegionMap { object_lifetime_defaults: HirIdMap>, } +crate enum MissingLifetimeSpot<'tcx> { + Generics(&'tcx hir::Generics<'tcx>), + HRLT { span: Span, span_type: HRLTSpanType }, +} + +crate enum HRLTSpanType { + Empty, + Tail, +} + +impl<'tcx> Into> for &'tcx hir::Generics<'tcx> { + fn into(self) -> MissingLifetimeSpot<'tcx> { + MissingLifetimeSpot::Generics(self) + } +} + struct LifetimeContext<'a, 'tcx> { tcx: TyCtxt<'tcx>, map: &'a mut NamedRegionMap, @@ -186,7 +202,7 @@ struct LifetimeContext<'a, 'tcx> { /// When encountering an undefined named lifetime, we will suggest introducing it in these /// places. - missing_named_lifetime_spots: Vec<&'tcx hir::Generics<'tcx>>, + missing_named_lifetime_spots: Vec>, } #[derive(Debug)] @@ -389,7 +405,7 @@ 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.missing_named_lifetime_spots.push(generics.into()); self.visit_early_late(None, &sig.decl, generics, |this| { intravisit::walk_item(this, item); }); @@ -424,7 +440,7 @@ 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); + self.missing_named_lifetime_spots.push(generics.into()); // Impls permit `'_` to be used and it is equivalent to "some fresh lifetime name". // This is not true for other kinds of items.x @@ -696,7 +712,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); + self.missing_named_lifetime_spots.push((&trait_item.generics).into()); match trait_item.kind { Method(ref sig, _) => { let tcx = self.tcx; @@ -753,7 +769,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { 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); + self.missing_named_lifetime_spots.push((&impl_item.generics).into()); match impl_item.kind { Method(ref sig, _) => { let tcx = self.tcx; @@ -953,6 +969,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { ) { debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref); + let should_pop_missing_lt = self.is_trait_ref_fn_scope(trait_ref); if !self.trait_ref_hack || trait_ref.bound_generic_params.iter().any(|param| match param.kind { GenericParamKind::Lifetime { .. } => true, @@ -988,10 +1005,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { self.with(scope, |old_scope, this| { this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params); walk_list!(this, visit_generic_param, trait_ref.bound_generic_params); - this.visit_trait_ref(&trait_ref.trait_ref) + this.visit_trait_ref(&trait_ref.trait_ref); }) } else { - self.visit_trait_ref(&trait_ref.trait_ref) + self.visit_trait_ref(&trait_ref.trait_ref); + } + if should_pop_missing_lt { + self.missing_named_lifetime_spots.pop(); } } } @@ -1832,18 +1852,41 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { lifetime_ref ); 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, - ); + for missing in &self.missing_named_lifetime_spots { + match missing { + MissingLifetimeSpot::Generics(generics) => { + 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, + ); + } + MissingLifetimeSpot::HRLT { span, span_type } => { + err.span_suggestion( + *span, + &format!( + "consider introducing a Higher-Ranked lifetime `{}` here", + lifetime_ref + ), + match span_type { + HRLTSpanType::Empty => format!("for<{}> ", lifetime_ref), + HRLTSpanType::Tail => format!(", {}", lifetime_ref), + } + .to_string(), + Applicability::MaybeIncorrect, + ); + err.note( + "for more information on Higher-Ranked lifetimes, visit \ + https://doc.rust-lang.org/nomicon/hrtb.html", + ); + } } } err.emit(); @@ -2441,6 +2484,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let elided_len = elided_params.len(); + // FIXME: collect spans of the input params when appropriate to use in the diagnostic. for (i, info) in elided_params.into_iter().enumerate() { let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions } = info; @@ -2747,6 +2791,27 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let old_value = self.map.defs.remove(&lifetime_ref.hir_id); assert_eq!(old_value, Some(bad_def)); } + + fn is_trait_ref_fn_scope(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) -> bool { + if let Res::Def(_, did) = trait_ref.trait_ref.path.res { + if [ + self.tcx.lang_items().fn_once_trait(), + self.tcx.lang_items().fn_trait(), + self.tcx.lang_items().fn_mut_trait(), + ] + .contains(&Some(did)) + { + let (span, span_type) = match &trait_ref.bound_generic_params { + [] => (trait_ref.span.shrink_to_lo(), HRLTSpanType::Empty), + [.., bound] => (bound.span.shrink_to_hi(), HRLTSpanType::Tail), + }; + self.missing_named_lifetime_spots + .push(MissingLifetimeSpot::HRLT { span, span_type }); + return true; + } + }; + false + } } /// Detects late-bound lifetimes and inserts them into diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 231aed48fb6be..6bd120d818d09 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1307,12 +1307,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); } }; + // FIXME: point at the type params that don't have appropriate lifetimes: + // struct S1 Fn(&i32, &i32) -> &'a i32>(F); + // ---- ---- ^^^^^^^ struct_span_err!( tcx.sess, binding.span, E0582, "binding for associated type `{}` references lifetime `{}`, \ - which does not appear in the trait input types", + which does not appear in the trait input types", binding.item_name, br_name ) 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 bfb20ade035cf..7d71230e16210 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 @@ -9,6 +9,8 @@ LL | let y: &'test u32 = x; error[E0261]: use of undeclared lifetime name `'test` --> $DIR/no_introducing_in_band_in_locals.rs:10:16 | +LL | fn bar() { + | - help: consider introducing lifetime `'test` here: `<'test>` LL | let y: fn(&'test u32) = foo2; | ^^^^^ undeclared lifetime diff --git a/src/test/ui/issues/issue-19707.stderr b/src/test/ui/issues/issue-19707.stderr index 8a627bc0bd4de..c5129152aa581 100644 --- a/src/test/ui/issues/issue-19707.stderr +++ b/src/test/ui/issues/issue-19707.stderr @@ -17,6 +17,11 @@ 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 + = note: for more information on Higher-Ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider introducing a Higher-Ranked lifetime + | +LL | fn bar Fn(&u8, &u8) -> &'lifetime u8>(f: &F) {} + | ^^^^^^^^^^^^^^ ^^^^^^^^^^ 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/regions/regions-name-undeclared.stderr b/src/test/ui/regions/regions-name-undeclared.stderr index 79ebef41dccd6..cb72d1ec9bc71 100644 --- a/src/test/ui/regions/regions-name-undeclared.stderr +++ b/src/test/ui/regions/regions-name-undeclared.stderr @@ -88,12 +88,32 @@ error[E0261]: use of undeclared lifetime name `'b` | LL | ... &'b isize, | ^^ undeclared lifetime + | + = note: for more information on Higher-Ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider introducing lifetime `'b` here + | +LL | fn fn_types<'b>(a: &'a isize, + | ^^^^ +help: consider introducing a Higher-Ranked lifetime `'b` here + | +LL | b: Box FnOnce(&'a isize, + | ^^^^ error[E0261]: use of undeclared lifetime name `'b` --> $DIR/regions-name-undeclared.rs:45:36 | LL | ... &'b isize)>, | ^^ undeclared lifetime + | + = note: for more information on Higher-Ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider introducing lifetime `'b` here + | +LL | fn fn_types<'b>(a: &'a isize, + | ^^^^ +help: consider introducing a Higher-Ranked lifetime `'b` here + | +LL | b: Box FnOnce(&'a isize, + | ^^^^ error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-name-undeclared.rs:46:17 From 70dbf5526d37ad031fca57ddde55bf8757bfc326 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 27 Jan 2020 11:48:52 -0800 Subject: [PATCH 02/12] Use spans for input borrowed types unrelated to return type --- src/librustc_resolve/lifetimes.rs | 27 +++++++++++++------ .../async-await/issues/issue-63388-2.stderr | 6 ++++- 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/rfc1623.stderr | 12 +++++++-- .../return-without-lifetime.stderr | 12 +++++++-- ...oxed-closure-sugar-lifetime-elision.stderr | 6 ++++- .../in-fn-return-illegal.stderr | 6 ++++- .../underscore-lifetime-binders.stderr | 6 ++++- 12 files changed, 104 insertions(+), 25 deletions(-) diff --git a/src/librustc_resolve/lifetimes.rs b/src/librustc_resolve/lifetimes.rs index a8d6afa0e55be..022f83af8159c 100644 --- a/src/librustc_resolve/lifetimes.rs +++ b/src/librustc_resolve/lifetimes.rs @@ -287,6 +287,7 @@ struct ElisionFailureInfo { index: usize, lifetime_count: usize, have_bound_regions: bool, + span: Span, } type ScopeRef<'a> = &'a Scope<'a>; @@ -2273,6 +2274,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { index: i, lifetime_count: gather.lifetimes.len(), have_bound_regions: gather.have_bound_regions, + span: input.span, } }) .collect(); @@ -2483,11 +2485,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { params.iter().cloned().filter(|info| info.lifetime_count > 0).collect(); let elided_len = elided_params.len(); + let mut spans = vec![]; - // FIXME: collect spans of the input params when appropriate to use in the diagnostic. for (i, info) in elided_params.into_iter().enumerate() { - let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions } = info; + let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } = info; + spans.push(span); let help_name = if let Some(ident) = parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident()) { @@ -2518,14 +2521,22 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } + let help = |msg| { + if spans.is_empty() { + db.help(msg); + } else { + db.span_help(spans, msg); + } + }; + if len == 0 { db.help( "this function's return type contains a borrowed value, \ - but there is no value for it to be borrowed from", + but there is no value for it to be borrowed from", ); self.suggest_lifetime(db, span, "consider giving it a 'static lifetime") } else if elided_len == 0 { - db.help( + help( "this function's return type contains a borrowed value with \ an elided lifetime, but the lifetime cannot be derived from \ the arguments", @@ -2533,16 +2544,16 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let msg = "consider giving it an explicit bounded or 'static lifetime"; self.suggest_lifetime(db, span, msg) } else if elided_len == 1 { - db.help(&format!( + help(&format!( "this function's return type contains a borrowed value, \ - but the signature does not say which {} it is borrowed from", + but the signature does not say which {} it is borrowed from", m )); true } else { - db.help(&format!( + help(&format!( "this function's return type contains a borrowed value, \ - but the signature does not say whether it is borrowed from {}", + but the signature does not say whether it is borrowed from {}", m )); true diff --git a/src/test/ui/async-await/issues/issue-63388-2.stderr b/src/test/ui/async-await/issues/issue-63388-2.stderr index 7e45d588c6c6c..a12c601b936af 100644 --- a/src/test/ui/async-await/issues/issue-63388-2.stderr +++ b/src/test/ui/async-await/issues/issue-63388-2.stderr @@ -4,7 +4,11 @@ error[E0106]: missing lifetime specifier LL | ) -> &dyn Foo | ^ help: consider using the named lifetime: `&'a` | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `foo` or `bar` +help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `foo` or `bar` + --> $DIR/issue-63388-2.rs:11:14 + | +LL | foo: &dyn Foo, bar: &'a dyn Foo + | ^^^^^^^^ ^^^^^^^^^^^ error: cannot infer an appropriate lifetime --> $DIR/issue-63388-2.rs:11:9 diff --git a/src/test/ui/issues/issue-19707.stderr b/src/test/ui/issues/issue-19707.stderr index c5129152aa581..1be066caa87a9 100644 --- a/src/test/ui/issues/issue-19707.stderr +++ b/src/test/ui/issues/issue-19707.stderr @@ -4,7 +4,11 @@ error[E0106]: missing lifetime specifier 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: 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 + --> $DIR/issue-19707.rs:3:15 + | +LL | type Foo = fn(&u8, &u8) -> &u8; + | ^^^ ^^^ help: consider introducing a named lifetime parameter | LL | type Foo<'lifetime> = fn(&u8, &u8) -> &'lifetime u8; @@ -16,7 +20,11 @@ error[E0106]: missing lifetime specifier 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: 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 + --> $DIR/issue-19707.rs:5:14 + | +LL | fn bar &u8>(f: &F) {} + | ^^^ ^^^ = note: for more information on Higher-Ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider introducing a Higher-Ranked lifetime | diff --git a/src/test/ui/issues/issue-26638.stderr b/src/test/ui/issues/issue-26638.stderr index 85d5d9cc42e9a..882102799d913 100644 --- a/src/test/ui/issues/issue-26638.stderr +++ b/src/test/ui/issues/issue-26638.stderr @@ -4,7 +4,11 @@ error[E0106]: missing lifetime specifier LL | fn parse_type(iter: Box+'static>) -> &str { iter.next() } | ^ 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: 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 + --> $DIR/issue-26638.rs:1:21 + | +LL | fn parse_type(iter: Box+'static>) -> &str { iter.next() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 c940227764099..e2b57a20325d3 100644 --- a/src/test/ui/issues/issue-30255.stderr +++ b/src/test/ui/issues/issue-30255.stderr @@ -4,7 +4,11 @@ error[E0106]: missing lifetime specifier 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: 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 + --> $DIR/issue-30255.rs:9:9 + | +LL | fn f(a: &S, b: i32) -> &i32 { + | ^^ help: consider introducing a named lifetime parameter | LL | fn f<'lifetime>(a: &S, b: i32) -> &'lifetime i32 { @@ -16,7 +20,11 @@ error[E0106]: missing lifetime specifier 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: 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` + --> $DIR/issue-30255.rs:14:9 + | +LL | fn g(a: &S, b: bool, c: &i32) -> &i32 { + | ^^ ^^^^ help: consider introducing a named lifetime parameter | LL | fn g<'lifetime>(a: &S, b: bool, c: &i32) -> &'lifetime i32 { @@ -28,7 +36,11 @@ error[E0106]: missing lifetime specifier 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: 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` + --> $DIR/issue-30255.rs:19:9 + | +LL | fn h(a: &bool, b: bool, c: &S, d: &i32) -> &i32 { + | ^^^^^ ^^ ^^^^ 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 1d5eeac23f96a..d1b597804cda9 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 @@ -12,7 +12,11 @@ error[E0106]: missing lifetime specifier 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: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `_x` or `_y` + --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:7:10 + | +LL | fn g(_x: &isize, _y: &isize) -> &isize { + | ^^^^^^ ^^^^^^ help: consider introducing a named lifetime parameter | LL | fn g<'lifetime>(_x: &isize, _y: &isize) -> &'lifetime isize { @@ -24,7 +28,11 @@ error[E0106]: missing lifetime specifier 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: 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 + --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:17:10 + | +LL | fn h(_x: &Foo) -> &isize { + | ^^^^ 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 2990ab8682434..52a980a61daa0 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 @@ -4,7 +4,11 @@ error[E0106]: missing lifetime specifier 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: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` + --> $DIR/ex1b-return-no-names-if-else.rs:1:11 + | +LL | fn foo(x: &i32, y: &i32) -> &i32 { + | ^^^^ ^^^^ help: consider introducing a named lifetime parameter | LL | fn foo<'lifetime>(x: &i32, y: &i32) -> &'lifetime i32 { diff --git a/src/test/ui/rfc1623.stderr b/src/test/ui/rfc1623.stderr index 5b665e181412a..aabe088d63ca6 100644 --- a/src/test/ui/rfc1623.stderr +++ b/src/test/ui/rfc1623.stderr @@ -4,7 +4,11 @@ error[E0106]: missing lifetime specifier LL | static NON_ELIDABLE_FN: &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: 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 + --> $DIR/rfc1623.rs:8:29 + | +LL | static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = + | ^^^ ^^^ error[E0106]: missing lifetime specifier --> $DIR/rfc1623.rs:10:39 @@ -12,7 +16,11 @@ error[E0106]: missing lifetime specifier LL | &(non_elidable as 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: 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 + --> $DIR/rfc1623.rs:10:26 + | +LL | &(non_elidable as fn(&u8, &u8) -> &u8); + | ^^^ ^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/return-without-lifetime.stderr b/src/test/ui/suggestions/return-without-lifetime.stderr index 7f5ff95938e30..3b7936c5f44b6 100644 --- a/src/test/ui/suggestions/return-without-lifetime.stderr +++ b/src/test/ui/suggestions/return-without-lifetime.stderr @@ -10,7 +10,11 @@ error[E0106]: missing lifetime specifier LL | fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() } | ^ help: consider using the named lifetime: `&'a` | - = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from +help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from + --> $DIR/return-without-lifetime.rs:5:20 + | +LL | fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() } + | ^^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/return-without-lifetime.rs:7:35 @@ -18,7 +22,11 @@ error[E0106]: missing lifetime specifier LL | fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() } | ^ help: consider using the named lifetime: `&'a` | - = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from +help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from + --> $DIR/return-without-lifetime.rs:7:20 + | +LL | fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() } + | ^^^^^^^^^^ error: aborting due to 3 previous errors 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 0a028e44919a6..1e15196f8ec85 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 @@ -4,7 +4,11 @@ error[E0106]: missing lifetime specifier 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: 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 + --> $DIR/unboxed-closure-sugar-lifetime-elision.rs:26:20 + | +LL | let _: dyn Foo(&isize, &usize) -> &usize; + | ^^^^^^ ^^^^^^ help: consider introducing a named lifetime parameter | LL | fn main<'lifetime>() { 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 cf820249c80af..801504627c0ac 100644 --- a/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr +++ b/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr @@ -4,7 +4,11 @@ error[E0106]: missing lifetime specifier 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: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` + --> $DIR/in-fn-return-illegal.rs:5:11 + | +LL | fn foo(x: &u32, y: &u32) -> &'_ u32 { loop { } } + | ^^^^ ^^^^ 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/underscore-lifetime-binders.stderr b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr index 517904ee62869..ef3ad18ee8861 100644 --- a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr +++ b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr @@ -30,7 +30,11 @@ error[E0106]: missing lifetime specifier 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: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or `y` + --> $DIR/underscore-lifetime-binders.rs:16:12 + | +LL | fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y } + | ^^^^^^ ^^^^^^ help: consider introducing a named lifetime parameter | LL | fn foo2<'lifetime>(_: &'_ u8, y: &'_ u8) -> &'lifetime u8 { y } From 7e1464336a627ecb962f4eb38173fbfbfdd2ccf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 27 Jan 2020 12:41:49 -0800 Subject: [PATCH 03/12] When suggesting lifetimes, propose adding the new lifetime to all arguments --- src/librustc_resolve/diagnostics.rs | 12 +++++++++++- src/librustc_resolve/lifetimes.rs | 9 ++++++--- src/test/ui/issues/issue-19707.stderr | 12 ++++++------ src/test/ui/issues/issue-30255.stderr | 12 ++++++------ ...ion-return-type-requires-explicit-lifetime.stderr | 8 ++++---- .../ex1b-return-no-names-if-else.stderr | 4 ++-- .../underscore-lifetime/in-fn-return-illegal.stderr | 4 ++-- 7 files changed, 37 insertions(+), 24 deletions(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index fafceb1f97cee..56fb66004053c 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -19,7 +19,7 @@ use syntax::ast::{self, Ident, Path}; use syntax::util::lev_distance::find_best_match_for_name; use crate::imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver}; -use crate::lifetimes::{HRLTSpanType, MissingLifetimeSpot}; +use crate::lifetimes::{ElisionFailureInfo, HRLTSpanType, MissingLifetimeSpot}; use crate::path_names_to_string; use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind}; use crate::{BindingError, CrateLint, HasGenericParams, LegacyScope, Module, ModuleOrUniformRoot}; @@ -1467,11 +1467,13 @@ crate fn report_missing_lifetime_specifiers( crate fn add_missing_lifetime_specifiers_label( err: &mut DiagnosticBuilder<'_>, + source_map: &SourceMap, span: Span, count: usize, lifetime_names: &FxHashSet, snippet: Option<&str>, missing_named_lifetime_spots: &[MissingLifetimeSpot<'_>], + params: &[ElisionFailureInfo], ) { if count > 1 { err.span_label(span, format!("expected {} lifetime parameters", count)); @@ -1514,6 +1516,14 @@ crate fn add_missing_lifetime_specifiers_label( (*span, suggestion.to_string()) } }); + for param in params { + if let Ok(snippet) = source_map.span_to_snippet(param.span) { + if snippet.starts_with("&") && !snippet.starts_with("&'") { + introduce_suggestion + .push((param.span, format!("&'lifetime {}", &snippet[1..]))); + } + } + } introduce_suggestion.push((span, sugg.to_string())); err.multipart_suggestion(msg, introduce_suggestion, Applicability::MaybeIncorrect); if should_break { diff --git a/src/librustc_resolve/lifetimes.rs b/src/librustc_resolve/lifetimes.rs index 022f83af8159c..97d314c8f65a9 100644 --- a/src/librustc_resolve/lifetimes.rs +++ b/src/librustc_resolve/lifetimes.rs @@ -280,14 +280,14 @@ enum Elide { } #[derive(Clone, Debug)] -struct ElisionFailureInfo { +crate struct ElisionFailureInfo { /// Where we can find the argument pattern. parent: Option, /// The index of the argument in the original definition. index: usize, lifetime_count: usize, have_bound_regions: bool, - span: Span, + crate span: Span, } type ScopeRef<'a> = &'a Scope<'a>; @@ -2441,11 +2441,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { if add_label { add_missing_lifetime_specifiers_label( &mut err, + self.tcx.sess.source_map(), span, 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, + error.map(|p| &p[..]).unwrap_or(&[]), ); } @@ -2488,7 +2490,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let mut spans = vec![]; for (i, info) in elided_params.into_iter().enumerate() { - let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } = info; + let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } = + info; spans.push(span); let help_name = if let Some(ident) = diff --git a/src/test/ui/issues/issue-19707.stderr b/src/test/ui/issues/issue-19707.stderr index 1be066caa87a9..f8917b7bdd087 100644 --- a/src/test/ui/issues/issue-19707.stderr +++ b/src/test/ui/issues/issue-19707.stderr @@ -11,8 +11,8 @@ LL | type Foo = fn(&u8, &u8) -> &u8; | ^^^ ^^^ help: consider introducing a named lifetime parameter | -LL | type Foo<'lifetime> = fn(&u8, &u8) -> &'lifetime u8; - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | type Foo<'lifetime> = fn(&'lifetime u8, &'lifetime u8) -> &'lifetime u8; + | ^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/issue-19707.rs:5:27 @@ -28,12 +28,12 @@ LL | fn bar &u8>(f: &F) {} = note: for more information on Higher-Ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider introducing a Higher-Ranked lifetime | -LL | fn bar Fn(&u8, &u8) -> &'lifetime u8>(f: &F) {} - | ^^^^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn bar Fn(&'lifetime u8, &'lifetime u8) -> &'lifetime u8>(f: &F) {} + | ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^ help: consider introducing a named lifetime parameter | -LL | fn bar<'lifetime, F: Fn(&u8, &u8) -> &'lifetime u8>(f: &F) {} - | ^^^^^^^^^^ ^^^^^^^^^^ +LL | fn bar<'lifetime, F: Fn(&'lifetime u8, &'lifetime u8) -> &'lifetime u8>(f: &F) {} + | ^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-30255.stderr b/src/test/ui/issues/issue-30255.stderr index e2b57a20325d3..fbe715de932f9 100644 --- a/src/test/ui/issues/issue-30255.stderr +++ b/src/test/ui/issues/issue-30255.stderr @@ -11,8 +11,8 @@ LL | fn f(a: &S, b: i32) -> &i32 { | ^^ help: consider introducing a named lifetime parameter | -LL | fn f<'lifetime>(a: &S, b: i32) -> &'lifetime i32 { - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn f<'lifetime>(a: &'lifetime S, b: i32) -> &'lifetime i32 { + | ^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/issue-30255.rs:14:34 @@ -27,8 +27,8 @@ LL | fn g(a: &S, b: bool, c: &i32) -> &i32 { | ^^ ^^^^ help: consider introducing a named lifetime parameter | -LL | fn g<'lifetime>(a: &S, b: bool, c: &i32) -> &'lifetime i32 { - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn g<'lifetime>(a: &'lifetime S, b: bool, c: &'lifetime i32) -> &'lifetime i32 { + | ^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/issue-30255.rs:19:44 @@ -43,8 +43,8 @@ LL | fn h(a: &bool, b: bool, c: &S, d: &i32) -> &i32 { | ^^^^^ ^^ ^^^^ help: consider introducing a named lifetime parameter | -LL | fn h<'lifetime>(a: &bool, b: bool, c: &S, d: &i32) -> &'lifetime i32 { - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn h<'lifetime>(a: &'lifetime bool, b: bool, c: &'lifetime S, d: &'lifetime 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 d1b597804cda9..01236e3c77304 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 @@ -19,8 +19,8 @@ LL | fn g(_x: &isize, _y: &isize) -> &isize { | ^^^^^^ ^^^^^^ help: consider introducing a named lifetime parameter | -LL | fn g<'lifetime>(_x: &isize, _y: &isize) -> &'lifetime isize { - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn g<'lifetime>(_x: &'lifetime isize, _y: &'lifetime isize) -> &'lifetime isize { + | ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ ^^^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:17:19 @@ -35,8 +35,8 @@ LL | fn h(_x: &Foo) -> &isize { | ^^^^ help: consider introducing a named lifetime parameter | -LL | fn h<'lifetime>(_x: &Foo) -> &'lifetime isize { - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn h<'lifetime>(_x: &'lifetime 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 52a980a61daa0..bea1a8bf2c1fd 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 @@ -11,8 +11,8 @@ LL | fn foo(x: &i32, y: &i32) -> &i32 { | ^^^^ ^^^^ help: consider introducing a named lifetime parameter | -LL | fn foo<'lifetime>(x: &i32, y: &i32) -> &'lifetime i32 { - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn foo<'lifetime>(x: &'lifetime i32, y: &'lifetime i32) -> &'lifetime i32 { + | ^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^ error: aborting due to previous error 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 801504627c0ac..97014dae2b970 100644 --- a/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr +++ b/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr @@ -11,8 +11,8 @@ LL | fn foo(x: &u32, y: &u32) -> &'_ u32 { loop { } } | ^^^^ ^^^^ help: consider introducing a named lifetime parameter | -LL | fn foo<'lifetime>(x: &u32, y: &u32) -> &'lifetime u32 { loop { } } - | ^^^^^^^^^^^ ^^^^^^^^^ +LL | fn foo<'lifetime>(x: &'lifetime u32, y: &'lifetime u32) -> &'lifetime u32 { loop { } } + | ^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^ error: aborting due to previous error From fa4594196d2bcc265c4cdc1382d33366b3008341 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 27 Jan 2020 12:49:12 -0800 Subject: [PATCH 04/12] Suggest `'r` instead of `'lifetime` --- src/librustc_resolve/diagnostics.rs | 16 +++--- src/test/ui/error-codes/E0106.stderr | 16 +++--- .../assoc-type.stderr | 8 +-- ...anon-lifetime-in-struct-declaration.stderr | 4 +- src/test/ui/issues/issue-19707.stderr | 12 ++--- src/test/ui/issues/issue-26638.stderr | 4 +- src/test/ui/issues/issue-30255.stderr | 12 ++--- ...urn-type-requires-explicit-lifetime.stderr | 8 +-- .../ex1b-return-no-names-if-else.stderr | 4 +- src/test/ui/proc-macro/item-error.stderr | 4 +- .../ui/regions/regions-in-enums-anon.stderr | 4 +- .../ui/regions/regions-in-structs-anon.stderr | 4 +- .../fn-missing-lifetime-in-item.rs | 8 +++ .../fn-missing-lifetime-in-item.stderr | 53 +++++++++++++++++++ ...oxed-closure-sugar-lifetime-elision.stderr | 2 +- .../dyn-trait-underscore-in-struct.stderr | 4 +- .../in-fn-return-illegal.stderr | 4 +- .../ui/underscore-lifetime/in-struct.stderr | 8 +-- .../underscore-lifetime-binders.stderr | 4 +- 19 files changed, 120 insertions(+), 59 deletions(-) create mode 100644 src/test/ui/suggestions/fn-missing-lifetime-in-item.rs create mode 100644 src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 56fb66004053c..8346dc3b85425 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -1498,8 +1498,8 @@ crate fn add_missing_lifetime_specifiers_label( msg = "consider introducing a named lifetime parameter"; should_break = true; match &generics.params { - [] => (generics.span, "<'lifetime>".to_string()), - [param, ..] => (param.span.shrink_to_lo(), "'lifetime, ".to_string()), + [] => (generics.span, "<'r>".to_string()), + [param, ..] => (param.span.shrink_to_lo(), "'r, ".to_string()), } } MissingLifetimeSpot::HRLT { span, span_type } => { @@ -1510,8 +1510,8 @@ crate fn add_missing_lifetime_specifiers_label( https://doc.rust-lang.org/nomicon/hrtb.html", ); let suggestion = match span_type { - HRLTSpanType::Empty => "for<'lifetime> ", - HRLTSpanType::Tail => ", 'lifetime", + HRLTSpanType::Empty => "for<'r> ", + HRLTSpanType::Tail => ", 'r", }; (*span, suggestion.to_string()) } @@ -1520,7 +1520,7 @@ crate fn add_missing_lifetime_specifiers_label( if let Ok(snippet) = source_map.span_to_snippet(param.span) { if snippet.starts_with("&") && !snippet.starts_with("&'") { introduce_suggestion - .push((param.span, format!("&'lifetime {}", &snippet[1..]))); + .push((param.span, format!("&'r {}", &snippet[1..]))); } } } @@ -1543,13 +1543,13 @@ crate fn add_missing_lifetime_specifiers_label( suggest_existing(err, format!("{}<{}>", snippet, name)); } (0, _, Some("&")) => { - suggest_new(err, "&'lifetime "); + suggest_new(err, "&'r "); } (0, _, Some("'_")) => { - suggest_new(err, "'lifetime"); + suggest_new(err, "'r"); } (0, _, Some(snippet)) if !snippet.ends_with(">") => { - suggest_new(err, &format!("{}<'lifetime>", snippet)); + suggest_new(err, &format!("{}<'r>", snippet)); } _ => { err.span_label(span, "expected lifetime parameter"); diff --git a/src/test/ui/error-codes/E0106.stderr b/src/test/ui/error-codes/E0106.stderr index e01e0a6f54b07..3792b8f637aa0 100644 --- a/src/test/ui/error-codes/E0106.stderr +++ b/src/test/ui/error-codes/E0106.stderr @@ -6,8 +6,8 @@ LL | x: &bool, | help: consider introducing a named lifetime parameter | -LL | struct Foo<'lifetime> { -LL | x: &'lifetime bool, +LL | struct Foo<'r> { +LL | x: &'r bool, | error[E0106]: missing lifetime specifier @@ -18,9 +18,9 @@ LL | B(&bool), | help: consider introducing a named lifetime parameter | -LL | enum Bar<'lifetime> { +LL | enum Bar<'r> { LL | A(u8), -LL | B(&'lifetime bool), +LL | B(&'r bool), | error[E0106]: missing lifetime specifier @@ -31,8 +31,8 @@ LL | type MyStr = &str; | help: consider introducing a named lifetime parameter | -LL | type MyStr<'lifetime> = &'lifetime str; - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | type MyStr<'r> = &'r str; + | ^^^^ ^^^ error[E0106]: missing lifetime specifier --> $DIR/E0106.rs:17:10 @@ -42,8 +42,8 @@ LL | baz: Baz, | help: consider introducing a named lifetime parameter | -LL | struct Quux<'lifetime> { -LL | baz: Baz<'lifetime>, +LL | struct Quux<'r> { +LL | baz: Baz<'r>, | error[E0106]: missing lifetime specifiers 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 14c53f906654b..d3968917bed54 100644 --- a/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr +++ b/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr @@ -6,8 +6,8 @@ LL | type Output = &i32; | help: consider introducing a named lifetime parameter | -LL | type Output<'lifetime> = &'lifetime i32; - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | type Output<'r> = &'r i32; + | ^^^^ ^^^ error[E0106]: missing lifetime specifier --> $DIR/assoc-type.rs:16:20 @@ -17,8 +17,8 @@ LL | type Output = &'_ i32; | help: consider introducing a named lifetime parameter | -LL | type Output<'lifetime> = &'lifetime i32; - | ^^^^^^^^^^^ ^^^^^^^^^ +LL | type Output<'r> = &'r 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 5f101a24c1d43..3688b222a3508 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 @@ -6,8 +6,8 @@ LL | struct Heartbreak(Betrayal); | help: consider introducing a named lifetime parameter | -LL | struct Heartbreak<'lifetime>(Betrayal<'lifetime>); - | ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ +LL | struct Heartbreak<'r>(Betrayal<'r>); + | ^^^^ ^^^^^^^^^^^^ 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 f8917b7bdd087..8246b0e54019f 100644 --- a/src/test/ui/issues/issue-19707.stderr +++ b/src/test/ui/issues/issue-19707.stderr @@ -11,8 +11,8 @@ LL | type Foo = fn(&u8, &u8) -> &u8; | ^^^ ^^^ help: consider introducing a named lifetime parameter | -LL | type Foo<'lifetime> = fn(&'lifetime u8, &'lifetime u8) -> &'lifetime u8; - | ^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^ +LL | type Foo<'r> = fn(&'r u8, &'r u8) -> &'r u8; + | ^^^^ ^^^^^^ ^^^^^^ ^^^ error[E0106]: missing lifetime specifier --> $DIR/issue-19707.rs:5:27 @@ -28,12 +28,12 @@ LL | fn bar &u8>(f: &F) {} = note: for more information on Higher-Ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider introducing a Higher-Ranked lifetime | -LL | fn bar Fn(&'lifetime u8, &'lifetime u8) -> &'lifetime u8>(f: &F) {} - | ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn bar Fn(&'r u8, &'r u8) -> &'r u8>(f: &F) {} + | ^^^^^^^ ^^^^^^ ^^^^^^ ^^^ help: consider introducing a named lifetime parameter | -LL | fn bar<'lifetime, F: Fn(&'lifetime u8, &'lifetime u8) -> &'lifetime u8>(f: &F) {} - | ^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn bar<'r, F: Fn(&'r u8, &'r u8) -> &'r 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 882102799d913..8c114cf1ae8b4 100644 --- a/src/test/ui/issues/issue-26638.stderr +++ b/src/test/ui/issues/issue-26638.stderr @@ -11,8 +11,8 @@ LL | fn parse_type(iter: Box+'static>) -> &str { iter.ne | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider introducing a named lifetime parameter | -LL | fn parse_type<'lifetime>(iter: Box+'static>) -> &'lifetime str { iter.next() } - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn parse_type<'r>(iter: Box+'static>) -> &'r 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 fbe715de932f9..fff3766e12dc7 100644 --- a/src/test/ui/issues/issue-30255.stderr +++ b/src/test/ui/issues/issue-30255.stderr @@ -11,8 +11,8 @@ LL | fn f(a: &S, b: i32) -> &i32 { | ^^ help: consider introducing a named lifetime parameter | -LL | fn f<'lifetime>(a: &'lifetime S, b: i32) -> &'lifetime i32 { - | ^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn f<'r>(a: &'r S, b: i32) -> &'r i32 { + | ^^^^ ^^^^^ ^^^ error[E0106]: missing lifetime specifier --> $DIR/issue-30255.rs:14:34 @@ -27,8 +27,8 @@ LL | fn g(a: &S, b: bool, c: &i32) -> &i32 { | ^^ ^^^^ help: consider introducing a named lifetime parameter | -LL | fn g<'lifetime>(a: &'lifetime S, b: bool, c: &'lifetime i32) -> &'lifetime i32 { - | ^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn g<'r>(a: &'r S, b: bool, c: &'r i32) -> &'r i32 { + | ^^^^ ^^^^^ ^^^^^^^ ^^^ error[E0106]: missing lifetime specifier --> $DIR/issue-30255.rs:19:44 @@ -43,8 +43,8 @@ LL | fn h(a: &bool, b: bool, c: &S, d: &i32) -> &i32 { | ^^^^^ ^^ ^^^^ help: consider introducing a named lifetime parameter | -LL | fn h<'lifetime>(a: &'lifetime bool, b: bool, c: &'lifetime S, d: &'lifetime i32) -> &'lifetime i32 { - | ^^^^^^^^^^^ ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn h<'r>(a: &'r bool, b: bool, c: &'r S, d: &'r i32) -> &'r 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 01236e3c77304..638c8b8612cf2 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 @@ -19,8 +19,8 @@ LL | fn g(_x: &isize, _y: &isize) -> &isize { | ^^^^^^ ^^^^^^ help: consider introducing a named lifetime parameter | -LL | fn g<'lifetime>(_x: &'lifetime isize, _y: &'lifetime isize) -> &'lifetime isize { - | ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn g<'r>(_x: &'r isize, _y: &'r isize) -> &'r isize { + | ^^^^ ^^^^^^^^^ ^^^^^^^^^ ^^^ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:17:19 @@ -35,8 +35,8 @@ LL | fn h(_x: &Foo) -> &isize { | ^^^^ help: consider introducing a named lifetime parameter | -LL | fn h<'lifetime>(_x: &'lifetime Foo) -> &'lifetime isize { - | ^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn h<'r>(_x: &'r Foo) -> &'r 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 bea1a8bf2c1fd..e1982ea393ef4 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 @@ -11,8 +11,8 @@ LL | fn foo(x: &i32, y: &i32) -> &i32 { | ^^^^ ^^^^ help: consider introducing a named lifetime parameter | -LL | fn foo<'lifetime>(x: &'lifetime i32, y: &'lifetime i32) -> &'lifetime i32 { - | ^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn foo<'r>(x: &'r i32, y: &'r i32) -> &'r 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 01eadbe252e9f..be33f2e2f7695 100644 --- a/src/test/ui/proc-macro/item-error.stderr +++ b/src/test/ui/proc-macro/item-error.stderr @@ -6,8 +6,8 @@ LL | a: &u64 | help: consider introducing a named lifetime parameter | -LL | struct A<'lifetime> { -LL | a: &'lifetime u64 +LL | struct A<'r> { +LL | a: &'r 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 41655a210b3c0..46555df59367e 100644 --- a/src/test/ui/regions/regions-in-enums-anon.stderr +++ b/src/test/ui/regions/regions-in-enums-anon.stderr @@ -6,8 +6,8 @@ LL | Bar(&isize) | help: consider introducing a named lifetime parameter | -LL | enum Foo<'lifetime> { -LL | Bar(&'lifetime isize) +LL | enum Foo<'r> { +LL | Bar(&'r 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 fbe8036880f48..e807810db26fb 100644 --- a/src/test/ui/regions/regions-in-structs-anon.stderr +++ b/src/test/ui/regions/regions-in-structs-anon.stderr @@ -6,8 +6,8 @@ LL | x: &isize | help: consider introducing a named lifetime parameter | -LL | struct Foo<'lifetime> { -LL | x: &'lifetime isize +LL | struct Foo<'r> { +LL | x: &'r isize | error: aborting due to previous error diff --git a/src/test/ui/suggestions/fn-missing-lifetime-in-item.rs b/src/test/ui/suggestions/fn-missing-lifetime-in-item.rs new file mode 100644 index 0000000000000..dac6610b3355f --- /dev/null +++ b/src/test/ui/suggestions/fn-missing-lifetime-in-item.rs @@ -0,0 +1,8 @@ +struct S1 &'a i32>(F); //~ ERROR use of undeclared lifetime name `'a` +struct S2 &i32>(F); //~ ERROR missing lifetime specifier +struct S3 Fn(&i32, &i32) -> &'a i32>(F); +//~^ ERROR binding for associated type `Output` references lifetime `'a`, which does not appear +struct S4 Fn(&'x i32, &'x i32) -> &'x i32>(F); +const C: Option Fn(&usize, &usize) -> &'a usize>> = None; +//~^ ERROR binding for associated type `Output` references lifetime `'a`, which does not appear +fn main() {} diff --git a/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr b/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr new file mode 100644 index 0000000000000..c1a40ebc89286 --- /dev/null +++ b/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr @@ -0,0 +1,53 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/fn-missing-lifetime-in-item.rs:1:33 + | +LL | struct S1 &'a i32>(F); + | ^^ undeclared lifetime + | + = note: for more information on Higher-Ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider introducing lifetime `'a` here + | +LL | struct S1<'a, F: Fn(&i32, &i32) -> &'a i32>(F); + | ^^^ +help: consider introducing a Higher-Ranked lifetime `'a` here + | +LL | struct S1 Fn(&i32, &i32) -> &'a i32>(F); + | ^^^^^^^ + +error[E0106]: missing lifetime specifier + --> $DIR/fn-missing-lifetime-in-item.rs:2:32 + | +LL | struct S2 &i32>(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 + --> $DIR/fn-missing-lifetime-in-item.rs:2:17 + | +LL | struct S2 &i32>(F); + | ^^^^ ^^^^ + = note: for more information on Higher-Ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider introducing a Higher-Ranked lifetime + | +LL | struct S2 Fn(&'r i32, &'r i32) -> &'r i32>(F); + | ^^^^^^^ ^^^^^^^ ^^^^^^^ ^^^ +help: consider introducing a named lifetime parameter + | +LL | struct S2<'r, F: Fn(&'r i32, &'r i32) -> &'r i32>(F); + | ^^^ ^^^^^^^ ^^^^^^^ ^^^ + +error[E0582]: binding for associated type `Output` references lifetime `'a`, which does not appear in the trait input types + --> $DIR/fn-missing-lifetime-in-item.rs:3:40 + | +LL | struct S3 Fn(&i32, &i32) -> &'a i32>(F); + | ^^^^^^^ + +error[E0582]: binding for associated type `Output` references lifetime `'a`, which does not appear in the trait input types + --> $DIR/fn-missing-lifetime-in-item.rs:6:55 + | +LL | const C: Option Fn(&usize, &usize) -> &'a usize>> = None; + | ^^^^^^^^^ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0106, E0261, E0582. +For more information about an error, try `rustc --explain E0106`. 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 1e15196f8ec85..459000a3722ca 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 @@ -11,7 +11,7 @@ LL | let _: dyn Foo(&isize, &usize) -> &usize; | ^^^^^^ ^^^^^^ help: consider introducing a named lifetime parameter | -LL | fn main<'lifetime>() { +LL | fn main<'r>() { 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)>, 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 04df2e4570396..d0efd788dc1a9 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 @@ -6,8 +6,8 @@ LL | x: Box, | help: consider introducing a named lifetime parameter | -LL | struct Foo<'lifetime> { -LL | x: Box, +LL | struct Foo<'r> { +LL | x: Box, | error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound 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 97014dae2b970..998028622c265 100644 --- a/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr +++ b/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr @@ -11,8 +11,8 @@ LL | fn foo(x: &u32, y: &u32) -> &'_ u32 { loop { } } | ^^^^ ^^^^ help: consider introducing a named lifetime parameter | -LL | fn foo<'lifetime>(x: &'lifetime u32, y: &'lifetime u32) -> &'lifetime u32 { loop { } } - | ^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^ +LL | fn foo<'r>(x: &'r u32, y: &'r u32) -> &'r 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 e01b39a4b64f4..406e0a92013d4 100644 --- a/src/test/ui/underscore-lifetime/in-struct.stderr +++ b/src/test/ui/underscore-lifetime/in-struct.stderr @@ -6,8 +6,8 @@ LL | x: &'_ u32, | help: consider introducing a named lifetime parameter | -LL | struct Foo<'lifetime> { -LL | x: &'lifetime u32, +LL | struct Foo<'r> { +LL | x: &'r u32, | error[E0106]: missing lifetime specifier @@ -18,8 +18,8 @@ LL | Variant(&'_ u32), | help: consider introducing a named lifetime parameter | -LL | enum Bar<'lifetime> { -LL | Variant(&'lifetime u32), +LL | enum Bar<'r> { +LL | Variant(&'r 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 ef3ad18ee8861..94f3499df5f26 100644 --- a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr +++ b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr @@ -37,8 +37,8 @@ LL | fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y } | ^^^^^^ ^^^^^^ help: consider introducing a named lifetime parameter | -LL | fn foo2<'lifetime>(_: &'_ u8, y: &'_ u8) -> &'lifetime u8 { y } - | ^^^^^^^^^^^ ^^^^^^^^^ +LL | fn foo2<'r>(_: &'_ u8, y: &'_ u8) -> &'r u8 { y } + | ^^^^ ^^ error: aborting due to 5 previous errors From 2100b31535a2a6a51876c024591b9e5679692a9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 27 Jan 2020 14:08:59 -0800 Subject: [PATCH 05/12] review comments --- src/librustc_hir/hir.rs | 2 +- src/librustc_resolve/diagnostics.rs | 20 +++++++++---------- src/librustc_resolve/lifetimes.rs | 4 ++-- src/test/ui/error-codes/E0106.stderr | 14 ++++++------- .../assoc-type.stderr | 4 ++-- ...anon-lifetime-in-struct-declaration.stderr | 2 +- src/test/ui/issues/issue-19707.stderr | 10 +++++----- src/test/ui/issues/issue-26638.stderr | 2 +- src/test/ui/issues/issue-30255.stderr | 6 +++--- ...urn-type-requires-explicit-lifetime.stderr | 4 ++-- .../ex1b-return-no-names-if-else.stderr | 2 +- src/test/ui/proc-macro/item-error.stderr | 4 ++-- .../ui/regions/regions-in-enums-anon.stderr | 4 ++-- .../ui/regions/regions-in-structs-anon.stderr | 4 ++-- .../ui/regions/regions-name-undeclared.stderr | 8 ++++---- .../fn-missing-lifetime-in-item.stderr | 12 +++++------ ...oxed-closure-sugar-lifetime-elision.stderr | 2 +- .../dyn-trait-underscore-in-struct.stderr | 4 ++-- .../in-fn-return-illegal.stderr | 2 +- .../ui/underscore-lifetime/in-struct.stderr | 8 ++++---- .../underscore-lifetime-binders.stderr | 2 +- 21 files changed, 60 insertions(+), 60 deletions(-) diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index 86252203f1d45..0c93a192667e5 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -2263,7 +2263,7 @@ pub struct PolyTraitRef<'hir> { /// The `'a` in `for<'a> Foo<&'a T>`. pub bound_generic_params: &'hir [GenericParam<'hir>], - /// The `Foo<&'a T>` in `for <'a> Foo<&'a T>`. + /// The `Foo<&'a T>` in `for<'a> Foo<&'a T>`. pub trait_ref: TraitRef<'hir>, pub span: Span, diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 8346dc3b85425..b62c9f4747c0b 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -1498,20 +1498,20 @@ crate fn add_missing_lifetime_specifiers_label( msg = "consider introducing a named lifetime parameter"; should_break = true; match &generics.params { - [] => (generics.span, "<'r>".to_string()), - [param, ..] => (param.span.shrink_to_lo(), "'r, ".to_string()), + [] => (generics.span, "<'a>".to_string()), + [param, ..] => (param.span.shrink_to_lo(), "'a, ".to_string()), } } MissingLifetimeSpot::HRLT { span, span_type } => { - msg = "consider introducing a Higher-Ranked lifetime"; + msg = "consider introducing a higher-ranked lifetime"; should_break = false; err.note( - "for more information on Higher-Ranked lifetimes, visit \ + "for more information on higher-ranked lifetimes, visit \ https://doc.rust-lang.org/nomicon/hrtb.html", ); let suggestion = match span_type { - HRLTSpanType::Empty => "for<'r> ", - HRLTSpanType::Tail => ", 'r", + HRLTSpanType::Empty => "for<'a> ", + HRLTSpanType::Tail => ", 'a", }; (*span, suggestion.to_string()) } @@ -1520,7 +1520,7 @@ crate fn add_missing_lifetime_specifiers_label( if let Ok(snippet) = source_map.span_to_snippet(param.span) { if snippet.starts_with("&") && !snippet.starts_with("&'") { introduce_suggestion - .push((param.span, format!("&'r {}", &snippet[1..]))); + .push((param.span, format!("&'a {}", &snippet[1..]))); } } } @@ -1543,13 +1543,13 @@ crate fn add_missing_lifetime_specifiers_label( suggest_existing(err, format!("{}<{}>", snippet, name)); } (0, _, Some("&")) => { - suggest_new(err, "&'r "); + suggest_new(err, "&'a "); } (0, _, Some("'_")) => { - suggest_new(err, "'r"); + suggest_new(err, "'a"); } (0, _, Some(snippet)) if !snippet.ends_with(">") => { - suggest_new(err, &format!("{}<'r>", snippet)); + suggest_new(err, &format!("{}<'a>", snippet)); } _ => { err.span_label(span, "expected lifetime parameter"); diff --git a/src/librustc_resolve/lifetimes.rs b/src/librustc_resolve/lifetimes.rs index 97d314c8f65a9..69deffe4a4c9a 100644 --- a/src/librustc_resolve/lifetimes.rs +++ b/src/librustc_resolve/lifetimes.rs @@ -1873,7 +1873,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { err.span_suggestion( *span, &format!( - "consider introducing a Higher-Ranked lifetime `{}` here", + "consider introducing a higher-ranked lifetime `{}` here", lifetime_ref ), match span_type { @@ -1884,7 +1884,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { Applicability::MaybeIncorrect, ); err.note( - "for more information on Higher-Ranked lifetimes, visit \ + "for more information on higher-ranked lifetimes, visit \ https://doc.rust-lang.org/nomicon/hrtb.html", ); } diff --git a/src/test/ui/error-codes/E0106.stderr b/src/test/ui/error-codes/E0106.stderr index 3792b8f637aa0..a23bcbfd71a56 100644 --- a/src/test/ui/error-codes/E0106.stderr +++ b/src/test/ui/error-codes/E0106.stderr @@ -6,8 +6,8 @@ LL | x: &bool, | help: consider introducing a named lifetime parameter | -LL | struct Foo<'r> { -LL | x: &'r bool, +LL | struct Foo<'a> { +LL | x: &'a bool, | error[E0106]: missing lifetime specifier @@ -18,9 +18,9 @@ LL | B(&bool), | help: consider introducing a named lifetime parameter | -LL | enum Bar<'r> { +LL | enum Bar<'a> { LL | A(u8), -LL | B(&'r bool), +LL | B(&'a bool), | error[E0106]: missing lifetime specifier @@ -31,7 +31,7 @@ LL | type MyStr = &str; | help: consider introducing a named lifetime parameter | -LL | type MyStr<'r> = &'r str; +LL | type MyStr<'a> = &'a str; | ^^^^ ^^^ error[E0106]: missing lifetime specifier @@ -42,8 +42,8 @@ LL | baz: Baz, | help: consider introducing a named lifetime parameter | -LL | struct Quux<'r> { -LL | baz: Baz<'r>, +LL | struct Quux<'a> { +LL | baz: Baz<'a>, | error[E0106]: missing lifetime specifiers 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 d3968917bed54..211a3286cc355 100644 --- a/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr +++ b/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr @@ -6,7 +6,7 @@ LL | type Output = &i32; | help: consider introducing a named lifetime parameter | -LL | type Output<'r> = &'r i32; +LL | type Output<'a> = &'a i32; | ^^^^ ^^^ error[E0106]: missing lifetime specifier @@ -17,7 +17,7 @@ LL | type Output = &'_ i32; | help: consider introducing a named lifetime parameter | -LL | type Output<'r> = &'r i32; +LL | type Output<'a> = &'a 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 3688b222a3508..f2a4150632d2f 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 @@ -6,7 +6,7 @@ LL | struct Heartbreak(Betrayal); | help: consider introducing a named lifetime parameter | -LL | struct Heartbreak<'r>(Betrayal<'r>); +LL | struct Heartbreak<'a>(Betrayal<'a>); | ^^^^ ^^^^^^^^^^^^ 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 8246b0e54019f..e84bfb969d4f9 100644 --- a/src/test/ui/issues/issue-19707.stderr +++ b/src/test/ui/issues/issue-19707.stderr @@ -11,7 +11,7 @@ LL | type Foo = fn(&u8, &u8) -> &u8; | ^^^ ^^^ help: consider introducing a named lifetime parameter | -LL | type Foo<'r> = fn(&'r u8, &'r u8) -> &'r u8; +LL | type Foo<'a> = fn(&'a u8, &'a u8) -> &'a u8; | ^^^^ ^^^^^^ ^^^^^^ ^^^ error[E0106]: missing lifetime specifier @@ -25,14 +25,14 @@ help: this function's return type contains a borrowed value, but the signature d | LL | fn bar &u8>(f: &F) {} | ^^^ ^^^ - = note: for more information on Higher-Ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html -help: consider introducing a Higher-Ranked lifetime + = note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider introducing a higher-ranked lifetime | -LL | fn bar Fn(&'r u8, &'r u8) -> &'r u8>(f: &F) {} +LL | fn bar Fn(&'a u8, &'a u8) -> &'a u8>(f: &F) {} | ^^^^^^^ ^^^^^^ ^^^^^^ ^^^ help: consider introducing a named lifetime parameter | -LL | fn bar<'r, F: Fn(&'r u8, &'r u8) -> &'r u8>(f: &F) {} +LL | fn bar<'a, F: Fn(&'a u8, &'a u8) -> &'a 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 8c114cf1ae8b4..75cd5332fd9a4 100644 --- a/src/test/ui/issues/issue-26638.stderr +++ b/src/test/ui/issues/issue-26638.stderr @@ -11,7 +11,7 @@ LL | fn parse_type(iter: Box+'static>) -> &str { iter.ne | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider introducing a named lifetime parameter | -LL | fn parse_type<'r>(iter: Box+'static>) -> &'r str { iter.next() } +LL | fn parse_type<'a>(iter: Box+'static>) -> &'a str { iter.next() } | ^^^^ ^^^ error[E0106]: missing lifetime specifier diff --git a/src/test/ui/issues/issue-30255.stderr b/src/test/ui/issues/issue-30255.stderr index fff3766e12dc7..3c26365d5d168 100644 --- a/src/test/ui/issues/issue-30255.stderr +++ b/src/test/ui/issues/issue-30255.stderr @@ -11,7 +11,7 @@ LL | fn f(a: &S, b: i32) -> &i32 { | ^^ help: consider introducing a named lifetime parameter | -LL | fn f<'r>(a: &'r S, b: i32) -> &'r i32 { +LL | fn f<'a>(a: &'a S, b: i32) -> &'a i32 { | ^^^^ ^^^^^ ^^^ error[E0106]: missing lifetime specifier @@ -27,7 +27,7 @@ LL | fn g(a: &S, b: bool, c: &i32) -> &i32 { | ^^ ^^^^ help: consider introducing a named lifetime parameter | -LL | fn g<'r>(a: &'r S, b: bool, c: &'r i32) -> &'r i32 { +LL | fn g<'a>(a: &'a S, b: bool, c: &'a i32) -> &'a i32 { | ^^^^ ^^^^^ ^^^^^^^ ^^^ error[E0106]: missing lifetime specifier @@ -43,7 +43,7 @@ LL | fn h(a: &bool, b: bool, c: &S, d: &i32) -> &i32 { | ^^^^^ ^^ ^^^^ help: consider introducing a named lifetime parameter | -LL | fn h<'r>(a: &'r bool, b: bool, c: &'r S, d: &'r i32) -> &'r i32 { +LL | fn h<'a>(a: &'a bool, b: bool, c: &'a S, d: &'a i32) -> &'a 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 638c8b8612cf2..b81ce552b3908 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 @@ -19,7 +19,7 @@ LL | fn g(_x: &isize, _y: &isize) -> &isize { | ^^^^^^ ^^^^^^ help: consider introducing a named lifetime parameter | -LL | fn g<'r>(_x: &'r isize, _y: &'r isize) -> &'r isize { +LL | fn g<'a>(_x: &'a isize, _y: &'a isize) -> &'a isize { | ^^^^ ^^^^^^^^^ ^^^^^^^^^ ^^^ error[E0106]: missing lifetime specifier @@ -35,7 +35,7 @@ LL | fn h(_x: &Foo) -> &isize { | ^^^^ help: consider introducing a named lifetime parameter | -LL | fn h<'r>(_x: &'r Foo) -> &'r isize { +LL | fn h<'a>(_x: &'a Foo) -> &'a isize { | ^^^^ ^^^^^^^ ^^^ error[E0106]: missing lifetime specifier 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 e1982ea393ef4..47b048a7a9779 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 @@ -11,7 +11,7 @@ LL | fn foo(x: &i32, y: &i32) -> &i32 { | ^^^^ ^^^^ help: consider introducing a named lifetime parameter | -LL | fn foo<'r>(x: &'r i32, y: &'r i32) -> &'r i32 { +LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a 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 be33f2e2f7695..27f7639d213d2 100644 --- a/src/test/ui/proc-macro/item-error.stderr +++ b/src/test/ui/proc-macro/item-error.stderr @@ -6,8 +6,8 @@ LL | a: &u64 | help: consider introducing a named lifetime parameter | -LL | struct A<'r> { -LL | a: &'r u64 +LL | struct A<'a> { +LL | a: &'a 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 46555df59367e..b3649c5b48530 100644 --- a/src/test/ui/regions/regions-in-enums-anon.stderr +++ b/src/test/ui/regions/regions-in-enums-anon.stderr @@ -6,8 +6,8 @@ LL | Bar(&isize) | help: consider introducing a named lifetime parameter | -LL | enum Foo<'r> { -LL | Bar(&'r isize) +LL | enum Foo<'a> { +LL | Bar(&'a 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 e807810db26fb..60a6fb9a0fad9 100644 --- a/src/test/ui/regions/regions-in-structs-anon.stderr +++ b/src/test/ui/regions/regions-in-structs-anon.stderr @@ -6,8 +6,8 @@ LL | x: &isize | help: consider introducing a named lifetime parameter | -LL | struct Foo<'r> { -LL | x: &'r isize +LL | struct Foo<'a> { +LL | x: &'a isize | error: aborting due to previous error diff --git a/src/test/ui/regions/regions-name-undeclared.stderr b/src/test/ui/regions/regions-name-undeclared.stderr index cb72d1ec9bc71..498667abe36d9 100644 --- a/src/test/ui/regions/regions-name-undeclared.stderr +++ b/src/test/ui/regions/regions-name-undeclared.stderr @@ -89,12 +89,12 @@ error[E0261]: use of undeclared lifetime name `'b` LL | ... &'b isize, | ^^ undeclared lifetime | - = note: for more information on Higher-Ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html + = note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider introducing lifetime `'b` here | LL | fn fn_types<'b>(a: &'a isize, | ^^^^ -help: consider introducing a Higher-Ranked lifetime `'b` here +help: consider introducing a higher-ranked lifetime `'b` here | LL | b: Box FnOnce(&'a isize, | ^^^^ @@ -105,12 +105,12 @@ error[E0261]: use of undeclared lifetime name `'b` LL | ... &'b isize)>, | ^^ undeclared lifetime | - = note: for more information on Higher-Ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html + = note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider introducing lifetime `'b` here | LL | fn fn_types<'b>(a: &'a isize, | ^^^^ -help: consider introducing a Higher-Ranked lifetime `'b` here +help: consider introducing a higher-ranked lifetime `'b` here | LL | b: Box FnOnce(&'a isize, | ^^^^ diff --git a/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr b/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr index c1a40ebc89286..858f23f1362cc 100644 --- a/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr +++ b/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr @@ -4,12 +4,12 @@ error[E0261]: use of undeclared lifetime name `'a` LL | struct S1 &'a i32>(F); | ^^ undeclared lifetime | - = note: for more information on Higher-Ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html + = note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider introducing lifetime `'a` here | LL | struct S1<'a, F: Fn(&i32, &i32) -> &'a i32>(F); | ^^^ -help: consider introducing a Higher-Ranked lifetime `'a` here +help: consider introducing a higher-ranked lifetime `'a` here | LL | struct S1 Fn(&i32, &i32) -> &'a i32>(F); | ^^^^^^^ @@ -25,14 +25,14 @@ help: this function's return type contains a borrowed value, but the signature d | LL | struct S2 &i32>(F); | ^^^^ ^^^^ - = note: for more information on Higher-Ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html -help: consider introducing a Higher-Ranked lifetime + = note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider introducing a higher-ranked lifetime | -LL | struct S2 Fn(&'r i32, &'r i32) -> &'r i32>(F); +LL | struct S2 Fn(&'a i32, &'a i32) -> &'a i32>(F); | ^^^^^^^ ^^^^^^^ ^^^^^^^ ^^^ help: consider introducing a named lifetime parameter | -LL | struct S2<'r, F: Fn(&'r i32, &'r i32) -> &'r i32>(F); +LL | struct S2<'a, F: Fn(&'a i32, &'a i32) -> &'a i32>(F); | ^^^ ^^^^^^^ ^^^^^^^ ^^^ error[E0582]: binding for associated type `Output` references lifetime `'a`, which does not appear in the trait input types 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 459000a3722ca..2431e8ece3807 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 @@ -11,7 +11,7 @@ LL | let _: dyn Foo(&isize, &usize) -> &usize; | ^^^^^^ ^^^^^^ help: consider introducing a named lifetime parameter | -LL | fn main<'r>() { +LL | fn main<'a>() { 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)>, 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 d0efd788dc1a9..fe242e6a909e3 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 @@ -6,8 +6,8 @@ LL | x: Box, | help: consider introducing a named lifetime parameter | -LL | struct Foo<'r> { -LL | x: Box, +LL | struct Foo<'a> { +LL | x: Box, | error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound 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 998028622c265..0e410e25ecf25 100644 --- a/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr +++ b/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr @@ -11,7 +11,7 @@ LL | fn foo(x: &u32, y: &u32) -> &'_ u32 { loop { } } | ^^^^ ^^^^ help: consider introducing a named lifetime parameter | -LL | fn foo<'r>(x: &'r u32, y: &'r u32) -> &'r u32 { loop { } } +LL | fn foo<'a>(x: &'a u32, y: &'a u32) -> &'a 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 406e0a92013d4..4275cc26f735f 100644 --- a/src/test/ui/underscore-lifetime/in-struct.stderr +++ b/src/test/ui/underscore-lifetime/in-struct.stderr @@ -6,8 +6,8 @@ LL | x: &'_ u32, | help: consider introducing a named lifetime parameter | -LL | struct Foo<'r> { -LL | x: &'r u32, +LL | struct Foo<'a> { +LL | x: &'a u32, | error[E0106]: missing lifetime specifier @@ -18,8 +18,8 @@ LL | Variant(&'_ u32), | help: consider introducing a named lifetime parameter | -LL | enum Bar<'r> { -LL | Variant(&'r u32), +LL | enum Bar<'a> { +LL | Variant(&'a 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 94f3499df5f26..f2eab86ae57ad 100644 --- a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr +++ b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr @@ -37,7 +37,7 @@ LL | fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y } | ^^^^^^ ^^^^^^ help: consider introducing a named lifetime parameter | -LL | fn foo2<'r>(_: &'_ u8, y: &'_ u8) -> &'r u8 { y } +LL | fn foo2<'a>(_: &'_ u8, y: &'_ u8) -> &'a u8 { y } | ^^^^ ^^ error: aborting due to 5 previous errors From ba3b44c508b133829f7b6a57f3e62c0735a7d110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 27 Jan 2020 14:35:20 -0800 Subject: [PATCH 06/12] Account for `'_` in suggestions --- src/librustc_resolve/diagnostics.rs | 3 +++ .../ui/underscore-lifetime/underscore-lifetime-binders.stderr | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index b62c9f4747c0b..3b689f03b43ba 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -1521,6 +1521,9 @@ crate fn add_missing_lifetime_specifiers_label( if snippet.starts_with("&") && !snippet.starts_with("&'") { introduce_suggestion .push((param.span, format!("&'a {}", &snippet[1..]))); + } else if snippet.starts_with("&'_ ") { + introduce_suggestion + .push((param.span, format!("&'a {}", &snippet[4..]))); } } } diff --git a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr index f2eab86ae57ad..d0eda1b615381 100644 --- a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr +++ b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr @@ -37,8 +37,8 @@ LL | fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y } | ^^^^^^ ^^^^^^ help: consider introducing a named lifetime parameter | -LL | fn foo2<'a>(_: &'_ u8, y: &'_ u8) -> &'a u8 { y } - | ^^^^ ^^ +LL | fn foo2<'a>(_: &'a u8, y: &'a u8) -> &'a u8 { y } + | ^^^^ ^^^^^^ ^^^^^^ ^^ error: aborting due to 5 previous errors From 92505df338a860f1055241a07949de2af7ddc6b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 27 Jan 2020 16:13:45 -0800 Subject: [PATCH 07/12] Account for `fn()` types in lifetime suggestions --- src/librustc_resolve/diagnostics.rs | 24 +++++-- src/librustc_resolve/lifetimes.rs | 64 ++++++++++++------- .../async-await/issues/issue-63388-2.stderr | 8 +-- .../ui/generic/generic-extern-lifetime.stderr | 12 ++++ .../no_introducing_in_band_in_locals.stderr | 12 +++- src/test/ui/issues/issue-19707.stderr | 21 +++--- src/test/ui/issues/issue-26638.stderr | 8 +-- src/test/ui/issues/issue-30255.stderr | 24 ++----- ...urn-type-requires-explicit-lifetime.stderr | 16 ++--- .../ex1b-return-no-names-if-else.stderr | 8 +-- .../ui/regions/regions-name-undeclared.stderr | 4 +- src/test/ui/rfc1623-2.rs | 13 ++++ src/test/ui/rfc1623-2.stderr | 29 +++++++++ src/test/ui/rfc1623.rs | 13 ++-- src/test/ui/rfc1623.stderr | 55 ++++++++++------ .../fn-missing-lifetime-in-item.stderr | 12 ++-- .../return-without-lifetime.stderr | 16 ++--- ...oxed-closure-sugar-lifetime-elision.stderr | 8 +-- .../in-fn-return-illegal.stderr | 8 +-- .../underscore-lifetime-binders.stderr | 8 +-- 20 files changed, 210 insertions(+), 153 deletions(-) create mode 100644 src/test/ui/rfc1623-2.rs create mode 100644 src/test/ui/rfc1623-2.stderr diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 3b689f03b43ba..8213a99a92d1e 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -19,7 +19,7 @@ use syntax::ast::{self, Ident, Path}; use syntax::util::lev_distance::find_best_match_for_name; use crate::imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver}; -use crate::lifetimes::{ElisionFailureInfo, HRLTSpanType, MissingLifetimeSpot}; +use crate::lifetimes::{ElisionFailureInfo, ForLifetimeSpanType, MissingLifetimeSpot}; use crate::path_names_to_string; use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind}; use crate::{BindingError, CrateLint, HasGenericParams, LegacyScope, Module, ModuleOrUniformRoot}; @@ -1495,7 +1495,7 @@ crate fn add_missing_lifetime_specifiers_label( let should_break; introduce_suggestion.push(match missing { MissingLifetimeSpot::Generics(generics) => { - msg = "consider introducing a named lifetime parameter"; + msg = "consider introducing a named lifetime parameter".to_string(); should_break = true; match &generics.params { [] => (generics.span, "<'a>".to_string()), @@ -1503,15 +1503,27 @@ crate fn add_missing_lifetime_specifiers_label( } } MissingLifetimeSpot::HRLT { span, span_type } => { - msg = "consider introducing a higher-ranked lifetime"; + msg = format!( + "consider making the {} lifetime-generic with a new `'a` lifetime", + match span_type { + ForLifetimeSpanType::BoundEmpty + | ForLifetimeSpanType::BoundTail => "bound", + ForLifetimeSpanType::TypeEmpty | ForLifetimeSpanType::TypeTail => + "type", + } + ); should_break = false; err.note( "for more information on higher-ranked lifetimes, visit \ https://doc.rust-lang.org/nomicon/hrtb.html", ); let suggestion = match span_type { - HRLTSpanType::Empty => "for<'a> ", - HRLTSpanType::Tail => ", 'a", + ForLifetimeSpanType::BoundEmpty | ForLifetimeSpanType::TypeEmpty => { + "for<'a> " + } + ForLifetimeSpanType::BoundTail | ForLifetimeSpanType::TypeTail => { + ", 'a" + } }; (*span, suggestion.to_string()) } @@ -1528,7 +1540,7 @@ crate fn add_missing_lifetime_specifiers_label( } } introduce_suggestion.push((span, sugg.to_string())); - err.multipart_suggestion(msg, introduce_suggestion, Applicability::MaybeIncorrect); + err.multipart_suggestion(&msg, introduce_suggestion, Applicability::MaybeIncorrect); if should_break { break; } diff --git a/src/librustc_resolve/lifetimes.rs b/src/librustc_resolve/lifetimes.rs index 69deffe4a4c9a..9bb852b2093aa 100644 --- a/src/librustc_resolve/lifetimes.rs +++ b/src/librustc_resolve/lifetimes.rs @@ -155,12 +155,14 @@ struct NamedRegionMap { crate enum MissingLifetimeSpot<'tcx> { Generics(&'tcx hir::Generics<'tcx>), - HRLT { span: Span, span_type: HRLTSpanType }, + HRLT { span: Span, span_type: ForLifetimeSpanType }, } -crate enum HRLTSpanType { - Empty, - Tail, +crate enum ForLifetimeSpanType { + BoundEmpty, + BoundTail, + TypeEmpty, + TypeTail, } impl<'tcx> Into> for &'tcx hir::Generics<'tcx> { @@ -509,6 +511,21 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let next_early_index = self.next_early_index(); let was_in_fn_syntax = self.is_in_fn_syntax; self.is_in_fn_syntax = true; + let lifetime_span: Option = c + .generic_params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => Some(param.span), + _ => None, + }) + .last(); + let (span, span_type) = if let Some(span) = lifetime_span { + (span.shrink_to_hi(), ForLifetimeSpanType::TypeTail) + } else { + (ty.span.shrink_to_lo(), ForLifetimeSpanType::TypeEmpty) + }; + self.missing_named_lifetime_spots + .push(MissingLifetimeSpot::HRLT { span, span_type }); let scope = Scope::Binder { lifetimes: c .generic_params @@ -531,6 +548,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { this.check_lifetime_params(old_scope, &c.generic_params); intravisit::walk_ty(this, ty); }); + self.missing_named_lifetime_spots.pop(); self.is_in_fn_syntax = was_in_fn_syntax; } hir::TyKind::TraitObject(bounds, ref lifetime) => { @@ -1873,12 +1891,23 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { err.span_suggestion( *span, &format!( - "consider introducing a higher-ranked lifetime `{}` here", + "consider making the {} lifetime-generic with a new `{}` lifetime", + match span_type { + ForLifetimeSpanType::BoundEmpty + | ForLifetimeSpanType::BoundTail => "bound", + ForLifetimeSpanType::TypeEmpty + | ForLifetimeSpanType::TypeTail => "type", + }, lifetime_ref ), match span_type { - HRLTSpanType::Empty => format!("for<{}> ", lifetime_ref), - HRLTSpanType::Tail => format!(", {}", lifetime_ref), + ForLifetimeSpanType::TypeEmpty + | ForLifetimeSpanType::BoundEmpty => { + format!("for<{}> ", lifetime_ref) + } + ForLifetimeSpanType::TypeTail | ForLifetimeSpanType::BoundTail => { + format!(", {}", lifetime_ref) + } } .to_string(), Applicability::MaybeIncorrect, @@ -2487,13 +2516,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { params.iter().cloned().filter(|info| info.lifetime_count > 0).collect(); let elided_len = elided_params.len(); - let mut spans = vec![]; for (i, info) in elided_params.into_iter().enumerate() { let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } = info; - spans.push(span); + db.span_label(span, ""); let help_name = if let Some(ident) = parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident()) { @@ -2524,14 +2552,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } - let help = |msg| { - if spans.is_empty() { - db.help(msg); - } else { - db.span_help(spans, msg); - } - }; - if len == 0 { db.help( "this function's return type contains a borrowed value, \ @@ -2539,7 +2559,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { ); self.suggest_lifetime(db, span, "consider giving it a 'static lifetime") } else if elided_len == 0 { - help( + db.help( "this function's return type contains a borrowed value with \ an elided lifetime, but the lifetime cannot be derived from \ the arguments", @@ -2547,14 +2567,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let msg = "consider giving it an explicit bounded or 'static lifetime"; self.suggest_lifetime(db, span, msg) } else if elided_len == 1 { - help(&format!( + db.help(&format!( "this function's return type contains a borrowed value, \ but the signature does not say which {} it is borrowed from", m )); true } else { - help(&format!( + db.help(&format!( "this function's return type contains a borrowed value, \ but the signature does not say whether it is borrowed from {}", m @@ -2816,8 +2836,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { .contains(&Some(did)) { let (span, span_type) = match &trait_ref.bound_generic_params { - [] => (trait_ref.span.shrink_to_lo(), HRLTSpanType::Empty), - [.., bound] => (bound.span.shrink_to_hi(), HRLTSpanType::Tail), + [] => (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty), + [.., bound] => (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail), }; self.missing_named_lifetime_spots .push(MissingLifetimeSpot::HRLT { span, span_type }); diff --git a/src/test/ui/async-await/issues/issue-63388-2.stderr b/src/test/ui/async-await/issues/issue-63388-2.stderr index a12c601b936af..9f51ced9c3f49 100644 --- a/src/test/ui/async-await/issues/issue-63388-2.stderr +++ b/src/test/ui/async-await/issues/issue-63388-2.stderr @@ -1,14 +1,12 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-63388-2.rs:12:10 | +LL | foo: &dyn Foo, bar: &'a dyn Foo + | -------- ----------- LL | ) -> &dyn Foo | ^ help: consider using the named lifetime: `&'a` | -help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `foo` or `bar` - --> $DIR/issue-63388-2.rs:11:14 - | -LL | foo: &dyn Foo, bar: &'a dyn Foo - | ^^^^^^^^ ^^^^^^^^^^^ + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `foo` or `bar` error: cannot infer an appropriate lifetime --> $DIR/issue-63388-2.rs:11:9 diff --git a/src/test/ui/generic/generic-extern-lifetime.stderr b/src/test/ui/generic/generic-extern-lifetime.stderr index 39372c9315831..5e25952390b2d 100644 --- a/src/test/ui/generic/generic-extern-lifetime.stderr +++ b/src/test/ui/generic/generic-extern-lifetime.stderr @@ -9,12 +9,24 @@ error[E0261]: use of undeclared lifetime name `'a` | LL | pub fn life4<'b>(x: for<'c> fn(&'a i32)); | ^^ undeclared lifetime + | + = note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the type lifetime-generic with a new `'a` lifetime + | +LL | pub fn life4<'b>(x: for<'c, 'a> fn(&'a i32)); + | ^^^^ error[E0261]: use of undeclared lifetime name `'a` --> $DIR/generic-extern-lifetime.rs:11:38 | LL | pub fn life7<'b>() -> for<'c> fn(&'a i32); | ^^ undeclared lifetime + | + = note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the type lifetime-generic with a new `'a` lifetime + | +LL | pub fn life7<'b>() -> for<'c, 'a> fn(&'a i32); + | ^^^^ error: aborting due to 3 previous errors 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 7d71230e16210..5abaf3c3aefff 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 @@ -9,10 +9,18 @@ LL | let y: &'test u32 = x; error[E0261]: use of undeclared lifetime name `'test` --> $DIR/no_introducing_in_band_in_locals.rs:10:16 | -LL | fn bar() { - | - help: consider introducing lifetime `'test` here: `<'test>` LL | let y: fn(&'test u32) = foo2; | ^^^^^ undeclared lifetime + | + = note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider introducing lifetime `'test` here + | +LL | fn bar<'test>() { + | ^^^^^^^ +help: consider making the type lifetime-generic with a new `'test` lifetime + | +LL | let y: for<'test> fn(&'test u32) = foo2; + | ^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-19707.stderr b/src/test/ui/issues/issue-19707.stderr index e84bfb969d4f9..398e97a6f207a 100644 --- a/src/test/ui/issues/issue-19707.stderr +++ b/src/test/ui/issues/issue-19707.stderr @@ -2,13 +2,14 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-19707.rs:3:28 | LL | type Foo = fn(&u8, &u8) -> &u8; - | ^ expected named 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 - --> $DIR/issue-19707.rs:3:15 + = 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 + = note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the type lifetime-generic with a new `'a` lifetime | -LL | type Foo = fn(&u8, &u8) -> &u8; - | ^^^ ^^^ +LL | type Foo = for<'a> fn(&'a u8, &'a u8) -> &'a u8; + | ^^^^^^^ ^^^^^^ ^^^^^^ ^^^ help: consider introducing a named lifetime parameter | LL | type Foo<'a> = fn(&'a u8, &'a u8) -> &'a u8; @@ -18,15 +19,11 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-19707.rs:5:27 | LL | fn bar &u8>(f: &F) {} - | ^ expected named 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 - --> $DIR/issue-19707.rs:5:14 - | -LL | fn bar &u8>(f: &F) {} - | ^^^ ^^^ + = 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 = note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html -help: consider introducing a higher-ranked lifetime +help: consider making the bound lifetime-generic with a new `'a` lifetime | LL | fn bar Fn(&'a u8, &'a u8) -> &'a u8>(f: &F) {} | ^^^^^^^ ^^^^^^ ^^^^^^ ^^^ diff --git a/src/test/ui/issues/issue-26638.stderr b/src/test/ui/issues/issue-26638.stderr index 75cd5332fd9a4..1d8fbdc63c5e0 100644 --- a/src/test/ui/issues/issue-26638.stderr +++ b/src/test/ui/issues/issue-26638.stderr @@ -2,13 +2,9 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-26638.rs:1:62 | LL | fn parse_type(iter: Box+'static>) -> &str { iter.next() } - | ^ expected named 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 - --> $DIR/issue-26638.rs:1:21 - | -LL | fn parse_type(iter: Box+'static>) -> &str { iter.next() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = 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 parameter | LL | fn parse_type<'a>(iter: Box+'static>) -> &'a str { iter.next() } diff --git a/src/test/ui/issues/issue-30255.stderr b/src/test/ui/issues/issue-30255.stderr index 3c26365d5d168..ab43d4a3c6002 100644 --- a/src/test/ui/issues/issue-30255.stderr +++ b/src/test/ui/issues/issue-30255.stderr @@ -2,13 +2,9 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-30255.rs:9:24 | LL | fn f(a: &S, b: i32) -> &i32 { - | ^ expected named 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 - --> $DIR/issue-30255.rs:9:9 - | -LL | fn f(a: &S, b: i32) -> &i32 { - | ^^ + = 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 parameter | LL | fn f<'a>(a: &'a S, b: i32) -> &'a i32 { @@ -18,13 +14,9 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-30255.rs:14:34 | 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` - --> $DIR/issue-30255.rs:14:9 + | -- ---- ^ expected named lifetime parameter | -LL | fn g(a: &S, b: bool, c: &i32) -> &i32 { - | ^^ ^^^^ + = 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 parameter | LL | fn g<'a>(a: &'a S, b: bool, c: &'a i32) -> &'a i32 { @@ -34,13 +26,9 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-30255.rs:19:44 | 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` - --> $DIR/issue-30255.rs:19:9 + | ----- -- ---- ^ expected named lifetime parameter | -LL | fn h(a: &bool, b: bool, c: &S, d: &i32) -> &i32 { - | ^^^^^ ^^ ^^^^ + = 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 parameter | LL | fn h<'a>(a: &'a bool, b: bool, c: &'a S, d: &'a i32) -> &'a 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 b81ce552b3908..461c1832e9af9 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,13 +10,9 @@ 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 named 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` - --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:7:10 - | -LL | fn g(_x: &isize, _y: &isize) -> &isize { - | ^^^^^^ ^^^^^^ + = 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 parameter | LL | fn g<'a>(_x: &'a isize, _y: &'a isize) -> &'a isize { @@ -26,13 +22,9 @@ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:17:19 | LL | fn h(_x: &Foo) -> &isize { - | ^ expected named 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 - --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:17:10 - | -LL | fn h(_x: &Foo) -> &isize { - | ^^^^ + = 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 parameter | LL | fn h<'a>(_x: &'a Foo) -> &'a 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 47b048a7a9779..c1fcab2409f64 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,13 +2,9 @@ error[E0106]: missing lifetime specifier --> $DIR/ex1b-return-no-names-if-else.rs:1:29 | LL | fn foo(x: &i32, y: &i32) -> &i32 { - | ^ expected named 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` - --> $DIR/ex1b-return-no-names-if-else.rs:1:11 - | -LL | fn foo(x: &i32, y: &i32) -> &i32 { - | ^^^^ ^^^^ + = 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 parameter | LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 { diff --git a/src/test/ui/regions/regions-name-undeclared.stderr b/src/test/ui/regions/regions-name-undeclared.stderr index 498667abe36d9..e139e3f425189 100644 --- a/src/test/ui/regions/regions-name-undeclared.stderr +++ b/src/test/ui/regions/regions-name-undeclared.stderr @@ -94,7 +94,7 @@ help: consider introducing lifetime `'b` here | LL | fn fn_types<'b>(a: &'a isize, | ^^^^ -help: consider introducing a higher-ranked lifetime `'b` here +help: consider making the bound lifetime-generic with a new `'b` lifetime | LL | b: Box FnOnce(&'a isize, | ^^^^ @@ -110,7 +110,7 @@ help: consider introducing lifetime `'b` here | LL | fn fn_types<'b>(a: &'a isize, | ^^^^ -help: consider introducing a higher-ranked lifetime `'b` here +help: consider making the bound lifetime-generic with a new `'b` lifetime | LL | b: Box FnOnce(&'a isize, | ^^^^ diff --git a/src/test/ui/rfc1623-2.rs b/src/test/ui/rfc1623-2.rs new file mode 100644 index 0000000000000..35a2ef10c2e3c --- /dev/null +++ b/src/test/ui/rfc1623-2.rs @@ -0,0 +1,13 @@ +#![allow(dead_code)] + +fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { + a +} + +// the boundaries of elision +static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = +//~^ ERROR missing lifetime specifier [E0106] + &(non_elidable as fn(&u8, &u8) -> &u8); + //~^ ERROR missing lifetime specifier [E0106] + +fn main() {} diff --git a/src/test/ui/rfc1623-2.stderr b/src/test/ui/rfc1623-2.stderr new file mode 100644 index 0000000000000..c927ad9e0ba4b --- /dev/null +++ b/src/test/ui/rfc1623-2.stderr @@ -0,0 +1,29 @@ +error[E0106]: missing lifetime specifier + --> $DIR/rfc1623-2.rs:8:42 + | +LL | static NON_ELIDABLE_FN: &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 + = note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the type lifetime-generic with a new `'a` lifetime + | +LL | static NON_ELIDABLE_FN: &for<'a> fn(&'a u8, &'a u8) -> &'a u8 = + | ^^^^^^^ ^^^^^^ ^^^^^^ ^^^ + +error[E0106]: missing lifetime specifier + --> $DIR/rfc1623-2.rs:10:39 + | +LL | &(non_elidable as 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 + = note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the type lifetime-generic with a new `'a` lifetime + | +LL | &(non_elidable as for<'a> fn(&'a u8, &'a u8) -> &'a u8); + | ^^^^^^^ ^^^^^^ ^^^^^^ ^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/rfc1623.rs b/src/test/ui/rfc1623.rs index ebb4d56af9eec..55f5d0b94dcb0 100644 --- a/src/test/ui/rfc1623.rs +++ b/src/test/ui/rfc1623.rs @@ -4,11 +4,10 @@ fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { a } -// the boundaries of elision -static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = -//~^ ERROR missing lifetime specifier [E0106] - &(non_elidable as fn(&u8, &u8) -> &u8); - //~^ ERROR missing lifetime specifier [E0106] +// The incorrect case without `for<'a>` is tested for in `rfc1623-2.rs` +static NON_ELIDABLE_FN: &for<'a> fn(&'a u8, &'a u8) -> &'a u8 = + &(non_elidable as for<'a> fn(&'a u8, &'a u8) -> &'a u8); + struct SomeStruct<'x, 'y, 'z: 'x> { foo: &'x Foo<'z>, @@ -20,10 +19,12 @@ fn id(t: T) -> T { t } -static SOME_STRUCT: &SomeStruct = SomeStruct { +static SOME_STRUCT: &SomeStruct = SomeStruct { //~ ERROR mismatched types foo: &Foo { bools: &[false, true] }, bar: &Bar { bools: &[true, true] }, f: &id, + //~^ ERROR type mismatch in function arguments + //~| ERROR type mismatch resolving }; // very simple test for a 'static static with default lifetime diff --git a/src/test/ui/rfc1623.stderr b/src/test/ui/rfc1623.stderr index aabe088d63ca6..ca956004ef76f 100644 --- a/src/test/ui/rfc1623.stderr +++ b/src/test/ui/rfc1623.stderr @@ -1,27 +1,46 @@ -error[E0106]: missing lifetime specifier - --> $DIR/rfc1623.rs:8:42 +error[E0308]: mismatched types + --> $DIR/rfc1623.rs:22:35 | -LL | static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = - | ^ expected named lifetime parameter +LL | static SOME_STRUCT: &SomeStruct = SomeStruct { + | ___________________________________^ +LL | | foo: &Foo { bools: &[false, true] }, +LL | | bar: &Bar { bools: &[true, true] }, +LL | | f: &id, +LL | | +LL | | +LL | | }; + | |_^ expected `&SomeStruct<'static, 'static, 'static>`, found struct `SomeStruct` | -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 - --> $DIR/rfc1623.rs:8:29 +help: consider borrowing here | -LL | static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = - | ^^^ ^^^ +LL | static SOME_STRUCT: &SomeStruct = &SomeStruct { +LL | foo: &Foo { bools: &[false, true] }, +LL | bar: &Bar { bools: &[true, true] }, +LL | f: &id, +LL | +LL | + ... -error[E0106]: missing lifetime specifier - --> $DIR/rfc1623.rs:10:39 +error[E0631]: type mismatch in function arguments + --> $DIR/rfc1623.rs:25:8 | -LL | &(non_elidable as fn(&u8, &u8) -> &u8); - | ^ expected named lifetime parameter +LL | fn id(t: T) -> T { + | ------------------- found signature of `fn(_) -> _` +... +LL | f: &id, + | ^^^ expected signature of `for<'a, 'b> fn(&'a Foo<'b>) -> _` | -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 - --> $DIR/rfc1623.rs:10:26 + = note: required for the cast to the object type `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` + +error[E0271]: type mismatch resolving `for<'a, 'b> _ {id::<_>} as std::ops::FnOnce<(&'a Foo<'b>,)>>::Output == &'a Foo<'b>` + --> $DIR/rfc1623.rs:25:8 + | +LL | f: &id, + | ^^^ expected bound lifetime parameter 'a, found concrete lifetime | -LL | &(non_elidable as fn(&u8, &u8) -> &u8); - | ^^^ ^^^ + = note: required for the cast to the object type `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0106`. +Some errors have detailed explanations: E0271, E0308, E0631. +For more information about an error, try `rustc --explain E0271`. diff --git a/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr b/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr index 858f23f1362cc..66913a3c544b3 100644 --- a/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr +++ b/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr @@ -9,7 +9,7 @@ help: consider introducing lifetime `'a` here | LL | struct S1<'a, F: Fn(&i32, &i32) -> &'a i32>(F); | ^^^ -help: consider introducing a higher-ranked lifetime `'a` here +help: consider making the bound lifetime-generic with a new `'a` lifetime | LL | struct S1 Fn(&i32, &i32) -> &'a i32>(F); | ^^^^^^^ @@ -18,15 +18,11 @@ error[E0106]: missing lifetime specifier --> $DIR/fn-missing-lifetime-in-item.rs:2:32 | LL | struct S2 &i32>(F); - | ^ expected named 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 - --> $DIR/fn-missing-lifetime-in-item.rs:2:17 - | -LL | struct S2 &i32>(F); - | ^^^^ ^^^^ + = 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 = note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html -help: consider introducing a higher-ranked lifetime +help: consider making the bound lifetime-generic with a new `'a` lifetime | LL | struct S2 Fn(&'a i32, &'a i32) -> &'a i32>(F); | ^^^^^^^ ^^^^^^^ ^^^^^^^ ^^^ diff --git a/src/test/ui/suggestions/return-without-lifetime.stderr b/src/test/ui/suggestions/return-without-lifetime.stderr index 3b7936c5f44b6..ce3b1748da435 100644 --- a/src/test/ui/suggestions/return-without-lifetime.stderr +++ b/src/test/ui/suggestions/return-without-lifetime.stderr @@ -8,25 +8,17 @@ error[E0106]: missing lifetime specifier --> $DIR/return-without-lifetime.rs:5:34 | LL | fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() } - | ^ help: consider using the named lifetime: `&'a` + | --------- ^ help: consider using the named lifetime: `&'a` | -help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from - --> $DIR/return-without-lifetime.rs:5:20 - | -LL | fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() } - | ^^^^^^^^^ + = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from error[E0106]: missing lifetime specifier --> $DIR/return-without-lifetime.rs:7:35 | LL | fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() } - | ^ help: consider using the named lifetime: `&'a` + | ---------- ^ help: consider using the named lifetime: `&'a` | -help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from - --> $DIR/return-without-lifetime.rs:7:20 - | -LL | fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() } - | ^^^^^^^^^^ + = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from error: aborting due to 3 previous errors 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 2431e8ece3807..1719a99d421d0 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,13 +2,9 @@ error[E0106]: missing lifetime specifier --> $DIR/unboxed-closure-sugar-lifetime-elision.rs:26:39 | LL | let _: dyn Foo(&isize, &usize) -> &usize; - | ^ expected named 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 - --> $DIR/unboxed-closure-sugar-lifetime-elision.rs:26:20 - | -LL | let _: dyn Foo(&isize, &usize) -> &usize; - | ^^^^^^ ^^^^^^ + = 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 parameter | LL | fn main<'a>() { 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 0e410e25ecf25..8d2c82e59edc1 100644 --- a/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr +++ b/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr @@ -2,13 +2,9 @@ error[E0106]: missing lifetime specifier --> $DIR/in-fn-return-illegal.rs:5:30 | LL | fn foo(x: &u32, y: &u32) -> &'_ u32 { loop { } } - | ^^ expected named 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` - --> $DIR/in-fn-return-illegal.rs:5:11 - | -LL | fn foo(x: &u32, y: &u32) -> &'_ u32 { loop { } } - | ^^^^ ^^^^ + = 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 parameter | LL | fn foo<'a>(x: &'a u32, y: &'a u32) -> &'a u32 { loop { } } diff --git a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr index d0eda1b615381..c7cda38e47691 100644 --- a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr +++ b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr @@ -28,13 +28,9 @@ error[E0106]: missing lifetime specifier --> $DIR/underscore-lifetime-binders.rs:16:35 | LL | fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y } - | ^^ expected named 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` - --> $DIR/underscore-lifetime-binders.rs:16:12 - | -LL | fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y } - | ^^^^^^ ^^^^^^ + = 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 parameter | LL | fn foo2<'a>(_: &'a u8, y: &'a u8) -> &'a u8 { y } From 30d927874a06d552c56c298fecb90d2af7444ae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 27 Jan 2020 16:25:43 -0800 Subject: [PATCH 08/12] review comments: wording --- src/librustc_resolve/diagnostics.rs | 2 +- src/librustc_resolve/lifetimes.rs | 2 +- src/test/ui/generic/generic-extern-lifetime.stderr | 4 ++-- .../in-band-lifetimes/no_introducing_in_band_in_locals.stderr | 2 +- src/test/ui/issues/issue-19707.stderr | 4 ++-- src/test/ui/regions/regions-name-undeclared.stderr | 4 ++-- src/test/ui/rfc1623-2.stderr | 4 ++-- src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr | 4 ++-- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 8213a99a92d1e..c254207cc3e7c 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -1514,7 +1514,7 @@ crate fn add_missing_lifetime_specifiers_label( ); should_break = false; err.note( - "for more information on higher-ranked lifetimes, visit \ + "for more information on higher-ranked polymorphism, visit \ https://doc.rust-lang.org/nomicon/hrtb.html", ); let suggestion = match span_type { diff --git a/src/librustc_resolve/lifetimes.rs b/src/librustc_resolve/lifetimes.rs index 9bb852b2093aa..b69eea6634b5a 100644 --- a/src/librustc_resolve/lifetimes.rs +++ b/src/librustc_resolve/lifetimes.rs @@ -1913,7 +1913,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { Applicability::MaybeIncorrect, ); err.note( - "for more information on higher-ranked lifetimes, visit \ + "for more information on higher-ranked polymorphism, visit \ https://doc.rust-lang.org/nomicon/hrtb.html", ); } diff --git a/src/test/ui/generic/generic-extern-lifetime.stderr b/src/test/ui/generic/generic-extern-lifetime.stderr index 5e25952390b2d..72951aea4aaf0 100644 --- a/src/test/ui/generic/generic-extern-lifetime.stderr +++ b/src/test/ui/generic/generic-extern-lifetime.stderr @@ -10,7 +10,7 @@ error[E0261]: use of undeclared lifetime name `'a` LL | pub fn life4<'b>(x: for<'c> fn(&'a i32)); | ^^ undeclared lifetime | - = note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider making the type lifetime-generic with a new `'a` lifetime | LL | pub fn life4<'b>(x: for<'c, 'a> fn(&'a i32)); @@ -22,7 +22,7 @@ error[E0261]: use of undeclared lifetime name `'a` LL | pub fn life7<'b>() -> for<'c> fn(&'a i32); | ^^ undeclared lifetime | - = note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider making the type lifetime-generic with a new `'a` lifetime | LL | pub fn life7<'b>() -> for<'c, 'a> fn(&'a i32); 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 5abaf3c3aefff..a43b49041ec2a 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 @@ -12,7 +12,7 @@ error[E0261]: use of undeclared lifetime name `'test` LL | let y: fn(&'test u32) = foo2; | ^^^^^ undeclared lifetime | - = note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider introducing lifetime `'test` here | LL | fn bar<'test>() { diff --git a/src/test/ui/issues/issue-19707.stderr b/src/test/ui/issues/issue-19707.stderr index 398e97a6f207a..337f2f971ede0 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 - = note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider making the type lifetime-generic with a new `'a` lifetime | LL | type Foo = for<'a> fn(&'a u8, &'a u8) -> &'a u8; @@ -22,7 +22,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 - = note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider making the bound lifetime-generic with a new `'a` lifetime | LL | fn bar Fn(&'a u8, &'a u8) -> &'a u8>(f: &F) {} diff --git a/src/test/ui/regions/regions-name-undeclared.stderr b/src/test/ui/regions/regions-name-undeclared.stderr index e139e3f425189..eb19a30c52b97 100644 --- a/src/test/ui/regions/regions-name-undeclared.stderr +++ b/src/test/ui/regions/regions-name-undeclared.stderr @@ -89,7 +89,7 @@ error[E0261]: use of undeclared lifetime name `'b` LL | ... &'b isize, | ^^ undeclared lifetime | - = note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider introducing lifetime `'b` here | LL | fn fn_types<'b>(a: &'a isize, @@ -105,7 +105,7 @@ error[E0261]: use of undeclared lifetime name `'b` LL | ... &'b isize)>, | ^^ undeclared lifetime | - = note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider introducing lifetime `'b` here | LL | fn fn_types<'b>(a: &'a isize, diff --git a/src/test/ui/rfc1623-2.stderr b/src/test/ui/rfc1623-2.stderr index c927ad9e0ba4b..732bb61e6eebb 100644 --- a/src/test/ui/rfc1623-2.stderr +++ b/src/test/ui/rfc1623-2.stderr @@ -5,7 +5,7 @@ LL | static NON_ELIDABLE_FN: &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 - = note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider making the type lifetime-generic with a new `'a` lifetime | LL | static NON_ELIDABLE_FN: &for<'a> fn(&'a u8, &'a u8) -> &'a u8 = @@ -18,7 +18,7 @@ LL | &(non_elidable as 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 - = note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider making the type lifetime-generic with a new `'a` lifetime | LL | &(non_elidable as for<'a> fn(&'a u8, &'a u8) -> &'a u8); diff --git a/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr b/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr index 66913a3c544b3..fe9c3445fc46f 100644 --- a/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr +++ b/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr @@ -4,7 +4,7 @@ error[E0261]: use of undeclared lifetime name `'a` LL | struct S1 &'a i32>(F); | ^^ undeclared lifetime | - = note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider introducing lifetime `'a` here | LL | struct S1<'a, F: Fn(&i32, &i32) -> &'a i32>(F); @@ -21,7 +21,7 @@ LL | struct S2 &i32>(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 - = note: for more information on higher-ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider making the bound lifetime-generic with a new `'a` lifetime | LL | struct S2 Fn(&'a i32, &'a i32) -> &'a i32>(F); From 49f9bf897b93349464c2046047991b3e77ca0f2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 27 Jan 2020 17:33:13 -0800 Subject: [PATCH 09/12] review comments --- src/librustc_resolve/diagnostics.rs | 21 +++------------ src/librustc_resolve/lifetimes.rs | 42 +++++++++++++++-------------- 2 files changed, 26 insertions(+), 37 deletions(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index c254207cc3e7c..be7a9de4317c5 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -19,7 +19,7 @@ use syntax::ast::{self, Ident, Path}; use syntax::util::lev_distance::find_best_match_for_name; use crate::imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver}; -use crate::lifetimes::{ElisionFailureInfo, ForLifetimeSpanType, MissingLifetimeSpot}; +use crate::lifetimes::{ElisionFailureInfo, MissingLifetimeSpot}; use crate::path_names_to_string; use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind}; use crate::{BindingError, CrateLint, HasGenericParams, LegacyScope, Module, ModuleOrUniformRoot}; @@ -1502,30 +1502,17 @@ crate fn add_missing_lifetime_specifiers_label( [param, ..] => (param.span.shrink_to_lo(), "'a, ".to_string()), } } - MissingLifetimeSpot::HRLT { span, span_type } => { + MissingLifetimeSpot::HigherRanked { span, span_type } => { msg = format!( "consider making the {} lifetime-generic with a new `'a` lifetime", - match span_type { - ForLifetimeSpanType::BoundEmpty - | ForLifetimeSpanType::BoundTail => "bound", - ForLifetimeSpanType::TypeEmpty | ForLifetimeSpanType::TypeTail => - "type", - } + span_type.descr(), ); should_break = false; err.note( "for more information on higher-ranked polymorphism, visit \ https://doc.rust-lang.org/nomicon/hrtb.html", ); - let suggestion = match span_type { - ForLifetimeSpanType::BoundEmpty | ForLifetimeSpanType::TypeEmpty => { - "for<'a> " - } - ForLifetimeSpanType::BoundTail | ForLifetimeSpanType::TypeTail => { - ", 'a" - } - }; - (*span, suggestion.to_string()) + (*span, span_type.suggestion("'a")) } }); for param in params { diff --git a/src/librustc_resolve/lifetimes.rs b/src/librustc_resolve/lifetimes.rs index b69eea6634b5a..811b36022a5b9 100644 --- a/src/librustc_resolve/lifetimes.rs +++ b/src/librustc_resolve/lifetimes.rs @@ -155,7 +155,7 @@ struct NamedRegionMap { crate enum MissingLifetimeSpot<'tcx> { Generics(&'tcx hir::Generics<'tcx>), - HRLT { span: Span, span_type: ForLifetimeSpanType }, + HigherRanked { span: Span, span_type: ForLifetimeSpanType }, } crate enum ForLifetimeSpanType { @@ -165,6 +165,22 @@ crate enum ForLifetimeSpanType { TypeTail, } +impl ForLifetimeSpanType { + crate fn descr(&self) -> &'static str { + match self { + Self::BoundEmpty | Self::BoundTail => "bound", + Self::TypeEmpty | Self::TypeTail => "type", + } + } + + crate fn suggestion(&self, sugg: &str) -> String { + match self { + Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg), + Self::BoundTail | Self::TypeTail => format!(", {}", sugg), + } + } +} + impl<'tcx> Into> for &'tcx hir::Generics<'tcx> { fn into(self) -> MissingLifetimeSpot<'tcx> { MissingLifetimeSpot::Generics(self) @@ -525,7 +541,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { (ty.span.shrink_to_lo(), ForLifetimeSpanType::TypeEmpty) }; self.missing_named_lifetime_spots - .push(MissingLifetimeSpot::HRLT { span, span_type }); + .push(MissingLifetimeSpot::HigherRanked { span, span_type }); let scope = Scope::Binder { lifetimes: c .generic_params @@ -1887,29 +1903,15 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { Applicability::MaybeIncorrect, ); } - MissingLifetimeSpot::HRLT { span, span_type } => { + MissingLifetimeSpot::HigherRanked { span, span_type } => { err.span_suggestion( *span, &format!( "consider making the {} lifetime-generic with a new `{}` lifetime", - match span_type { - ForLifetimeSpanType::BoundEmpty - | ForLifetimeSpanType::BoundTail => "bound", - ForLifetimeSpanType::TypeEmpty - | ForLifetimeSpanType::TypeTail => "type", - }, + span_type.descr(), lifetime_ref ), - match span_type { - ForLifetimeSpanType::TypeEmpty - | ForLifetimeSpanType::BoundEmpty => { - format!("for<{}> ", lifetime_ref) - } - ForLifetimeSpanType::TypeTail | ForLifetimeSpanType::BoundTail => { - format!(", {}", lifetime_ref) - } - } - .to_string(), + span_type.suggestion(&lifetime_ref.to_string()), Applicability::MaybeIncorrect, ); err.note( @@ -2840,7 +2842,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { [.., bound] => (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail), }; self.missing_named_lifetime_spots - .push(MissingLifetimeSpot::HRLT { span, span_type }); + .push(MissingLifetimeSpot::HigherRanked { span, span_type }); return true; } }; From 1beac2b774fa7081ad22f9856ebb6bb9d04297fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 28 Jan 2020 15:04:18 -0800 Subject: [PATCH 10/12] Move code to `diagnostics.rs` --- src/librustc_resolve/diagnostics.rs | 298 +++++++++++++++++++--------- src/librustc_resolve/lifetimes.rs | 116 +---------- 2 files changed, 214 insertions(+), 200 deletions(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index be7a9de4317c5..2732197f36125 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -8,6 +8,7 @@ use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; 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}; @@ -19,7 +20,7 @@ use syntax::ast::{self, Ident, Path}; use syntax::util::lev_distance::find_best_match_for_name; use crate::imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver}; -use crate::lifetimes::{ElisionFailureInfo, MissingLifetimeSpot}; +use crate::lifetimes::{ElisionFailureInfo, LifetimeContext}; use crate::path_names_to_string; use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind}; use crate::{BindingError, CrateLint, HasGenericParams, LegacyScope, Module, ModuleOrUniformRoot}; @@ -48,6 +49,40 @@ crate struct ImportSuggestion { pub path: Path, } +crate enum MissingLifetimeSpot<'tcx> { + Generics(&'tcx hir::Generics<'tcx>), + HigherRanked { span: Span, span_type: ForLifetimeSpanType }, +} + +crate enum ForLifetimeSpanType { + BoundEmpty, + BoundTail, + TypeEmpty, + TypeTail, +} + +impl ForLifetimeSpanType { + crate fn descr(&self) -> &'static str { + match self { + Self::BoundEmpty | Self::BoundTail => "bound", + Self::TypeEmpty | Self::TypeTail => "type", + } + } + + crate fn suggestion(&self, sugg: &str) -> String { + match self { + Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg), + Self::BoundTail | Self::TypeTail => format!(", {}", sugg), + } + } +} + +impl<'tcx> Into> for &'tcx hir::Generics<'tcx> { + fn into(self) -> MissingLifetimeSpot<'tcx> { + MissingLifetimeSpot::Generics(self) + } +} + /// Adjust the impl span so that just the `impl` keyword is taken by removing /// everything after `<` (`"impl Iterator for A {}" -> "impl"`) and /// everything after the first whitespace (`"impl Iterator for A" -> "impl"`). @@ -1457,104 +1492,185 @@ 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)) -} +impl<'tcx> LifetimeContext<'_, 'tcx> { + crate fn report_missing_lifetime_specifiers( + &self, + span: Span, + count: usize, + ) -> DiagnosticBuilder<'tcx> { + struct_span_err!( + self.tcx.sess, + span, + E0106, + "missing lifetime specifier{}", + pluralize!(count) + ) + } -crate fn add_missing_lifetime_specifiers_label( - err: &mut DiagnosticBuilder<'_>, - source_map: &SourceMap, - span: Span, - count: usize, - lifetime_names: &FxHashSet, - snippet: Option<&str>, - missing_named_lifetime_spots: &[MissingLifetimeSpot<'_>], - params: &[ElisionFailureInfo], -) { - 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, - ); + crate fn emit_undeclared_lifetime_error(&self, lifetime_ref: &hir::Lifetime) { + let mut err = struct_span_err!( + self.tcx.sess, + lifetime_ref.span, + E0261, + "use of undeclared lifetime name `{}`", + lifetime_ref + ); + err.span_label(lifetime_ref.span, "undeclared lifetime"); + for missing in &self.missing_named_lifetime_spots { + match missing { + MissingLifetimeSpot::Generics(generics) => { + 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, + ); + } + MissingLifetimeSpot::HigherRanked { span, span_type } => { + err.span_suggestion( + *span, + &format!( + "consider making the {} lifetime-generic with a new `{}` lifetime", + span_type.descr(), + lifetime_ref + ), + span_type.suggestion(&lifetime_ref.to_string()), + Applicability::MaybeIncorrect, + ); + err.note( + "for more information on higher-ranked polymorphism, visit \ + https://doc.rust-lang.org/nomicon/hrtb.html", + ); + } + } + } + err.emit(); + } + + crate fn is_trait_ref_fn_scope(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) -> bool { + if let def::Res::Def(_, did) = trait_ref.trait_ref.path.res { + if [ + self.tcx.lang_items().fn_once_trait(), + self.tcx.lang_items().fn_trait(), + self.tcx.lang_items().fn_mut_trait(), + ] + .contains(&Some(did)) + { + let (span, span_type) = match &trait_ref.bound_generic_params { + [] => (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty), + [.., bound] => (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail), + }; + self.missing_named_lifetime_spots + .push(MissingLifetimeSpot::HigherRanked { span, span_type }); + return true; + } }; - let suggest_new = |err: &mut DiagnosticBuilder<'_>, sugg: &str| { - err.span_label(span, "expected named lifetime parameter"); - - for missing in missing_named_lifetime_spots.iter().rev() { - let mut introduce_suggestion = vec![]; - let msg; - let should_break; - introduce_suggestion.push(match missing { - MissingLifetimeSpot::Generics(generics) => { - msg = "consider introducing a named lifetime parameter".to_string(); - should_break = true; - match &generics.params { - [] => (generics.span, "<'a>".to_string()), - [param, ..] => (param.span.shrink_to_lo(), "'a, ".to_string()), + false + } + + crate fn add_missing_lifetime_specifiers_label( + &self, + err: &mut DiagnosticBuilder<'_>, + span: Span, + count: usize, + lifetime_names: &FxHashSet, + params: &[ElisionFailureInfo], + ) { + if count > 1 { + err.span_label(span, format!("expected {} lifetime parameters", count)); + } else { + let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok(); + 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: &str| { + err.span_label(span, "expected named lifetime parameter"); + + for missing in self.missing_named_lifetime_spots.iter().rev() { + let mut introduce_suggestion = vec![]; + let msg; + let should_break; + introduce_suggestion.push(match missing { + MissingLifetimeSpot::Generics(generics) => { + msg = "consider introducing a named lifetime parameter".to_string(); + should_break = true; + match &generics.params { + [] => (generics.span, "<'a>".to_string()), + [param, ..] => (param.span.shrink_to_lo(), "'a, ".to_string()), + } } - } - MissingLifetimeSpot::HigherRanked { span, span_type } => { - msg = format!( - "consider making the {} lifetime-generic with a new `'a` lifetime", - span_type.descr(), - ); - should_break = false; - err.note( - "for more information on higher-ranked polymorphism, visit \ + MissingLifetimeSpot::HigherRanked { span, span_type } => { + msg = format!( + "consider making the {} lifetime-generic with a new `'a` lifetime", + span_type.descr(), + ); + should_break = false; + err.note( + "for more information on higher-ranked polymorphism, visit \ https://doc.rust-lang.org/nomicon/hrtb.html", - ); - (*span, span_type.suggestion("'a")) - } - }); - for param in params { - if let Ok(snippet) = source_map.span_to_snippet(param.span) { - if snippet.starts_with("&") && !snippet.starts_with("&'") { - introduce_suggestion - .push((param.span, format!("&'a {}", &snippet[1..]))); - } else if snippet.starts_with("&'_ ") { - introduce_suggestion - .push((param.span, format!("&'a {}", &snippet[4..]))); + ); + (*span, span_type.suggestion("'a")) + } + }); + for param in params { + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span) + { + if snippet.starts_with("&") && !snippet.starts_with("&'") { + introduce_suggestion + .push((param.span, format!("&'a {}", &snippet[1..]))); + } else if snippet.starts_with("&'_ ") { + introduce_suggestion + .push((param.span, format!("&'a {}", &snippet[4..]))); + } } } + introduce_suggestion.push((span, sugg.to_string())); + err.multipart_suggestion( + &msg, + introduce_suggestion, + Applicability::MaybeIncorrect, + ); + if should_break { + break; + } } - introduce_suggestion.push((span, sugg.to_string())); - err.multipart_suggestion(&msg, introduce_suggestion, Applicability::MaybeIncorrect); - if should_break { - break; - } - } - }; + }; - 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, "&'a "); - } - (0, _, Some("'_")) => { - suggest_new(err, "'a"); - } - (0, _, Some(snippet)) if !snippet.ends_with(">") => { - suggest_new(err, &format!("{}<'a>", snippet)); - } - _ => { - err.span_label(span, "expected lifetime parameter"); + match ( + lifetime_names.len(), + lifetime_names.iter().next(), + snippet.as_ref().map(|s| s.as_str()), + ) { + (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, "&'a "); + } + (0, _, Some("'_")) => { + suggest_new(err, "'a"); + } + (0, _, Some(snippet)) if !snippet.ends_with(">") => { + suggest_new(err, &format!("{}<'a>", snippet)); + } + _ => { + err.span_label(span, "expected lifetime parameter"); + } } } } diff --git a/src/librustc_resolve/lifetimes.rs b/src/librustc_resolve/lifetimes.rs index 811b36022a5b9..0ba9b4f17068e 100644 --- a/src/librustc_resolve/lifetimes.rs +++ b/src/librustc_resolve/lifetimes.rs @@ -5,9 +5,7 @@ //! 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 crate::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot}; use rustc::hir::map::Map; use rustc::lint; use rustc::middle::resolve_lifetime::*; @@ -153,42 +151,8 @@ struct NamedRegionMap { object_lifetime_defaults: HirIdMap>, } -crate enum MissingLifetimeSpot<'tcx> { - Generics(&'tcx hir::Generics<'tcx>), - HigherRanked { span: Span, span_type: ForLifetimeSpanType }, -} - -crate enum ForLifetimeSpanType { - BoundEmpty, - BoundTail, - TypeEmpty, - TypeTail, -} - -impl ForLifetimeSpanType { - crate fn descr(&self) -> &'static str { - match self { - Self::BoundEmpty | Self::BoundTail => "bound", - Self::TypeEmpty | Self::TypeTail => "type", - } - } - - crate fn suggestion(&self, sugg: &str) -> String { - match self { - Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg), - Self::BoundTail | Self::TypeTail => format!(", {}", sugg), - } - } -} - -impl<'tcx> Into> for &'tcx hir::Generics<'tcx> { - fn into(self) -> MissingLifetimeSpot<'tcx> { - MissingLifetimeSpot::Generics(self) - } -} - -struct LifetimeContext<'a, 'tcx> { - tcx: TyCtxt<'tcx>, +crate struct LifetimeContext<'a, 'tcx> { + crate tcx: TyCtxt<'tcx>, map: &'a mut NamedRegionMap, scope: ScopeRef<'a>, @@ -220,7 +184,7 @@ struct LifetimeContext<'a, 'tcx> { /// When encountering an undefined named lifetime, we will suggest introducing it in these /// places. - missing_named_lifetime_spots: Vec>, + crate missing_named_lifetime_spots: Vec>, } #[derive(Debug)] @@ -1879,49 +1843,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.insert_lifetime(lifetime_ref, def); } else { - let mut err = struct_span_err!( - self.tcx.sess, - lifetime_ref.span, - E0261, - "use of undeclared lifetime name `{}`", - lifetime_ref - ); - err.span_label(lifetime_ref.span, "undeclared lifetime"); - for missing in &self.missing_named_lifetime_spots { - match missing { - MissingLifetimeSpot::Generics(generics) => { - 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, - ); - } - MissingLifetimeSpot::HigherRanked { span, span_type } => { - err.span_suggestion( - *span, - &format!( - "consider making the {} lifetime-generic with a new `{}` lifetime", - span_type.descr(), - lifetime_ref - ), - span_type.suggestion(&lifetime_ref.to_string()), - Applicability::MaybeIncorrect, - ); - err.note( - "for more information on higher-ranked polymorphism, visit \ - https://doc.rust-lang.org/nomicon/hrtb.html", - ); - } - } - } - err.emit(); + self.emit_undeclared_lifetime_error(lifetime_ref); } } @@ -2461,7 +2383,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } }; - let mut err = report_missing_lifetime_specifiers(self.tcx.sess, span, lifetime_refs.len()); + let mut err = self.report_missing_lifetime_specifiers(span, lifetime_refs.len()); let mut add_label = true; if let Some(params) = error { @@ -2470,14 +2392,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } if add_label { - add_missing_lifetime_specifiers_label( + self.add_missing_lifetime_specifiers_label( &mut err, - self.tcx.sess.source_map(), span, 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, error.map(|p| &p[..]).unwrap_or(&[]), ); } @@ -2827,27 +2746,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let old_value = self.map.defs.remove(&lifetime_ref.hir_id); assert_eq!(old_value, Some(bad_def)); } - - fn is_trait_ref_fn_scope(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) -> bool { - if let Res::Def(_, did) = trait_ref.trait_ref.path.res { - if [ - self.tcx.lang_items().fn_once_trait(), - self.tcx.lang_items().fn_trait(), - self.tcx.lang_items().fn_mut_trait(), - ] - .contains(&Some(did)) - { - let (span, span_type) = match &trait_ref.bound_generic_params { - [] => (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty), - [.., bound] => (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail), - }; - self.missing_named_lifetime_spots - .push(MissingLifetimeSpot::HigherRanked { span, span_type }); - return true; - } - }; - false - } } /// Detects late-bound lifetimes and inserts them into From 96bbb0d67eee9cbe8565afd8b56d537c5937dd62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 30 Jan 2020 11:53:47 -0800 Subject: [PATCH 11/12] Account for `impl Trait` Address #49287 --- src/librustc_resolve/diagnostics.rs | 89 ++++++++++++------- .../impl-trait-missing-lifetime.rs | 2 + .../impl-trait-missing-lifetime.stderr | 14 +++ 3 files changed, 71 insertions(+), 34 deletions(-) create mode 100644 src/test/ui/suggestions/impl-trait-missing-lifetime.rs create mode 100644 src/test/ui/suggestions/impl-trait-missing-lifetime.stderr diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 2732197f36125..075dca8f01d7b 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -1519,9 +1519,21 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { for missing in &self.missing_named_lifetime_spots { match missing { MissingLifetimeSpot::Generics(generics) => { - let (span, sugg) = match &generics.params { - [] => (generics.span, format!("<{}>", lifetime_ref)), - [param, ..] => (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref)), + let (span, sugg) = if let Some(param) = generics + .params + .iter() + .filter(|p| match p.kind { + hir::GenericParamKind::Type { + synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), + .. + } => false, + _ => true, + }) + .next() + { + (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref)) + } else { + (generics.span, format!("<{}>", lifetime_ref)) }; err.span_suggestion( span, @@ -1592,20 +1604,28 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { Applicability::MaybeIncorrect, ); }; - let suggest_new = |err: &mut DiagnosticBuilder<'_>, sugg: &str| { - err.span_label(span, "expected named lifetime parameter"); - - for missing in self.missing_named_lifetime_spots.iter().rev() { - let mut introduce_suggestion = vec![]; - let msg; - let should_break; - introduce_suggestion.push(match missing { + let suggest_new = + |err: &mut DiagnosticBuilder<'_>, sugg: &str| { + err.span_label(span, "expected named lifetime parameter"); + + for missing in self.missing_named_lifetime_spots.iter().rev() { + let mut introduce_suggestion = vec![]; + let msg; + let should_break; + introduce_suggestion.push(match missing { MissingLifetimeSpot::Generics(generics) => { msg = "consider introducing a named lifetime parameter".to_string(); should_break = true; - match &generics.params { - [] => (generics.span, "<'a>".to_string()), - [param, ..] => (param.span.shrink_to_lo(), "'a, ".to_string()), + if let Some(param) = generics.params.iter().filter(|p| match p.kind { + hir::GenericParamKind::Type { + synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), + .. + } => false, + _ => true, + }).next() { + (param.span.shrink_to_lo(), "'a, ".to_string()) + } else { + (generics.span, "<'a>".to_string()) } } MissingLifetimeSpot::HigherRanked { span, span_type } => { @@ -1621,29 +1641,30 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { (*span, span_type.suggestion("'a")) } }); - for param in params { - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span) - { - if snippet.starts_with("&") && !snippet.starts_with("&'") { - introduce_suggestion - .push((param.span, format!("&'a {}", &snippet[1..]))); - } else if snippet.starts_with("&'_ ") { - introduce_suggestion - .push((param.span, format!("&'a {}", &snippet[4..]))); + for param in params { + if let Ok(snippet) = + self.tcx.sess.source_map().span_to_snippet(param.span) + { + if snippet.starts_with("&") && !snippet.starts_with("&'") { + introduce_suggestion + .push((param.span, format!("&'a {}", &snippet[1..]))); + } else if snippet.starts_with("&'_ ") { + introduce_suggestion + .push((param.span, format!("&'a {}", &snippet[4..]))); + } } } + introduce_suggestion.push((span, sugg.to_string())); + err.multipart_suggestion( + &msg, + introduce_suggestion, + Applicability::MaybeIncorrect, + ); + if should_break { + break; + } } - introduce_suggestion.push((span, sugg.to_string())); - err.multipart_suggestion( - &msg, - introduce_suggestion, - Applicability::MaybeIncorrect, - ); - if should_break { - break; - } - } - }; + }; match ( lifetime_names.len(), diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime.rs b/src/test/ui/suggestions/impl-trait-missing-lifetime.rs new file mode 100644 index 0000000000000..22dc448c97ff0 --- /dev/null +++ b/src/test/ui/suggestions/impl-trait-missing-lifetime.rs @@ -0,0 +1,2 @@ +fn f(_: impl Iterator) {} //~ ERROR missing lifetime specifier +fn main() {} diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr b/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr new file mode 100644 index 0000000000000..e31f25ab60304 --- /dev/null +++ b/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr @@ -0,0 +1,14 @@ +error[E0106]: missing lifetime specifier + --> $DIR/impl-trait-missing-lifetime.rs:1:31 + | +LL | fn f(_: impl Iterator) {} + | ^^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | fn f<'a>(_: impl Iterator) {} + | ^^^^ ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0106`. From 609a37407f6fbaeae66500c840cedc81a50960be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 5 Feb 2020 10:59:14 -0800 Subject: [PATCH 12/12] Fix test --- src/test/ui/async-await/issues/issue-63388-2.nll.stderr | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/ui/async-await/issues/issue-63388-2.nll.stderr b/src/test/ui/async-await/issues/issue-63388-2.nll.stderr index 7781af89deae2..6edb9e63d480a 100644 --- a/src/test/ui/async-await/issues/issue-63388-2.nll.stderr +++ b/src/test/ui/async-await/issues/issue-63388-2.nll.stderr @@ -1,6 +1,8 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-63388-2.rs:12:10 | +LL | foo: &dyn Foo, bar: &'a dyn Foo + | -------- ----------- LL | ) -> &dyn Foo | ^ help: consider using the named lifetime: `&'a` |