about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2020-05-29 21:58:14 +0200
committerGitHub <noreply@github.com>2020-05-29 21:58:14 +0200
commit81207802a0d83a2d43cb57f3a67f1b948d3b108f (patch)
tree87674bf6f87fe66cd0bff9499fe5e89fbe8ec63f
parent96dd4690c3aa70ec312448c3f2d50e6dc6fb87df (diff)
parent1bd69702de07858ad9c7ae7ed89c3c99aea64550 (diff)
downloadrust-81207802a0d83a2d43cb57f3a67f1b948d3b108f.tar.gz
rust-81207802a0d83a2d43cb57f3a67f1b948d3b108f.zip
Rollup merge of #67460 - estebank:named-lts, r=nikomatsakis
Tweak impl signature mismatch errors involving `RegionKind::ReVar` lifetimes

Fix #66406, fix #72106.

```
error: `impl` item signature doesn't match `trait` item signature
  --> $DIR/trait-param-without-lifetime-constraint.rs:14:5
   |
LL |     fn get_relation(&self) -> To;
   |     ----------------------------- expected `fn(&Article) -> &ProofReader`
...
LL |     fn get_relation(&self) -> &ProofReader {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Article) -> &ProofReader`
   |
   = note: expected `fn(&Article) -> &ProofReader`
              found `fn(&Article) -> &ProofReader`
help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
  --> $DIR/trait-param-without-lifetime-constraint.rs:10:31
   |
LL |     fn get_relation(&self) -> To;
   |                               ^^ consider borrowing this type parameter in the trait
```

r? @nikomatsakis
-rw-r--r--src/librustc_errors/diagnostic.rs15
-rw-r--r--src/librustc_infer/infer/error_reporting/mod.rs4
-rw-r--r--src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs107
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr8
-rw-r--r--src/test/ui/error-codes/E0490.stderr4
-rw-r--r--src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr8
-rw-r--r--src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr6
-rw-r--r--src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr6
-rw-r--r--src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr6
-rw-r--r--src/test/ui/issues/issue-16683.stderr4
-rw-r--r--src/test/ui/issues/issue-17758.stderr4
-rw-r--r--src/test/ui/issues/issue-20831-debruijn.stderr8
-rw-r--r--src/test/ui/issues/issue-52213.stderr4
-rw-r--r--src/test/ui/issues/issue-55796.stderr8
-rw-r--r--src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr6
-rw-r--r--src/test/ui/nll/issue-55394.stderr4
-rw-r--r--src/test/ui/nll/normalization-bounds-error.stderr4
-rw-r--r--src/test/ui/nll/type-alias-free-regions.stderr16
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr4
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr4
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-elision.stderr8
-rw-r--r--src/test/ui/regions/region-object-lifetime-in-coercion.stderr8
-rw-r--r--src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr8
-rw-r--r--src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr4
-rw-r--r--src/test/ui/regions/regions-close-object-into-object-2.stderr4
-rw-r--r--src/test/ui/regions/regions-close-object-into-object-4.stderr4
-rw-r--r--src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr4
-rw-r--r--src/test/ui/regions/regions-creating-enums4.stderr8
-rw-r--r--src/test/ui/regions/regions-nested-fns.stderr4
-rw-r--r--src/test/ui/regions/regions-normalize-in-where-clause-list.stderr12
-rw-r--r--src/test/ui/regions/regions-ret-borrowed-1.stderr4
-rw-r--r--src/test/ui/regions/regions-ret-borrowed.stderr4
-rw-r--r--src/test/ui/regions/regions-trait-object-subtyping.stderr4
-rw-r--r--src/test/ui/reject-specialized-drops-8142.stderr4
-rw-r--r--src/test/ui/traits/self-without-lifetime-constraint.rs53
-rw-r--r--src/test/ui/traits/self-without-lifetime-constraint.stderr19
-rw-r--r--src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr4
-rw-r--r--src/test/ui/traits/trait-param-without-lifetime-constraint.rs20
-rw-r--r--src/test/ui/traits/trait-param-without-lifetime-constraint.stderr19
-rw-r--r--src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr4
40 files changed, 324 insertions, 105 deletions
diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs
index 1cc5daafed1..cff83c3d5cd 100644
--- a/src/librustc_errors/diagnostic.rs
+++ b/src/librustc_errors/diagnostic.rs
@@ -193,9 +193,18 @@ impl Diagnostic {
         expected_extra: &dyn fmt::Display,
         found_extra: &dyn fmt::Display,
     ) -> &mut Self {
-        let expected_label = format!("expected {}", expected_label);
-
-        let found_label = format!("found {}", found_label);
+        let expected_label = expected_label.to_string();
+        let expected_label = if expected_label.is_empty() {
+            "expected".to_string()
+        } else {
+            format!("expected {}", expected_label)
+        };
+        let found_label = found_label.to_string();
+        let found_label = if found_label.is_empty() {
+            "found".to_string()
+        } else {
+            format!("found {}", found_label)
+        };
         let (found_padding, expected_padding) = if expected_label.len() > found_label.len() {
             (expected_label.len() - found_label.len(), 0)
         } else {
diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs
index cc479aa17ce..ae901982817 100644
--- a/src/librustc_infer/infer/error_reporting/mod.rs
+++ b/src/librustc_infer/infer/error_reporting/mod.rs
@@ -987,12 +987,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         }
 
         fn push_ty_ref<'tcx>(
-            r: &ty::Region<'tcx>,
+            region: &ty::Region<'tcx>,
             ty: Ty<'tcx>,
             mutbl: hir::Mutability,
             s: &mut DiagnosticStyledString,
         ) {
-            let mut r = r.to_string();
+            let mut r = region.to_string();
             if r == "'_" {
                 r.clear();
             } else {
diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index 695f3e47fb5..5f14f799fc7 100644
--- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -2,11 +2,16 @@
 
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
-use crate::infer::{Subtype, ValuePairs};
+use crate::infer::{Subtype, TyCtxtInferExt, ValuePairs};
 use crate::traits::ObligationCauseCode::CompareImplMethodObligation;
 use rustc_errors::ErrorReported;
-use rustc_middle::ty::Ty;
-use rustc_span::Span;
+use rustc_hir as hir;
+use rustc_hir::def::Res;
+use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::Visitor;
+use rustc_middle::ty::error::ExpectedFound;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::{MultiSpan, Span};
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`.
@@ -36,7 +41,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                                 var_origin.span(),
                                 sub_expected_found.expected,
                                 sub_expected_found.found,
