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] 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 fafceb1f97ce..56fb66004053 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 022f83af8159..97d314c8f65a 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 1be066caa87a..f8917b7bdd08 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 e2b57a20325d..fbe715de932f 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 d1b597804cda..01236e3c7730 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 52a980a61daa..bea1a8bf2c1f 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 801504627c0a..97014dae2b97 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