From 334577f0910f64f3865f3803d124b299bf0f3fe5 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Mon, 27 Nov 2023 03:20:45 +0000
Subject: [PATCH 1/2] Add deeply_normalize_for_diagnostics, use it in coherence

---
 .../rustc_trait_selection/src/solve/mod.rs    |  4 +++-
 .../src/solve/normalize.rs                    | 16 +++++++++++++-
 .../src/traits/coherence.rs                   | 14 ++++++++++--
 .../normalize-for-errors.current.stderr       | 14 ++++++++++++
 .../normalize-for-errors.next.stderr          | 14 ++++++++++++
 tests/ui/coherence/normalize-for-errors.rs    | 22 +++++++++++++++++++
 6 files changed, 80 insertions(+), 4 deletions(-)
 create mode 100644 tests/ui/coherence/normalize-for-errors.current.stderr
 create mode 100644 tests/ui/coherence/normalize-for-errors.next.stderr
 create mode 100644 tests/ui/coherence/normalize-for-errors.rs

diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index b9e256236e9..bf3b72caeb4 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -41,7 +41,9 @@ mod trait_goals;
 
 pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt};
 pub use fulfill::FulfillmentCtxt;
-pub(crate) use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes};
+pub(crate) use normalize::{
+    deeply_normalize, deeply_normalize_for_diagnostics, deeply_normalize_with_skipped_universes,
+};
 
 #[derive(Debug, Clone, Copy)]
 enum SolverMode {
diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs
index b0a34898570..af522799db8 100644
--- a/compiler/rustc_trait_selection/src/solve/normalize.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalize.rs
@@ -4,10 +4,11 @@ use crate::traits::{needs_normalization, BoundVarReplacer, PlaceholderReplacer};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_infer::infer::at::At;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::TraitEngineExt;
 use rustc_infer::traits::{FulfillmentError, Obligation, TraitEngine};
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
-use rustc_middle::traits::Reveal;
+use rustc_middle::traits::{ObligationCause, Reveal};
 use rustc_middle::ty::{self, AliasTy, Ty, TyCtxt, UniverseIndex};
 use rustc_middle::ty::{FallibleTypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::{TypeFoldable, TypeVisitableExt};
@@ -41,6 +42,19 @@ pub(crate) fn deeply_normalize_with_skipped_universes<'tcx, T: TypeFoldable<TyCt
     value.try_fold_with(&mut folder)
 }
 
+// Deeply normalize a value and return it
+pub(crate) fn deeply_normalize_for_diagnostics<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
+    infcx: &InferCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    t: T,
+) -> T {
+    infcx
+        .commit_if_ok(|_| {
+            deeply_normalize(infcx.at(&ObligationCause::dummy(), param_env), t.clone())
+        })
+        .unwrap_or(t)
+}
+
 struct NormalizationFolder<'me, 'tcx> {
     at: At<'me, 'tcx>,
     fulfill_cx: FulfillmentCtxt<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 8e97333ad0f..9f2e1df8ef8 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -6,8 +6,8 @@
 
 use crate::infer::outlives::env::OutlivesEnvironment;
 use crate::infer::InferOk;
-use crate::solve::inspect;
 use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
+use crate::solve::{deeply_normalize_for_diagnostics, inspect};
 use crate::traits::engine::TraitEngineExt;
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use crate::traits::select::{IntercrateAmbiguityCause, TreatInductiveCycleAs};
@@ -308,7 +308,13 @@ fn overlap<'tcx>(
         .iter()
         .any(|c| c.0.involves_placeholders());
 
-    let impl_header = selcx.infcx.resolve_vars_if_possible(impl1_header);
+    let mut impl_header = infcx.resolve_vars_if_possible(impl1_header);
+
+    // Deeply normalize the impl header for diagnostics, ignoring any errors if this fails.
+    if infcx.next_trait_solver() {
+        impl_header = deeply_normalize_for_diagnostics(&infcx, param_env, impl_header);
+    }
+
     Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder })
 }
 
