From 98ed5548d7e604470ab9a97ffed4d9c12e424d83 Mon Sep 17 00:00:00 2001
From: Michael Howell <michael@notriddle.com>
Date: Thu, 30 Sep 2021 22:47:41 -0700
Subject: [PATCH] nice_region_error: Include lifetime placeholders in error
 output

As you can see in src/test/ui/traits/self-without-lifetime-constraint.stderr
you can get very confusing type names if you don't have this.

Fixes #87763
---
 .../trait_impl_difference.rs                  | 59 +++++++++++++++----
 .../mismatched_trait_impl-2.stderr            |  8 +--
 .../mismatched_trait_impl.nll.stderr          |  8 +--
 .../mismatched_trait_impl.stderr              |  8 +--
 ...ime-mismatch-between-trait-and-impl.stderr |  8 +--
 .../issue-75361-mismatched-impl.stderr        |  8 +--
 .../param-without-lifetime-constraint.stderr  |  8 +--
 .../self-without-lifetime-constraint.stderr   |  8 +--
 8 files changed, 76 insertions(+), 39 deletions(-)

diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index ea9d0eae17e..b9e7ee12bc8 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -9,10 +9,13 @@ 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_middle::ty::print::RegionHighlightMode;
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
+
 use rustc_span::{MultiSpan, Span, Symbol};
 
+use std::ops::ControlFlow;
+
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`.
     pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option<ErrorReported> {
@@ -69,6 +72,47 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             .tcx()
             .sess
             .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature");
+
+        // Mark all unnamed regions in the type with a number.
+        // This diagnostic is called in response to lifetime errors, so be informative.
+        struct HighlightBuilder<'tcx> {
+            highlight: RegionHighlightMode,
+            tcx: TyCtxt<'tcx>,
+            counter: usize,
+        }
+
+        impl HighlightBuilder<'tcx> {
+            fn build(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> RegionHighlightMode {
+                let mut builder =
+                    HighlightBuilder { highlight: RegionHighlightMode::default(), counter: 1, tcx };
+                builder.visit_ty(ty);
+                builder.highlight
+            }
+        }
+
+        impl<'tcx> ty::fold::TypeVisitor<'tcx> for HighlightBuilder<'tcx> {
+            fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+                Some(self.tcx)
+            }
+
+            fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+                if !r.has_name() && self.counter <= 3 {
+                    self.highlight.highlighting_region(r, self.counter);
+                    self.counter += 1;
+                }
+                r.super_visit_with(self)
+            }
+        }
+
+        let expected_highlight = HighlightBuilder::build(self.tcx(), expected);
+        let expected = self
+            .infcx
+            .extract_inference_diagnostics_data(expected.into(), Some(expected_highlight))
+            .name;
+        let found_highlight = HighlightBuilder::build(self.tcx(), found);
+        let found =
+            self.infcx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
+
         err.span_label(sp, &format!("found `{}`", found));
         err.span_label(trait_sp, &format!("expected `{}`", expected));
 
@@ -96,15 +140,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             );
         }
 
-        if let Some((expected, found)) =
-            self.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.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 \
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 b15efd6c770..0546b6b51b2 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,15 @@ 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(&'1 Struct) -> &'1 (dyn Trait + '1)`
    |
   ::: $SRC_DIR/core/src/ops/deref.rs:LL:COL
    |
 LL |     fn deref(&self) -> &Self::Target;
-   |     --------------------------------- expected `fn(&Struct) -> &(dyn Trait + 'static)`
+   |     --------------------------------- expected `fn(&'1 Struct) -> &'1 (dyn Trait + 'static)`
    |
-   = note: expected `fn(&Struct) -> &(dyn Trait + 'static)`
-              found `fn(&Struct) -> &dyn Trait`
+   = note: expected `fn(&'1 Struct) -> &'1 (dyn Trait + 'static)`
+              found `fn(&'1 Struct) -> &'1 (dyn Trait + '1)`
    = 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
 
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 149c2aeb958..c7a90c57add 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,13 @@ 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(&'1 i32, &'a u32, &'2 u32) -> &'a u32`
 ...
 LL |     fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &u32, &u32) -> &u32`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 i32, &'2 u32, &'3 u32) -> &'3 u32`
    |