-                                self.tcx().def_span(*trait_item_def_id),
+                                *trait_item_def_id,
                             );
                             return Some(ErrorReported);
                         }
@@ -47,14 +52,100 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         None
     }
 
-    fn emit_err(&self, sp: Span, expected: Ty<'tcx>, found: Ty<'tcx>, impl_sp: Span) {
+    fn emit_err(&self, sp: Span, expected: Ty<'tcx>, found: Ty<'tcx>, trait_def_id: DefId) {
+        let tcx = self.tcx();
+        let trait_sp = self.tcx().def_span(trait_def_id);
         let mut err = self
             .tcx()
             .sess
             .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature");
-        err.note(&format!("expected `{:?}`\n   found `{:?}`", expected, found));
-        err.span_label(sp, &format!("found {:?}", found));
-        err.span_label(impl_sp, &format!("expected {:?}", expected));
+        err.span_label(sp, &format!("found `{:?}`", found));
+        err.span_label(trait_sp, &format!("expected `{:?}`", expected));
+
+        // Get the span of all the used type parameters in the method.
+        let assoc_item = self.tcx().associated_item(trait_def_id);
+        let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
+        match assoc_item.kind {
+            ty::AssocKind::Fn => {
+                let hir = self.tcx().hir();
+                if let Some(hir_id) = assoc_item.def_id.as_local().map(|id| hir.as_local_hir_id(id))
+                {
+                    if let Some(decl) = hir.fn_decl_by_hir_id(hir_id) {
+                        visitor.visit_fn_decl(decl);
+                    }
+                }
+            }
+            _ => {}
+        }
+        let mut type_param_span: MultiSpan =
+            visitor.types.iter().cloned().collect::<Vec<_>>().into();
+        for &span in &visitor.types {
+            type_param_span.push_span_label(
+                span,
+                "consider borrowing this type parameter in the trait".to_string(),
+            );
+        }
+
+        if let Some((expected, found)) = tcx
+            .infer_ctxt()
+            .enter(|infcx| infcx.expected_found_str_ty(&ExpectedFound { expected, found }))
+        {
+            // Highlighted the differences when showing the "expected/found" note.
+            err.note_expected_found(&"", expected, &"", found);
+        } else {
+            // This fallback shouldn't be necessary, but let's keep it in just in case.
+            err.note(&format!("expected `{:?}`\n   found `{:?}`", expected, found));
+        }
+        err.span_help(
+            type_param_span,
+            "the lifetime requirements from the `impl` do not correspond to the requirements in \
+             the `trait`",
+        );
+        if visitor.types.is_empty() {
+            err.help(
+                "verify the lifetime relationships in the `trait` and `impl` between the `self` \
+                 argument, the other inputs and its output",
+            );
+        }
         err.emit();
     }
 }
+
+struct TypeParamSpanVisitor<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    types: Vec<Span>,
+}
+
+impl Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
+    type Map = rustc_middle::hir::map::Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
+        hir::intravisit::NestedVisitorMap::OnlyBodies(self.tcx.hir())
+    }
+
+    fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
+        match arg.kind {
+            hir::TyKind::Rptr(_, ref mut_ty) => {
+                // We don't want to suggest looking into borrowing `&T` or `&Self`.
+                hir::intravisit::walk_ty(self, mut_ty.ty);
+                return;
+            }
+            hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
+                [segment]
+                    if segment
+                        .res
+                        .map(|res| match res {
+                            Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _) => true,
+                            _ => false,
+                        })
+                        .unwrap_or(false) =>
+                {
+                    self.types.push(path.span);
+                }
+                _ => {}
+            },
+            _ => {}
+        }
+        hir::intravisit::walk_ty(self, arg);
+    }
+}
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
index 3e39c8a7924..137cb83ccd3 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
@@ -14,16 +14,16 @@ note: ...so that the expression is assignable
    |
 LL |    bar(foo, x)
    |             ^