@@ -1084,6 +1090,10 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
                         Ok(Ok(())) => warn!("expected an unknowable trait ref: {trait_ref:?}"),
                         Ok(Err(conflict)) => {
                             if !trait_ref.references_error() {
+                                // Normalize the trait ref for diagnostics, ignoring any errors if this fails.
+                                let trait_ref =
+                                    deeply_normalize_for_diagnostics(infcx, param_env, trait_ref);
+
                                 let self_ty = trait_ref.self_ty();
                                 let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty);
                                 ambiguity_cause = Some(match conflict {
diff --git a/tests/ui/coherence/normalize-for-errors.current.stderr b/tests/ui/coherence/normalize-for-errors.current.stderr
new file mode 100644
index 00000000000..df71d80e7fb
--- /dev/null
+++ b/tests/ui/coherence/normalize-for-errors.current.stderr
@@ -0,0 +1,14 @@
+error[E0119]: conflicting implementations of trait `MyTrait` for type `Box<(MyType,)>`
+  --> $DIR/normalize-for-errors.rs:17:1
+   |
+LL | impl<T: Copy> MyTrait for T {}
+   | --------------------------- first implementation here
+LL |
+LL | impl MyTrait for Box<<(MyType,) as Mirror>::Assoc> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<(MyType,)>`
+   |
+   = note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/coherence/normalize-for-errors.next.stderr b/tests/ui/coherence/normalize-for-errors.next.stderr
new file mode 100644
index 00000000000..df71d80e7fb
--- /dev/null
+++ b/tests/ui/coherence/normalize-for-errors.next.stderr
@@ -0,0 +1,14 @@
+error[E0119]: conflicting implementations of trait `MyTrait` for type `Box<(MyType,)>`
+  --> $DIR/normalize-for-errors.rs:17:1
+   |
+LL | impl<T: Copy> MyTrait for T {}
+   | --------------------------- first implementation here
+LL |
+LL | impl MyTrait for Box<<(MyType,) as Mirror>::Assoc> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<(MyType,)>`
+   |
+   = note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/coherence/normalize-for-errors.rs b/tests/ui/coherence/normalize-for-errors.rs
new file mode 100644
index 00000000000..f488ad3d468
--- /dev/null
+++ b/tests/ui/coherence/normalize-for-errors.rs
@@ -0,0 +1,22 @@
+// revisions: current next
+//[next] compile-flags: -Ztrait-solver=next
+
+struct MyType;
+trait MyTrait {
+}
+
+trait Mirror {
+    type Assoc;
+}
+impl<T> Mirror for T {
+    type Assoc = T;
+}
+
+impl<T: Copy> MyTrait for T {}
+//~^ NOTE first implementation here
+impl MyTrait for Box<<(MyType,) as Mirror>::Assoc> {}
+//~^ ERROR conflicting implementations of trait `MyTrait` for type `Box<(MyType,)>`
+//~| NOTE conflicting implementation for `Box<(MyType,)>
+//~| NOTE upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions
+
+fn main() {}

From 3448284f8df0f136835500d220addc1326ab98d6 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Tue, 28 Nov 2023 21:45:37 +0000
Subject: [PATCH 2/2] Continue folding if deep normalizer fails

---
 .../src/solve/normalize.rs                    | 54 ++++++++++++++-----
 .../normalize-for-errors.current.stderr       | 12 ++---
 .../normalize-for-errors.next.stderr          | 12 ++---
 tests/ui/coherence/normalize-for-errors.rs    | 11 ++--
 4 files changed, 57 insertions(+), 32 deletions(-)

diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs
index af522799db8..ea512ba5fa7 100644
--- a/compiler/rustc_trait_selection/src/solve/normalize.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalize.rs
@@ -10,7 +10,7 @@ use rustc_infer::traits::{FulfillmentError, Obligation, TraitEngine};
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
 use rustc_middle::traits::{ObligationCause, Reveal};
 use rustc_middle::ty::{self, AliasTy, Ty, TyCtxt, UniverseIndex};
-use rustc_middle::ty::{FallibleTypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::{TypeFoldable, TypeVisitableExt};
 
 use super::FulfillmentCtxt;
@@ -42,19 +42,6 @@ pub(crate) fn deeply_normalize_with_skipped_universes<'tcx, T: TypeFoldable<TyCt
     value.try_fold_with(&mut folder)
 }
 
-// Deeply normalize a value and return it
-pub(crate) fn deeply_normalize_for_diagnostics<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
-    infcx: &InferCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    t: T,
-) -> T {
-    infcx
-        .commit_if_ok(|_| {
-            deeply_normalize(infcx.at(&ObligationCause::dummy(), param_env), t.clone())
-        })
-        .unwrap_or(t)
-}
-
 struct NormalizationFolder<'me, 'tcx> {
     at: At<'me, 'tcx>,
     fulfill_cx: FulfillmentCtxt<'tcx>,
@@ -244,3 +231,42 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> {
         }
     }
 }
+
+// Deeply normalize a value and return it
+pub(crate) fn deeply_normalize_for_diagnostics<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
+    infcx: &InferCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    t: T,
+) -> T {
+    t.fold_with(&mut DeeplyNormalizeForDiagnosticsFolder {
+        at: infcx.at(&ObligationCause::dummy(), param_env),
+    })
+}
+
+struct DeeplyNormalizeForDiagnosticsFolder<'a, 'tcx> {
+    at: At<'a, 'tcx>,
+}
+
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for DeeplyNormalizeForDiagnosticsFolder<'_, 'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
+        self.at.infcx.tcx
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        deeply_normalize_with_skipped_universes(
+            self.at,
+            ty,
+            vec![None; ty.outer_exclusive_binder().as_usize()],
+        )
+        .unwrap_or_else(|_| ty.super_fold_with(self))
+    }
+
+    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        deeply_normalize_with_skipped_universes(
+            self.at,
+            ct,
+            vec![None; ct.outer_exclusive_binder().as_usize()],
+        )
+        .unwrap_or_else(|_| ct.super_fold_with(self))
+    }
+}
diff --git a/tests/ui/coherence/normalize-for-errors.current.stderr b/tests/ui/coherence/normalize-for-errors.current.stderr
index df71d80e7fb..0e48aaed879 100644
--- a/tests/ui/coherence/normalize-for-errors.current.stderr
+++ b/tests/ui/coherence/normalize-for-errors.current.stderr
@@ -1,11 +1,11 @@
-error[E0119]: conflicting implementations of trait `MyTrait` for type `Box<(MyType,)>`
-  --> $DIR/normalize-for-errors.rs:17:1
+error[E0119]: conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>, _)`
+  --> $DIR/normalize-for-errors.rs:16:1
    |
-LL | impl<T: Copy> MyTrait for T {}
-   | --------------------------- first implementation here
+LL | impl<T: Copy, S: Iterator> MyTrait<S> for (T, S::Item) {}
+   | ------------------------------------------------------ first implementation here
 LL |
-LL | impl MyTrait for Box<<(MyType,) as Mirror>::Assoc> {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<(MyType,)>`
+LL | impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(Box<(MyType,)>, _)`
    |
    = note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions
 
diff --git a/tests/ui/coherence/normalize-for-errors.next.stderr b/tests/ui/coherence/normalize-for-errors.next.stderr
index df71d80e7fb..a8a7d437b32 100644
--- a/tests/ui/coherence/normalize-for-errors.next.stderr
+++ b/tests/ui/coherence/normalize-for-errors.next.stderr
@@ -1,11 +1,11 @@
-error[E0119]: conflicting implementations of trait `MyTrait` for type `Box<(MyType,)>`
-  --> $DIR/normalize-for-errors.rs:17:1
+error[E0119]: conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>, <_ as Iterator>::Item)`
+  --> $DIR/normalize-for-errors.rs:16:1
    |