-   = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32`
-              found `fn(&i32, &u32, &u32) -> &u32`
+   = note: expected `fn(&'1 i32, &'a u32, &'2 u32) -> &'a u32`
+              found `fn(&'1 i32, &'2 u32, &'3 u32) -> &'3 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
 
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 9a0bd827850..84e5339122e 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,13 @@ 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(&'1 i32, &'a u32, &'2 u32) -> &'a u32`
 ...
 LL |     fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &u32, &u32) -> &u32`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 i32, &'2 u32, &'3 u32) -> &'3 u32`
    |
-   = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32`
-              found `fn(&i32, &u32, &u32) -> &u32`
+   = note: expected `fn(&'1 i32, &'a u32, &'2 u32) -> &'a u32`
+              found `fn(&'1 i32, &'2 u32, &'3 u32) -> &'3 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
 
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 060e6954403..3040a8512ce 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,13 @@ 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(&'1 i32, &'a i32) -> &'a i32`
 ...
 LL |     fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &i32) -> &i32`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 i32, &'1 i32) -> &'1 i32`
    |
-   = note: expected `fn(&i32, &'a i32) -> &'a i32`
-              found `fn(&i32, &i32) -> &i32`
+   = note: expected `fn(&'1 i32, &'a i32) -> &'a i32`
+              found `fn(&'1 i32, &'1 i32) -> &'1 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
 
diff --git a/src/test/ui/mismatched_types/issue-75361-mismatched-impl.stderr b/src/test/ui/mismatched_types/issue-75361-mismatched-impl.stderr
index 9867addaf38..2a2c23c9421 100644
--- a/src/test/ui/mismatched_types/issue-75361-mismatched-impl.stderr
+++ b/src/test/ui/mismatched_types/issue-75361-mismatched-impl.stderr
@@ -2,13 +2,13 @@ error: `impl` item signature doesn't match `trait` item signature
   --> $DIR/issue-75361-mismatched-impl.rs:18:3
    |
 LL |   fn adjacent_edges(&self) -> Box<dyn MyTrait<Item = &Self::EdgeType>>;
-   |   --------------------------------------------------------------------- expected `fn(&T) -> Box<(dyn MyTrait<Item = &T> + 'static)>`
+   |   --------------------------------------------------------------------- expected `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + 'static)>`
 ...
 LL |   fn adjacent_edges(&self) -> Box<dyn MyTrait<Item = &Self::EdgeType> + '_> {
-   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&T) -> Box<dyn MyTrait<Item = &T>>`
+   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + '1)>`
    |
-   = note: expected `fn(&T) -> Box<(dyn MyTrait<Item = &T> + 'static)>`
-              found `fn(&T) -> Box<dyn MyTrait<Item = &T>>`
+   = note: expected `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + 'static)>`
+              found `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + '1)>`
 help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
   --> $DIR/issue-75361-mismatched-impl.rs:12:55
    |
diff --git a/src/test/ui/traits/param-without-lifetime-constraint.stderr b/src/test/ui/traits/param-without-lifetime-constraint.stderr
index 763fb5186cc..118b2cf3ecd 100644
--- a/src/test/ui/traits/param-without-lifetime-constraint.stderr
+++ b/src/test/ui/traits/param-without-lifetime-constraint.stderr
@@ -2,13 +2,13 @@ error: `impl` item signature doesn't match `trait` item signature
   --> $DIR/param-without-lifetime-constraint.rs:14:5
    |
 LL |     fn get_relation(&self) -> To;
-   |     ----------------------------- expected `fn(&Article) -> &ProofReader`
+   |     ----------------------------- expected `fn(&'1 Article) -> &'2 ProofReader`
 ...
 LL |     fn get_relation(&self) -> &ProofReader {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Article) -> &ProofReader`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 Article) -> &'1 ProofReader`
    |
-   = note: expected `fn(&Article) -> &ProofReader`
-              found `fn(&Article) -> &ProofReader`
+   = note: expected `fn(&'1 Article) -> &'2 ProofReader`
+              found `fn(&'1 Article) -> &'1 ProofReader`
 help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
   --> $DIR/param-without-lifetime-constraint.rs:10:31
    |
diff --git a/src/test/ui/traits/self-without-lifetime-constraint.stderr b/src/test/ui/traits/self-without-lifetime-constraint.stderr
index 73b5aec022c..85fada3b87c 100644
--- a/src/test/ui/traits/self-without-lifetime-constraint.stderr
+++ b/src/test/ui/traits/self-without-lifetime-constraint.stderr
@@ -2,13 +2,13 @@ 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<'_>) -> Result<(&str, &&str), FromSqlError>`
+   |     -------------------------------------------------------------------- expected `fn(ValueRef<'1>) -> Result<(&'2 str, &'1 &'2 str), FromSqlError>`
 ...
 LL |     fn column_result(value: ValueRef<'_>) -> FromSqlResult<&str, &&str> {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(ValueRef<'_>) -> Result<(&str, &&str), FromSqlError>`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(ValueRef<'1>) -> Result<(&'1 str, &'1 &'1 str), FromSqlError>`
    |
-   = note: expected `fn(ValueRef<'_>) -> Result<(&str, &&str), _>`
-              found `fn(ValueRef<'_>) -> Result<(&str, &&str), _>`
+   = note: expected `fn(ValueRef<'1>) -> Result<(&'2 str, &'1 &'2 str), FromSqlError>`
+              found `fn(ValueRef<'1>) -> Result<(&'1 str, &'1 &'1 str), FromSqlError>`
 help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
   --> $DIR/self-without-lifetime-constraint.rs:41:60
    |