-   = note: expected  `Type<'_>`
-              found  `Type<'a>`
+   = note: expected `Type<'_>`
+              found `Type<'a>`
    = note: but, the lifetime must be valid for the static lifetime...
 note: ...so that the expression is assignable
   --> $DIR/project-fn-ret-invariant.rs:48:4
    |
 LL |    bar(foo, x)
    |    ^^^^^^^^^^^
-   = note: expected  `Type<'static>`
-              found  `Type<'_>`
+   = note: expected `Type<'static>`
+              found `Type<'_>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0490.stderr b/src/test/ui/error-codes/E0490.stderr
index 03fce213605..9ba5bc330ea 100644
--- a/src/test/ui/error-codes/E0490.stderr
+++ b/src/test/ui/error-codes/E0490.stderr
@@ -58,8 +58,8 @@ note: ...so that the expression is assignable
    |
 LL |     let x: &'a _ = &y;
    |                    ^^
-   = note: expected  `&'a &()`
-              found  `&'a &'b ()`
+   = note: expected `&'a &()`
+              found `&'a &'b ()`
 note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 1:6...
   --> $DIR/E0490.rs:1:6
    |
diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr
index 3300293bb36..268008c2111 100644
--- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr
+++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr
@@ -14,16 +14,16 @@ note: ...so that the expression is assignable
    |
 LL |     static_val(x);
    |                ^
-   = note: expected  `std::boxed::Box<dyn std::fmt::Debug>`
-              found  `std::boxed::Box<(dyn std::fmt::Debug + 'a)>`
+   = note: expected `std::boxed::Box<dyn std::fmt::Debug>`
+              found `std::boxed::Box<(dyn std::fmt::Debug + 'a)>`
    = note: but, the lifetime must be valid for the static lifetime...
 note: ...so that the types are compatible
   --> $DIR/dyn-trait.rs:20:5
    |
 LL |     static_val(x);
    |     ^^^^^^^^^^