-LL | impl<T: Copy> MyTrait for T {}
-   | --------------------------- first implementation here
+LL | impl<T: Copy, S: Iterator> MyTrait<S> for (T, S::Item) {}
+   | ------------------------------------------------------ first implementation here
 LL |
-LL | impl MyTrait for Box<<(MyType,) as Mirror>::Assoc> {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<(MyType,)>`
+LL | impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(Box<(MyType,)>, <_ as Iterator>::Item)`
    |
    = note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions
 
diff --git a/tests/ui/coherence/normalize-for-errors.rs b/tests/ui/coherence/normalize-for-errors.rs
index f488ad3d468..367d34251ae 100644
--- a/tests/ui/coherence/normalize-for-errors.rs
+++ b/tests/ui/coherence/normalize-for-errors.rs
@@ -2,8 +2,7 @@
 //[next] compile-flags: -Ztrait-solver=next
 
 struct MyType;
-trait MyTrait {
-}
+trait MyTrait<S> {}
 
 trait Mirror {
     type Assoc;
@@ -12,11 +11,11 @@ impl<T> Mirror for T {
     type Assoc = T;
 }
 
-impl<T: Copy> MyTrait for T {}
+impl<T: Copy, S: Iterator> MyTrait<S> for (T, S::Item) {}
 //~^ NOTE first implementation here
-impl MyTrait for Box<<(MyType,) as Mirror>::Assoc> {}
-//~^ ERROR conflicting implementations of trait `MyTrait` for type `Box<(MyType,)>`
-//~| NOTE conflicting implementation for `Box<(MyType,)>
+impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {}
+//~^ ERROR conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>,
+//~| NOTE conflicting implementation for `(Box<(MyType,)>,
 //~| NOTE upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions
 
 fn main() {}