about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2020-01-27 16:13:45 -0800
committerEsteban Küber <esteban@kuber.com.ar>2020-02-05 10:32:01 -0800
commit92505df338a860f1055241a07949de2af7ddc6b0 (patch)
tree93bfee2c894e11c8b035fd1a1b2fe44ff0b6e5a3
parentba3b44c508b133829f7b6a57f3e62c0735a7d110 (diff)
downloadrust-92505df338a860f1055241a07949de2af7ddc6b0.tar.gz
rust-92505df338a860f1055241a07949de2af7ddc6b0.zip
Account for `fn()` types in lifetime suggestions
-rw-r--r--src/librustc_resolve/diagnostics.rs24
-rw-r--r--src/librustc_resolve/lifetimes.rs64
-rw-r--r--src/test/ui/async-await/issues/issue-63388-2.stderr8
-rw-r--r--src/test/ui/generic/generic-extern-lifetime.stderr12
-rw-r--r--src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr12
-rw-r--r--src/test/ui/issues/issue-19707.stderr21
-rw-r--r--src/test/ui/issues/issue-26638.stderr8
-rw-r--r--src/test/ui/issues/issue-30255.stderr24
-rw-r--r--src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr16
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr8
-rw-r--r--src/test/ui/regions/regions-name-undeclared.stderr4
-rw-r--r--src/test/ui/rfc1623-2.rs13
-rw-r--r--src/test/ui/rfc1623-2.stderr29
-rw-r--r--src/test/ui/rfc1623.rs13
-rw-r--r--src/test/ui/rfc1623.stderr55
-rw-r--r--src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr12
-rw-r--r--src/test/ui/suggestions/return-without-lifetime.stderr16
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr8
-rw-r--r--src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr8
-rw-r--r--src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr8
20 files changed, 210 insertions, 153 deletions
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index 3b689f03b43..8213a99a92d 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 69deffe4a4c..9bb852b2093 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<MissingLifetimeSpot<'tcx>> 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<Span> = 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 a12c601b936..9f51ced9c3f 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 39372c93158..5e25952390b 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 7d71230e162..5abaf3c3aef 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 e84bfb969d4..398e97a6f20 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<F: Fn(&u8, &u8) -> &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<F: Fn(&u8, &u8) -> &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<F: for<'a> 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 75cd5332fd9..1d8fbdc63c5 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<dyn Iterator<Item=&str>+'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<dyn Iterator<Item=&str>+'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<dyn Iterator<Item=&str>+'static>) -> &'a str { iter.next() }
diff --git a/src/test/ui/issues/issue-30255.stderr b/src/test/ui/issues/issue-30255.stderr
index 3c26365d5d1..ab43d4a3c60 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 b81ce552b39..461c1832e9a 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 47b048a7a97..c1fcab2409f 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 498667abe36..e139e3f4251 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<dyn for<'a, 'b> 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<dyn for<'a, 'b> FnOnce(&'a isize,
    |                              ^^^^
diff --git a/src/test/ui/rfc1623-2.rs b/src/test/ui/rfc1623-2.rs
new file mode 100644
index 00000000000..35a2ef10c2e
--- /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 00000000000..c927ad9e0ba
--- /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 ebb4d56af9e..55f5d0b94dc 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 {
     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 aabe088d63c..ca956004ef7 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) -> 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> <fn(_) -> _ {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 858f23f1362..66913a3c544 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<F: for<'a> 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<F: Fn(&i32, &i32) -> &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<F: Fn(&i32, &i32) -> &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<F: for<'a> 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 3b7936c5f44..ce3b1748da4 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 2431e8ece38..1719a99d421 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 0e410e25ecf..8d2c82e59ed 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 d0eda1b6153..c7cda38e476 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 }