-   = note: expected  `StaticTrait`
-              found  `StaticTrait`
+   = note: expected `StaticTrait`
+              found `StaticTrait`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr
index c1c4ec9ed7b..b93d98ca39f 100644
--- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr
+++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr
@@ -2,15 +2,17 @@ error: `impl` item signature doesn't match `trait` item signature
   --> $DIR/mismatched_trait_impl-2.rs:8:5
    |
 LL |     fn deref(&self) -> &dyn Trait {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&Struct) -> &dyn Trait
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Struct) -> &dyn Trait`
    | 
   ::: $SRC_DIR/libcore/ops/deref.rs:LL:COL
    |
 LL |     fn deref(&self) -> &Self::Target;
-   |     --------------------------------- expected fn(&Struct) -> &(dyn Trait + 'static)
+   |     --------------------------------- expected `fn(&Struct) -> &(dyn Trait + 'static)`
    |
    = note: expected `fn(&Struct) -> &(dyn Trait + 'static)`
               found `fn(&Struct) -> &dyn Trait`
+   = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+   = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr
index c245d78ae82..149c2aeb958 100644
--- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr
+++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr
@@ -2,13 +2,15 @@ error: `impl` item signature doesn't match `trait` item signature
   --> $DIR/mismatched_trait_impl.rs:9:5
    |
 LL |     fn foo(&self, x: &'a u32, y: &u32) -> &'a u32;
-   |     ---------------------------------------------- expected fn(&i32, &'a u32, &u32) -> &'a u32
+   |     ---------------------------------------------- expected `fn(&i32, &'a u32, &u32) -> &'a u32`
 ...
 LL |     fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &u32, &u32) -> &u32
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &u32, &u32) -> &u32`
    |
    = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32`
               found `fn(&i32, &u32, &u32) -> &u32`
+   = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+   = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr
index 15891c9e7a6..9a0bd827850 100644
--- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr
+++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr
@@ -2,13 +2,15 @@ error: `impl` item signature doesn't match `trait` item signature
   --> $DIR/mismatched_trait_impl.rs:9:5
    |
 LL |     fn foo(&self, x: &'a u32, y: &u32) -> &'a u32;
-   |     ---------------------------------------------- expected fn(&i32, &'a u32, &u32) -> &'a u32
+   |     ---------------------------------------------- expected `fn(&i32, &'a u32, &u32) -> &'a u32`
 ...
 LL |     fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &u32, &u32) -> &u32
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &u32, &u32) -> &u32`
    |
    = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32`
               found `fn(&i32, &u32, &u32) -> &u32`
+   = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+   = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
 
 error[E0623]: lifetime mismatch
   --> $DIR/mismatched_trait_impl.rs:10:9
diff --git a/src/test/ui/issues/issue-16683.stderr b/src/test/ui/issues/issue-16683.stderr
index 99700f2084e..4f658330758 100644
--- a/src/test/ui/issues/issue-16683.stderr
+++ b/src/test/ui/issues/issue-16683.stderr
@@ -26,8 +26,8 @@ note: ...so that the types are compatible
    |
 LL |         self.a();
    |              ^
-   = note: expected  `&'a Self`
-              found  `&Self`
+   = note: expected `&'a Self`
+              found `&Self`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-17758.stderr b/src/test/ui/issues/issue-17758.stderr
index adfc3f50858..31788cfa61c 100644
--- a/src/test/ui/issues/issue-17758.stderr
+++ b/src/test/ui/issues/issue-17758.stderr
@@ -27,8 +27,8 @@ note: ...so that the types are compatible
    |
 LL |         self.foo();
    |              ^^^
-   = note: expected  `&'a Self`
-              found  `&Self`
+   = note: expected `&'a Self`
+              found `&Self`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-20831-debruijn.stderr b/src/test/ui/issues/issue-20831-debruijn.stderr
index a785a956ca9..e7c1dcc5d69 100644
--- a/src/test/ui/issues/issue-20831-debruijn.stderr
+++ b/src/test/ui/issues/issue-20831-debruijn.stderr
@@ -87,8 +87,8 @@ note: ...so that the types are compatible
    |
 LL |     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected  `Publisher<'_>`
-              found  `Publisher<'_>`
+   = note: expected `Publisher<'_>`
+              found `Publisher<'_>`
 
 error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
   --> $DIR/issue-20831-debruijn.rs:28:33
@@ -117,8 +117,8 @@ note: ...so that the types are compatible
    |
 LL |     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected  `Publisher<'_>`
-              found  `Publisher<'_>`
+   = note: expected `Publisher<'_>`
+              found `Publisher<'_>`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/issues/issue-52213.stderr b/src/test/ui/issues/issue-52213.stderr
index a8960f77563..7463af9332a 100644
--- a/src/test/ui/issues/issue-52213.stderr
+++ b/src/test/ui/issues/issue-52213.stderr
@@ -14,8 +14,8 @@ note: ...so that the types are compatible
    |
 LL |     match (&t,) {
    |           ^^^^^
-   = note: expected  `(&&(T,),)`
-              found  `(&&'a (T,),)`
+   = note: expected `(&&(T,),)`
+              found `(&&'a (T,),)`
 note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 1:27...
   --> $DIR/issue-52213.rs:1:27
    |
diff --git a/src/test/ui/issues/issue-55796.stderr b/src/test/ui/issues/issue-55796.stderr
index b8cafdc5c14..6bfb7af5444 100644
--- a/src/test/ui/issues/issue-55796.stderr
+++ b/src/test/ui/issues/issue-55796.stderr
@@ -20,8 +20,8 @@ note: ...so that the expression is assignable
    |
 LL |         Box::new(self.out_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected  `std::boxed::Box<(dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node> + 'static)>`
-              found  `std::boxed::Box<dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node>>`
+   = note: expected `std::boxed::Box<(dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node> + 'static)>`
+              found `std::boxed::Box<dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node>>`
 
 error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
   --> $DIR/issue-55796.rs:21:9
@@ -45,8 +45,8 @@ note: ...so that the expression is assignable
    |
 LL |         Box::new(self.in_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected  `std::boxed::Box<(dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node> + 'static)>`
-              found  `std::boxed::Box<dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node>>`
+   = note: expected `std::boxed::Box<(dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node> + 'static)>`
+              found `std::boxed::Box<dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node>>`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr
index d07f305954b..060e6954403 100644
--- a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr
+++ b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr
@@ -2,13 +2,15 @@ error: `impl` item signature doesn't match `trait` item signature
   --> $DIR/lifetime-mismatch-between-trait-and-impl.rs:6:5
    |
 LL |     fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32;
-   |     ------------------------------------------- expected fn(&i32, &'a i32) -> &'a i32
+   |     ------------------------------------------- expected `fn(&i32, &'a i32) -> &'a i32`
 ...
 LL |     fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &i32) -> &i32
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &i32) -> &i32`
    |
    = note: expected `fn(&i32, &'a i32) -> &'a i32`
               found `fn(&i32, &i32) -> &i32`
+   = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+   = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/issue-55394.stderr b/src/test/ui/nll/issue-55394.stderr
index 69a6ab004fd..ba8d91b8455 100644
--- a/src/test/ui/nll/issue-55394.stderr
+++ b/src/test/ui/nll/issue-55394.stderr
@@ -26,8 +26,8 @@ note: ...so that the expression is assignable
    |
 LL |         Foo { bar }
    |         ^^^^^^^^^^^
-   = note: expected  `Foo<'_>`
-              found  `Foo<'_>`
+   = note: expected `Foo<'_>`
+              found `Foo<'_>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/normalization-bounds-error.stderr b/src/test/ui/nll/normalization-bounds-error.stderr
index 58f206742f4..d003acd879a 100644
--- a/src/test/ui/nll/normalization-bounds-error.stderr
+++ b/src/test/ui/nll/normalization-bounds-error.stderr
@@ -19,8 +19,8 @@ note: ...so that the types are compatible
    |
 LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected  `Visitor<'d>`
-              found  `Visitor<'_>`
+   = note: expected `Visitor<'d>`
+              found `Visitor<'_>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/type-alias-free-regions.stderr b/src/test/ui/nll/type-alias-free-regions.stderr
index 5191deca281..3317aae83bb 100644
--- a/src/test/ui/nll/type-alias-free-regions.stderr
+++ b/src/test/ui/nll/type-alias-free-regions.stderr
@@ -16,8 +16,8 @@ note: ...so that the expression is assignable
    |
 LL |         C { f: b }
    |                ^
-   = note: expected  `std::boxed::Box<std::boxed::Box<&isize>>`
-              found  `std::boxed::Box<std::boxed::Box<&isize>>`
+   = note: expected `std::boxed::Box<std::boxed::Box<&isize>>`
+              found `std::boxed::Box<std::boxed::Box<&isize>>`
 note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 15:6...
   --> $DIR/type-alias-free-regions.rs:15:6
    |
@@ -28,8 +28,8 @@ note: ...so that the expression is assignable
    |
 LL |         C { f: b }
    |         ^^^^^^^^^^
-   = note: expected  `C<'a>`
-              found  `C<'_>`
+   = note: expected `C<'a>`
+              found `C<'_>`
 
 error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
   --> $DIR/type-alias-free-regions.rs:27:16
@@ -49,8 +49,8 @@ note: ...so that the expression is assignable
    |
 LL |         C { f: Box::new(b.0) }
    |                         ^^^
-   = note: expected  `std::boxed::Box<&isize>`
-              found  `std::boxed::Box<&isize>`
+   = note: expected `std::boxed::Box<&isize>`
+              found `std::boxed::Box<&isize>`
 note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 25:6...
   --> $DIR/type-alias-free-regions.rs:25:6
    |
@@ -61,8 +61,8 @@ note: ...so that the expression is assignable
    |
 LL |         C { f: Box::new(b.0) }
    |         ^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected  `C<'a>`
-              found  `C<'_>`
+   = note: expected `C<'a>`
+              found `C<'_>`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr
index 37be450fd0a..8421dc1d0c1 100644
--- a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr
@@ -14,8 +14,8 @@ note: ...so that the types are compatible
    |
 LL |     <Foo<'a>>::C
    |     ^^^^^^^^^^^^
-   = note: expected  `Foo<'_>`
-              found  `Foo<'a>`
+   = note: expected `Foo<'_>`
+              found `Foo<'a>`
    = note: but, the lifetime must be valid for the static lifetime...
 note: ...so that reference does not outlive borrowed content
   --> $DIR/constant-in-expr-inherent-1.rs:8:5
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr
index 4ee32847c5e..ba0a1748c5e 100644
--- a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr
@@ -14,8 +14,8 @@ note: ...so that the types are compatible
    |
 LL |     T::C
    |     ^^^^
-   = note: expected  `Foo<'_>`
-              found  `Foo<'a>`
+   = note: expected `Foo<'_>`
+              found `Foo<'a>`
    = note: but, the lifetime must be valid for the static lifetime...
 note: ...so that reference does not outlive borrowed content
   --> $DIR/constant-in-expr-trait-item-3.rs:10:5
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr b/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr
index 1952ee8269d..79ded5fc875 100644
--- a/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr
+++ b/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr
@@ -24,8 +24,8 @@ note: ...so that the expression is assignable
    |
 LL |     ss
    |     ^^
-   = note: expected  `&'b (dyn SomeTrait + 'b)`
-              found  `&dyn SomeTrait`
+   = note: expected `&'b (dyn SomeTrait + 'b)`
+              found `&dyn SomeTrait`
 
 error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
   --> $DIR/object-lifetime-default-elision.rs:71:5
@@ -53,8 +53,8 @@ note: ...so that the expression is assignable
    |
 LL |     ss
    |     ^^
-   = note: expected  `&'b (dyn SomeTrait + 'b)`
-              found  `&dyn SomeTrait`
+   = note: expected `&'b (dyn SomeTrait + 'b)`
+              found `&dyn SomeTrait`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr
index e8896516470..069b897603c 100644
--- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr
+++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr
@@ -39,8 +39,8 @@ note: ...so that the expression is assignable
    |
 LL |     Box::new(v)
    |              ^
-   = note: expected  `&[u8]`
-              found  `&'a [u8]`
+   = note: expected `&[u8]`
+              found `&'a [u8]`
 note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 25:9...
   --> $DIR/region-object-lifetime-in-coercion.rs:25:9
    |
@@ -51,8 +51,8 @@ note: ...so that the expression is assignable
    |
 LL |     Box::new(v)
    |     ^^^^^^^^^^^
-   = note: expected  `std::boxed::Box<(dyn Foo + 'b)>`
-              found  `std::boxed::Box<dyn Foo>`
+   = note: expected `std::boxed::Box<(dyn Foo + 'b)>`
+              found `std::boxed::Box<dyn Foo>`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr
index 865e967fba3..c134b3b3ed5 100644
--- a/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr
+++ b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr
@@ -14,8 +14,8 @@ note: ...so that the types are compatible
    |
 LL | impl<'a> Foo<'static> for &'a i32 {
    |          ^^^^^^^^^^^^
-   = note: expected  `Foo<'static>`
-              found  `Foo<'static>`
+   = note: expected `Foo<'static>`
+              found `Foo<'static>`
    = note: but, the lifetime must be valid for the static lifetime...
 note: ...so that the type `&i32` will meet its required lifetime bounds
   --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:14:10
@@ -39,8 +39,8 @@ note: ...so that the types are compatible
    |
 LL | impl<'a,'b> Foo<'b> for &'a i64 {
    |             ^^^^^^^
-   = note: expected  `Foo<'b>`
-              found  `Foo<'_>`
+   = note: expected `Foo<'b>`
+              found `Foo<'_>`
 note: but, the lifetime must be valid for the lifetime `'b` as defined on the impl at 19:9...
   --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:19:9
    |
diff --git a/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr
index 6a34871c07e..ac8c55ccc8f 100644
--- a/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr
+++ b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr
@@ -14,8 +14,8 @@ note: ...so that the types are compatible
    |
 LL | impl<'a> Foo for &'a i32 {
    |          ^^^
-   = note: expected  `Foo`
-              found  `Foo`
+   = note: expected `Foo`
+              found `Foo`
    = note: but, the lifetime must be valid for the static lifetime...
 note: ...so that the type `&i32` will meet its required lifetime bounds
   --> $DIR/regions-assoc-type-static-bound-in-trait-not-met.rs:9:10
diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr
index 28873ab807f..147f7f35418 100644
--- a/src/test/ui/regions/regions-close-object-into-object-2.stderr
+++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr
@@ -20,8 +20,8 @@ note: ...so that the expression is assignable
    |
 LL |     box B(&*v) as Box<dyn X>
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected  `std::boxed::Box<(dyn X + 'static)>`
-              found  `std::boxed::Box<dyn X>`
+   = note: expected `std::boxed::Box<(dyn X + 'static)>`
+              found `std::boxed::Box<dyn X>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr
index 449a5b5fdd4..6e7d6152cd0 100644
--- a/src/test/ui/regions/regions-close-object-into-object-4.stderr
+++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr
@@ -20,8 +20,8 @@ note: ...so that the expression is assignable
    |
 LL |     box B(&*v) as Box<dyn X>
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected  `std::boxed::Box<(dyn X + 'static)>`
-              found  `std::boxed::Box<dyn X>`
+   = note: expected `std::boxed::Box<(dyn X + 'static)>`
+              found `std::boxed::Box<dyn X>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr
index b2a7afaf1b4..2070ce257b1 100644
--- a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr
+++ b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr
@@ -24,8 +24,8 @@ note: ...so that the expression is assignable
    |
 LL |     box v as Box<dyn SomeTrait + 'a>
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected  `std::boxed::Box<(dyn SomeTrait + 'c)>`
-              found  `std::boxed::Box<dyn SomeTrait>`
+   = note: expected `std::boxed::Box<(dyn SomeTrait + 'c)>`
+              found `std::boxed::Box<dyn SomeTrait>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-creating-enums4.stderr b/src/test/ui/regions/regions-creating-enums4.stderr
index 58f74e4ee14..b24db1df18b 100644
--- a/src/test/ui/regions/regions-creating-enums4.stderr
+++ b/src/test/ui/regions/regions-creating-enums4.stderr
@@ -14,8 +14,8 @@ note: ...so that the expression is assignable
    |
 LL |     Ast::Add(x, y)
    |              ^
-   = note: expected  `&Ast<'_>`
-              found  `&Ast<'a>`
+   = note: expected `&Ast<'_>`
+              found `&Ast<'a>`
 note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 6:19...
   --> $DIR/regions-creating-enums4.rs:6:19
    |
@@ -26,8 +26,8 @@ note: ...so that the expression is assignable
    |
 LL |     Ast::Add(x, y)
    |     ^^^^^^^^^^^^^^
-   = note: expected  `Ast<'b>`
-              found  `Ast<'_>`
+   = note: expected `Ast<'b>`
+              found `Ast<'_>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-nested-fns.stderr b/src/test/ui/regions/regions-nested-fns.stderr
index 8fce1609d78..9e405d83140 100644
--- a/src/test/ui/regions/regions-nested-fns.stderr
+++ b/src/test/ui/regions/regions-nested-fns.stderr
@@ -39,8 +39,8 @@ LL | |         if false { return ay; }
 LL | |         return z;
 LL | |     }));
    | |_____^
-   = note: expected  `&isize`
-              found  `&isize`
+   = note: expected `&isize`
+              found `&isize`
 
 error[E0312]: lifetime of reference outlives lifetime of borrowed content...
   --> $DIR/regions-nested-fns.rs:14:27
diff --git a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr
index c35516d2c08..dc93d620ca6 100644
--- a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr
+++ b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr
@@ -29,8 +29,8 @@ LL | |     where <() as Project<'a, 'b>>::Item : Eq
 LL | | {
 LL | | }
    | |_^
-   = note: expected  `Project<'a, 'b>`
-              found  `Project<'_, '_>`
+   = note: expected `Project<'a, 'b>`
+              found `Project<'_, '_>`
 
 error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
   --> $DIR/regions-normalize-in-where-clause-list.rs:22:1
@@ -63,8 +63,8 @@ LL | |     where <() as Project<'a, 'b>>::Item : Eq
 LL | | {
 LL | | }
    | |_^
-   = note: expected  `Project<'a, 'b>`
-              found  `Project<'_, '_>`
+   = note: expected `Project<'a, 'b>`
+              found `Project<'_, '_>`
 
 error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
   --> $DIR/regions-normalize-in-where-clause-list.rs:22:4
@@ -87,8 +87,8 @@ note: ...so that the types are compatible
    |
 LL | fn bar<'a, 'b>()
    |    ^^^
-   = note: expected  `Project<'a, 'b>`
-              found  `Project<'_, '_>`
+   = note: expected `Project<'a, 'b>`
+              found `Project<'_, '_>`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/regions/regions-ret-borrowed-1.stderr b/src/test/ui/regions/regions-ret-borrowed-1.stderr
index 2895a0ccdee..2c4769d8e37 100644
--- a/src/test/ui/regions/regions-ret-borrowed-1.stderr
+++ b/src/test/ui/regions/regions-ret-borrowed-1.stderr
@@ -14,8 +14,8 @@ note: ...so that the expression is assignable
    |
 LL |     with(|o| o)
    |              ^
-   = note: expected  `&isize`
-              found  `&isize`
+   = note: expected `&isize`
+              found `&isize`
 note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 9:14...
   --> $DIR/regions-ret-borrowed-1.rs:9:14
    |
diff --git a/src/test/ui/regions/regions-ret-borrowed.stderr b/src/test/ui/regions/regions-ret-borrowed.stderr
index b74f10f5075..da560107cea 100644
--- a/src/test/ui/regions/regions-ret-borrowed.stderr
+++ b/src/test/ui/regions/regions-ret-borrowed.stderr
@@ -14,8 +14,8 @@ note: ...so that the expression is assignable
    |
 LL |     with(|o| o)
    |              ^
-   = note: expected  `&isize`
-              found  `&isize`
+   = note: expected `&isize`
+              found `&isize`
 note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 12:14...
   --> $DIR/regions-ret-borrowed.rs:12:14
    |
diff --git a/src/test/ui/regions/regions-trait-object-subtyping.stderr b/src/test/ui/regions/regions-trait-object-subtyping.stderr
index 58b79d21270..7478b53bd3c 100644
--- a/src/test/ui/regions/regions-trait-object-subtyping.stderr
+++ b/src/test/ui/regions/regions-trait-object-subtyping.stderr
@@ -41,8 +41,8 @@ note: ...so that the expression is assignable
    |
 LL |     x
    |     ^
-   = note: expected  `&'b mut (dyn Dummy + 'b)`
-              found  `&mut (dyn Dummy + 'b)`
+   = note: expected `&'b mut (dyn Dummy + 'b)`
+              found `&mut (dyn Dummy + 'b)`
 
 error[E0308]: mismatched types
   --> $DIR/regions-trait-object-subtyping.rs:22:5
diff --git a/src/test/ui/reject-specialized-drops-8142.stderr b/src/test/ui/reject-specialized-drops-8142.stderr
index c09418de518..f819faa2789 100644
--- a/src/test/ui/reject-specialized-drops-8142.stderr
+++ b/src/test/ui/reject-specialized-drops-8142.stderr
@@ -118,8 +118,8 @@ note: ...so that the types are compatible
    |
 LL | impl<'lw>         Drop for W<'lw,'lw>     { fn drop(&mut self) { } } // REJECT
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected  `W<'l1, 'l2>`
-              found  `W<'_, '_>`
+   = note: expected `W<'l1, 'l2>`
+              found `W<'_, '_>`
 
 error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the enum it is implemented for does not
   --> $DIR/reject-specialized-drops-8142.rs:61:14
diff --git a/src/test/ui/traits/self-without-lifetime-constraint.rs b/src/test/ui/traits/self-without-lifetime-constraint.rs
new file mode 100644
index 00000000000..99013d32ab8
--- /dev/null
+++ b/src/test/ui/traits/self-without-lifetime-constraint.rs
@@ -0,0 +1,53 @@
+use std::error::Error;
+use std::fmt;
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub enum ValueRef<'a> {
+    Null,
+    Integer(i64),
+    Real(f64),
+    Text(&'a [u8]),
+    Blob(&'a [u8]),
+}
+
+impl<'a> ValueRef<'a> {
+    pub fn as_str(&self) -> FromSqlResult<&'a str, &'a &'a str> {
+        match *self {
+            ValueRef::Text(t) => {
+                std::str::from_utf8(t).map_err(|_| FromSqlError::InvalidType).map(|x| (x, &x))
+            }
+            _ => Err(FromSqlError::InvalidType),
+        }
+    }
+}
+
+#[derive(Debug)]
+#[non_exhaustive]
+pub enum FromSqlError {
+    InvalidType
+}
+
+impl fmt::Display for FromSqlError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "InvalidType")
+    }
+}
+
+impl Error for FromSqlError {}
+
+pub type FromSqlResult<T, K> = Result<(T, K), FromSqlError>;
+
+pub trait FromSql: Sized {
+    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self, &Self>;
+}
+
+impl FromSql for &str {
+    fn column_result(value: ValueRef<'_>) -> FromSqlResult<&str, &&str> {
+    //~^ ERROR `impl` item signature doesn't match `trait` item signature
+        value.as_str()
+    }
+}
+
+pub fn main() {
+    println!("{}", "Hello World");
+}
diff --git a/src/test/ui/traits/self-without-lifetime-constraint.stderr b/src/test/ui/traits/self-without-lifetime-constraint.stderr
new file mode 100644
index 00000000000..6c7abe753e2
--- /dev/null
+++ b/src/test/ui/traits/self-without-lifetime-constraint.stderr
@@ -0,0 +1,19 @@
+error: `impl` item signature doesn't match `trait` item signature
+  --> $DIR/self-without-lifetime-constraint.rs:45:5
+   |
+LL |     fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self, &Self>;
+   |     -------------------------------------------------------------------- expected `fn(ValueRef<'_>) -> std::result::Result<(&str, &&str), FromSqlError>`
+...
+LL |     fn column_result(value: ValueRef<'_>) -> FromSqlResult<&str, &&str> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(ValueRef<'_>) -> std::result::Result<(&str, &&str), FromSqlError>`
+   |
+   = note: expected `fn(ValueRef<'_>) -> std::result::Result<(&str, &&str), _>`
+              found `fn(ValueRef<'_>) -> std::result::Result<(&str, &&str), _>`
+help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+  --> $DIR/self-without-lifetime-constraint.rs:41:60
+   |
+LL |     fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self, &Self>;
+   |                                                            ^^^^ consider borrowing this type parameter in the trait
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr b/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr
index 9fdcd4de495..46aa7db967a 100644
--- a/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr
+++ b/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr
@@ -19,8 +19,8 @@ note: ...so that the types are compatible
    |
 LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> {
    |             ^^^^^^^^^^
-   = note: expected  `T1<'a>`
-              found  `T1<'_>`
+   = note: expected `T1<'a>`
+              found `T1<'_>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/traits/trait-param-without-lifetime-constraint.rs b/src/test/ui/traits/trait-param-without-lifetime-constraint.rs
new file mode 100644
index 00000000000..a79b74dcdde
--- /dev/null
+++ b/src/test/ui/traits/trait-param-without-lifetime-constraint.rs
@@ -0,0 +1,20 @@
+struct Article {
+    proof_reader: ProofReader,
+}
+
+struct ProofReader {
+    name: String,
+}
+
+pub trait HaveRelationship<To> {
+    fn get_relation(&self) -> To;
+}
+
+impl HaveRelationship<&ProofReader> for Article {
+    fn get_relation(&self) -> &ProofReader {
+    //~^ ERROR `impl` item signature doesn't match `trait` item signature
+        &self.proof_reader
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr b/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr
new file mode 100644
index 00000000000..4942dbe480b
--- /dev/null
+++ b/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr
@@ -0,0 +1,19 @@
+error: `impl` item signature doesn't match `trait` item signature
+  --> $DIR/trait-param-without-lifetime-constraint.rs:14:5
+   |
+LL |     fn get_relation(&self) -> To;
+   |     ----------------------------- expected `fn(&Article) -> &ProofReader`
+...
+LL |     fn get_relation(&self) -> &ProofReader {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Article) -> &ProofReader`
+   |
+   = note: expected `fn(&Article) -> &ProofReader`
+              found `fn(&Article) -> &ProofReader`
+help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+  --> $DIR/trait-param-without-lifetime-constraint.rs:10:31
+   |
+LL |     fn get_relation(&self) -> To;
+   |                               ^^ consider borrowing this type parameter in the trait
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr
index e6029e0d462..e3c9d50dfe5 100644
--- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr
+++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr
@@ -23,8 +23,8 @@ note: ...so that the expression is assignable
    |
 LL |     Box::new(items.iter())
    |     ^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected  `std::boxed::Box<(dyn std::iter::Iterator<Item = &T> + 'static)>`
-              found  `std::boxed::Box<dyn std::iter::Iterator<Item = &T>>`
+   = note: expected `std::boxed::Box<(dyn std::iter::Iterator<Item = &T> + 'static)>`
+              found `std::boxed::Box<dyn std::iter::Iterator<Item = &T>>`
 
 error: aborting due to previous error