From fdaec57a28ab6a8cd60fd7a2842d366a9b452a2e Mon Sep 17 00:00:00 2001
From: lcnr <rust@lcnr.de>
Date: Tue, 18 Jul 2023 17:03:22 +0200
Subject: [PATCH 1/6] XSimplifiedType to SimplifiedType::X

---
 .../src/coherence/orphan.rs                   |  10 +-
 compiler/rustc_middle/src/ty/fast_reject.rs   | 112 +++++++++---------
 .../src/solve/trait_goals.rs                  |   2 +-
 src/librustdoc/clean/inline.rs                |   4 +-
 src/librustdoc/clean/types.rs                 |  51 ++++----
 .../src/utils/internal_lints/invalid_paths.rs |   8 +-
 src/tools/clippy/clippy_utils/src/lib.rs      |  47 ++++----
 7 files changed, 116 insertions(+), 118 deletions(-)

diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 05c78f5708814..21ffbefcd0810 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -568,10 +568,10 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty:
 
     impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for DisableAutoTraitVisitor<'tcx> {
         type BreakTy = ();
-        fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+        fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
             let tcx = self.tcx;
-            if t != self.self_ty_root {
-                for impl_def_id in tcx.non_blanket_impls_for_ty(self.trait_def_id, t) {
+            if ty != self.self_ty_root {
+                for impl_def_id in tcx.non_blanket_impls_for_ty(self.trait_def_id, ty) {
                     match tcx.impl_polarity(impl_def_id) {
                         ImplPolarity::Negative => return ControlFlow::Break(()),
                         ImplPolarity::Reservation => {}
@@ -584,7 +584,7 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty:
                 }
             }
 
-            match t.kind() {
+            match ty.kind() {
                 ty::Adt(def, args) if def.is_phantom_data() => args.visit_with(self),
                 ty::Adt(def, args) => {
                     // @lcnr: This is the only place where cycles can happen. We avoid this
@@ -599,7 +599,7 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty:
 
                     ControlFlow::Continue(())
                 }
-                _ => t.super_visit_with(self),
+                _ => ty.super_visit_with(self),
             }
         }
     }
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index e86ff4d26aaab..deb4dcf1f760a 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -6,35 +6,33 @@ use std::fmt::Debug;
 use std::hash::Hash;
 use std::iter;
 
-use self::SimplifiedType::*;
-
 /// See `simplify_type`.
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
 pub enum SimplifiedType {
-    BoolSimplifiedType,
-    CharSimplifiedType,
-    IntSimplifiedType(ty::IntTy),
-    UintSimplifiedType(ty::UintTy),
-    FloatSimplifiedType(ty::FloatTy),
-    AdtSimplifiedType(DefId),
-    ForeignSimplifiedType(DefId),
-    StrSimplifiedType,
-    ArraySimplifiedType,
-    SliceSimplifiedType,
-    RefSimplifiedType(Mutability),
-    PtrSimplifiedType(Mutability),
-    NeverSimplifiedType,
-    TupleSimplifiedType(usize),
+    Bool,
+    Char,
+    Int(ty::IntTy),
+    Uint(ty::UintTy),
+    Float(ty::FloatTy),
+    Adt(DefId),
+    Foreign(DefId),
+    Str,
+    Array,
+    Slice,
+    Ref(Mutability),
+    Ptr(Mutability),
+    Never,
+    Tuple(usize),
     /// A trait object, all of whose components are markers
     /// (e.g., `dyn Send + Sync`).
-    MarkerTraitObjectSimplifiedType,
-    TraitSimplifiedType(DefId),
-    ClosureSimplifiedType(DefId),
-    GeneratorSimplifiedType(DefId),
-    GeneratorWitnessSimplifiedType(usize),
-    GeneratorWitnessMIRSimplifiedType(DefId),
-    FunctionSimplifiedType(usize),
-    PlaceholderSimplifiedType,
+    MarkerTraitObject,
+    Trait(DefId),
+    Closure(DefId),
+    Generator(DefId),
+    GeneratorWitness(usize),
+    GeneratorWitnessMIR(DefId),
+    Function(usize),
+    Placeholder,
 }
 
 /// Generic parameters are pretty much just bound variables, e.g.
@@ -110,34 +108,36 @@ pub fn simplify_type<'tcx>(
     treat_params: TreatParams,
 ) -> Option<SimplifiedType> {
     match *ty.kind() {
-        ty::Bool => Some(BoolSimplifiedType),
-        ty::Char => Some(CharSimplifiedType),
-        ty::Int(int_type) => Some(IntSimplifiedType(int_type)),
-        ty::Uint(uint_type) => Some(UintSimplifiedType(uint_type)),
-        ty::Float(float_type) => Some(FloatSimplifiedType(float_type)),
-        ty::Adt(def, _) => Some(AdtSimplifiedType(def.did())),
-        ty::Str => Some(StrSimplifiedType),
-        ty::Array(..) => Some(ArraySimplifiedType),
-        ty::Slice(..) => Some(SliceSimplifiedType),
-        ty::RawPtr(ptr) => Some(PtrSimplifiedType(ptr.mutbl)),
+        ty::Bool => Some(SimplifiedType::Bool),
+        ty::Char => Some(SimplifiedType::Char),
+        ty::Int(int_type) => Some(SimplifiedType::Int(int_type)),
+        ty::Uint(uint_type) => Some(SimplifiedType::Uint(uint_type)),
+        ty::Float(float_type) => Some(SimplifiedType::Float(float_type)),
+        ty::Adt(def, _) => Some(SimplifiedType::Adt(def.did())),
+        ty::Str => Some(SimplifiedType::Str),
+        ty::Array(..) => Some(SimplifiedType::Array),
+        ty::Slice(..) => Some(SimplifiedType::Slice),
+        ty::RawPtr(ptr) => Some(SimplifiedType::Ptr(ptr.mutbl)),
         ty::Dynamic(trait_info, ..) => match trait_info.principal_def_id() {
             Some(principal_def_id) if !tcx.trait_is_auto(principal_def_id) => {
-                Some(TraitSimplifiedType(principal_def_id))
+                Some(SimplifiedType::Trait(principal_def_id))
             }
-            _ => Some(MarkerTraitObjectSimplifiedType),
+            _ => Some(SimplifiedType::MarkerTraitObject),
         },
-        ty::Ref(_, _, mutbl) => Some(RefSimplifiedType(mutbl)),
-        ty::FnDef(def_id, _) | ty::Closure(def_id, _) => Some(ClosureSimplifiedType(def_id)),
-        ty::Generator(def_id, _, _) => Some(GeneratorSimplifiedType(def_id)),
-        ty::GeneratorWitness(tys) => Some(GeneratorWitnessSimplifiedType(tys.skip_binder().len())),
-        ty::GeneratorWitnessMIR(def_id, _) => Some(GeneratorWitnessMIRSimplifiedType(def_id)),
-        ty::Never => Some(NeverSimplifiedType),
-        ty::Tuple(tys) => Some(TupleSimplifiedType(tys.len())),
-        ty::FnPtr(f) => Some(FunctionSimplifiedType(f.skip_binder().inputs().len())),
-        ty::Placeholder(..) => Some(PlaceholderSimplifiedType),
+        ty::Ref(_, _, mutbl) => Some(SimplifiedType::Ref(mutbl)),
+        ty::FnDef(def_id, _) | ty::Closure(def_id, _) => Some(SimplifiedType::Closure(def_id)),
+        ty::Generator(def_id, _, _) => Some(SimplifiedType::Generator(def_id)),
+        ty::GeneratorWitness(tys) => {
+            Some(SimplifiedType::GeneratorWitness(tys.skip_binder().len()))
+        }
+        ty::GeneratorWitnessMIR(def_id, _) => Some(SimplifiedType::GeneratorWitnessMIR(def_id)),
+        ty::Never => Some(SimplifiedType::Never),
+        ty::Tuple(tys) => Some(SimplifiedType::Tuple(tys.len())),
+        ty::FnPtr(f) => Some(SimplifiedType::Function(f.skip_binder().inputs().len())),
+        ty::Placeholder(..) => Some(SimplifiedType::Placeholder),
         ty::Param(_) => match treat_params {
             TreatParams::ForLookup | TreatParams::NextSolverLookup => {
-                Some(PlaceholderSimplifiedType)
+                Some(SimplifiedType::Placeholder)
             }
             TreatParams::AsCandidateKey => None,
         },
@@ -147,11 +147,13 @@ pub fn simplify_type<'tcx>(
             //
             // We will have to be careful with lazy normalization here.
             // FIXME(lazy_normalization): This is probably not right...
-            TreatParams::ForLookup if !ty.has_non_region_infer() => Some(PlaceholderSimplifiedType),
-            TreatParams::NextSolverLookup => Some(PlaceholderSimplifiedType),
+            TreatParams::ForLookup if !ty.has_non_region_infer() => {
+                Some(SimplifiedType::Placeholder)
+            }
+            TreatParams::NextSolverLookup => Some(SimplifiedType::Placeholder),
             TreatParams::ForLookup | TreatParams::AsCandidateKey => None,
         },
-        ty::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)),
+        ty::Foreign(def_id) => Some(SimplifiedType::Foreign(def_id)),
         ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None,
     }
 }
@@ -159,12 +161,12 @@ pub fn simplify_type<'tcx>(
 impl SimplifiedType {
     pub fn def(self) -> Option<DefId> {
         match self {
-            AdtSimplifiedType(d)
-            | ForeignSimplifiedType(d)
-            | TraitSimplifiedType(d)
-            | ClosureSimplifiedType(d)
-            | GeneratorSimplifiedType(d)
-            | GeneratorWitnessMIRSimplifiedType(d) => Some(d),
+            SimplifiedType::Adt(d)
+            | SimplifiedType::Foreign(d)
+            | SimplifiedType::Trait(d)
+            | SimplifiedType::Closure(d)
+            | SimplifiedType::Generator(d)
+            | SimplifiedType::GeneratorWitnessMIR(d) => Some(d),
             _ => None,
         }
     }
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index e7867eead1597..29889614620dd 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -686,7 +686,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             | ty::Tuple(_)
             | ty::Adt(_, _)
             // FIXME: Handling opaques here is kinda sus. Especially because we
-            // simplify them to PlaceholderSimplifiedType.
+            // simplify them to SimplifiedType::Placeholder.
             | ty::Alias(ty::Opaque, _) => {
                 let mut disqualifying_impl = None;
                 self.tcx().for_each_relevant_impl_treating_projections(
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 5e2e2d2495000..cfd9875e1c8fa 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -12,6 +12,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, DefIdSet, LocalDefId};
 use rustc_hir::Mutability;
 use rustc_metadata::creader::{CStore, LoadedMacro};
+use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Symbol};
@@ -314,9 +315,8 @@ pub(crate) fn build_impls(
     // * https://github.com/rust-lang/rust/pull/99917 — where the feature got used
     // * https://github.com/rust-lang/rust/issues/53487 — overall tracking issue for Error
     if tcx.has_attr(did, sym::rustc_has_incoherent_inherent_impls) {
-        use rustc_middle::ty::fast_reject::SimplifiedType::*;
         let type_ =
-            if tcx.is_trait(did) { TraitSimplifiedType(did) } else { AdtSimplifiedType(did) };
+            if tcx.is_trait(did) { SimplifiedType::Trait(did) } else { SimplifiedType::Adt(did) };
         for &did in tcx.incoherent_impls(type_) {
             build_impl(cx, did, attrs, ret);
         }
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index cfe62407fd35d..ddef165a05479 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1776,7 +1776,6 @@ impl PrimitiveType {
     }
 
     pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
-        use ty::fast_reject::SimplifiedType::*;
         use ty::{FloatTy, IntTy, UintTy};
         use PrimitiveType::*;
         static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
@@ -1784,38 +1783,38 @@ impl PrimitiveType {
         let single = |x| iter::once(x).collect();
         CELL.get_or_init(move || {
             map! {
-                Isize => single(IntSimplifiedType(IntTy::Isize)),
-                I8 => single(IntSimplifiedType(IntTy::I8)),
-                I16 => single(IntSimplifiedType(IntTy::I16)),
-                I32 => single(IntSimplifiedType(IntTy::I32)),
-                I64 => single(IntSimplifiedType(IntTy::I64)),
-                I128 => single(IntSimplifiedType(IntTy::I128)),
-                Usize => single(UintSimplifiedType(UintTy::Usize)),
-                U8 => single(UintSimplifiedType(UintTy::U8)),
-                U16 => single(UintSimplifiedType(UintTy::U16)),
-                U32 => single(UintSimplifiedType(UintTy::U32)),
-                U64 => single(UintSimplifiedType(UintTy::U64)),
-                U128 => single(UintSimplifiedType(UintTy::U128)),
-                F32 => single(FloatSimplifiedType(FloatTy::F32)),
-                F64 => single(FloatSimplifiedType(FloatTy::F64)),
-                Str => single(StrSimplifiedType),
-                Bool => single(BoolSimplifiedType),
-                Char => single(CharSimplifiedType),
-                Array => single(ArraySimplifiedType),
-                Slice => single(SliceSimplifiedType),
+                Isize => single(SimplifiedType::Int(IntTy::Isize)),
+                I8 => single(SimplifiedType::Int(IntTy::I8)),
+                I16 => single(SimplifiedType::Int(IntTy::I16)),
+                I32 => single(SimplifiedType::Int(IntTy::I32)),
+                I64 => single(SimplifiedType::Int(IntTy::I64)),
+                I128 => single(SimplifiedType::Int(IntTy::I128)),
+                Usize => single(SimplifiedType::Uint(UintTy::Usize)),
+                U8 => single(SimplifiedType::Uint(UintTy::U8)),
+                U16 => single(SimplifiedType::Uint(UintTy::U16)),
+                U32 => single(SimplifiedType::Uint(UintTy::U32)),
+                U64 => single(SimplifiedType::Uint(UintTy::U64)),
+                U128 => single(SimplifiedType::Uint(UintTy::U128)),
+                F32 => single(SimplifiedType::Float(FloatTy::F32)),
+                F64 => single(SimplifiedType::Float(FloatTy::F64)),
+                Str => single(SimplifiedType::Str),
+                Bool => single(SimplifiedType::Bool),
+                Char => single(SimplifiedType::Char),
+                Array => single(SimplifiedType::Array),
+                Slice => single(SimplifiedType::Slice),
                 // FIXME: If we ever add an inherent impl for tuples
                 // with different lengths, they won't show in rustdoc.
                 //
                 // Either manually update this arrayvec at this point
                 // or start with a more complex refactoring.
-                Tuple => [TupleSimplifiedType(1), TupleSimplifiedType(2), TupleSimplifiedType(3)].into(),
-                Unit => single(TupleSimplifiedType(0)),
-                RawPointer => [PtrSimplifiedType(Mutability::Not), PtrSimplifiedType(Mutability::Mut)].into_iter().collect(),
-                Reference => [RefSimplifiedType(Mutability::Not), RefSimplifiedType(Mutability::Mut)].into_iter().collect(),
+                Tuple => [SimplifiedType::Tuple(1), SimplifiedType::Tuple(2), SimplifiedType::Tuple(3)].into(),
+                Unit => single(SimplifiedType::Tuple(0)),
+                RawPointer => [SimplifiedType::Ptr(Mutability::Not), SimplifiedType::Ptr(Mutability::Mut)].into_iter().collect(),
+                Reference => [SimplifiedType::Ref(Mutability::Not), SimplifiedType::Ref(Mutability::Mut)].into_iter().collect(),
                 // FIXME: This will be wrong if we ever add inherent impls
                 // for function pointers.
-                Fn => single(FunctionSimplifiedType(1)),
-                Never => single(NeverSimplifiedType),
+                Fn => single(SimplifiedType::Function(1)),
+                Never => single(SimplifiedType::Never),
             }
         })
     }
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
index 94b56304bcab4..e4906944c8d0a 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
@@ -74,10 +74,10 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
     let lang_items = cx.tcx.lang_items();
     // This list isn't complete, but good enough for our current list of paths.
     let incoherent_impls = [
-        SimplifiedType::FloatSimplifiedType(FloatTy::F32),
-        SimplifiedType::FloatSimplifiedType(FloatTy::F64),
-        SimplifiedType::SliceSimplifiedType,
-        SimplifiedType::StrSimplifiedType,
+        SimplifiedType::Float(FloatTy::F32),
+        SimplifiedType::Float(FloatTy::F64),
+        SimplifiedType::Slice,
+        SimplifiedType::Str,
     ]
     .iter()
     .flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter().copied());
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 00e893fbdda8b..035511e891258 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -100,10 +100,7 @@ use rustc_middle::mir::ConstantKind;
 use rustc_middle::ty as rustc_ty;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::binding::BindingMode;
-use rustc_middle::ty::fast_reject::SimplifiedType::{
-    ArraySimplifiedType, BoolSimplifiedType, CharSimplifiedType, FloatSimplifiedType, IntSimplifiedType,
-    PtrSimplifiedType, SliceSimplifiedType, StrSimplifiedType, UintSimplifiedType,
-};
+use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::{
     BorrowKind, ClosureKind, FloatTy, IntTy, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, UintTy, UpvarCapture,
@@ -512,30 +509,30 @@ pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>
 
 fn find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator<Item = DefId> + 'tcx {
     let ty = match name {
-        "bool" => BoolSimplifiedType,
-        "char" => CharSimplifiedType,
-        "str" => StrSimplifiedType,
-        "array" => ArraySimplifiedType,
-        "slice" => SliceSimplifiedType,
+        "bool" => SimplifiedType::Bool,
+        "char" => SimplifiedType::Char,
+        "str" => SimplifiedType::Str,
+        "array" => SimplifiedType::Array,
+        "slice" => SimplifiedType::Slice,
         // FIXME: rustdoc documents these two using just `pointer`.
         //
         // Maybe this is something we should do here too.
-        "const_ptr" => PtrSimplifiedType(Mutability::Not),
-        "mut_ptr" => PtrSimplifiedType(Mutability::Mut),
-        "isize" => IntSimplifiedType(IntTy::Isize),
-        "i8" => IntSimplifiedType(IntTy::I8),
-        "i16" => IntSimplifiedType(IntTy::I16),
-        "i32" => IntSimplifiedType(IntTy::I32),
-        "i64" => IntSimplifiedType(IntTy::I64),
-        "i128" => IntSimplifiedType(IntTy::I128),
-        "usize" => UintSimplifiedType(UintTy::Usize),
-        "u8" => UintSimplifiedType(UintTy::U8),
-        "u16" => UintSimplifiedType(UintTy::U16),
-        "u32" => UintSimplifiedType(UintTy::U32),
-        "u64" => UintSimplifiedType(UintTy::U64),
-        "u128" => UintSimplifiedType(UintTy::U128),
-        "f32" => FloatSimplifiedType(FloatTy::F32),
-        "f64" => FloatSimplifiedType(FloatTy::F64),
+        "const_ptr" => SimplifiedType::Ptr(Mutability::Not),
+        "mut_ptr" => SimplifiedType::Ptr(Mutability::Mut),
+        "isize" => SimplifiedType::Int(IntTy::Isize),
+        "i8" => SimplifiedType::Int(IntTy::I8),
+        "i16" => SimplifiedType::Int(IntTy::I16),
+        "i32" => SimplifiedType::Int(IntTy::I32),
+        "i64" => SimplifiedType::Int(IntTy::I64),
+        "i128" => SimplifiedType::Int(IntTy::I128),
+        "usize" => SimplifiedType::Uint(UintTy::Usize),
+        "u8" => SimplifiedType::Uint(UintTy::U8),
+        "u16" => SimplifiedType::Uint(UintTy::U16),
+        "u32" => SimplifiedType::Uint(UintTy::U32),
+        "u64" => SimplifiedType::Uint(UintTy::U64),
+        "u128" => SimplifiedType::Uint(UintTy::U128),
+        "f32" => SimplifiedType::Float(FloatTy::F32),
+        "f64" => SimplifiedType::Float(FloatTy::F64),
         _ => return [].iter().copied(),
     };
 

From 2d99f40ec5ee10df8f7325e4e71d8249f8dacd92 Mon Sep 17 00:00:00 2001
From: lcnr <rust@lcnr.de>
Date: Tue, 18 Jul 2023 18:07:42 +0200
Subject: [PATCH 2/6] assembly: only consider blanket impls once

---
 .../src/solve/assembly/mod.rs                 | 273 +++++++++++++-----
 .../src/solve/project_goals.rs                |  12 +-
 .../src/solve/trait_goals.rs                  |   9 +-
 ...mble-normalizing-self-ty-impl-ambiguity.rs |  25 ++
 ...-normalizing-self-ty-impl-ambiguity.stderr |  23 ++
 5 files changed, 274 insertions(+), 68 deletions(-)
 create mode 100644 tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.rs
 create mode 100644 tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.stderr

diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 1e79899889551..73cf15ff94b59 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -10,9 +10,11 @@ use rustc_infer::traits::util::elaborate;
 use rustc_infer::traits::Reveal;
 use rustc_middle::traits::solve::inspect::CandidateKind;
 use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult};
-use rustc_middle::ty::fast_reject::TreatProjections;
-use rustc_middle::ty::TypeFoldable;
+use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams};
+use rustc_middle::ty::TypeVisitableExt;
 use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{fast_reject, TypeFoldable};
+use rustc_span::ErrorGuaranteed;
 use std::fmt::Debug;
 
 pub(super) mod structural_traits;
@@ -109,10 +111,10 @@ pub(super) trait GoalKind<'tcx>:
 
     fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId;
 
-    // Try equating an assumption predicate against a goal's predicate. If it
-    // holds, then execute the `then` callback, which should do any additional
-    // work, then produce a response (typically by executing
-    // [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]).
+    /// Try equating an assumption predicate against a goal's predicate. If it
+    /// holds, then execute the `then` callback, which should do any additional
+    /// work, then produce a response (typically by executing
+    /// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]).
     fn probe_and_match_goal_against_assumption(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
@@ -120,9 +122,9 @@ pub(super) trait GoalKind<'tcx>:
         then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
     ) -> QueryResult<'tcx>;
 
-    // Consider a clause, which consists of a "assumption" and some "requirements",
-    // to satisfy a goal. If the requirements hold, then attempt to satisfy our
-    // goal by equating it with the assumption.
+    /// Consider a clause, which consists of a "assumption" and some "requirements",
+    /// to satisfy a goal. If the requirements hold, then attempt to satisfy our
+    /// goal by equating it with the assumption.
     fn consider_implied_clause(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
@@ -149,9 +151,9 @@ pub(super) trait GoalKind<'tcx>:
         })
     }
 
-    // Consider a clause specifically for a `dyn Trait` self type. This requires
-    // additionally checking all of the supertraits and object bounds to hold,
-    // since they're not implied by the well-formedness of the object type.
+    /// Consider a clause specifically for a `dyn Trait` self type. This requires
+    /// additionally checking all of the supertraits and object bounds to hold,
+    /// since they're not implied by the well-formedness of the object type.
     fn consider_object_bound_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
@@ -182,96 +184,106 @@ pub(super) trait GoalKind<'tcx>:
         impl_def_id: DefId,
     ) -> QueryResult<'tcx>;
 
-    // A type implements an `auto trait` if its components do as well. These components
-    // are given by built-in rules from [`instantiate_constituent_tys_for_auto_trait`].
+    /// If the predicate contained an error, we want to avoid emitting unnecessary trait errors but
+    /// still want to emit errors for other trait goals. We have some special handling for this case.
+    ///
+    /// Trait goals always hold while projection goals never do. This is a bit arbitrary but prevents
+    /// incorrect normalization while hiding any trait errors.
+    fn consider_error_guaranteed_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        guar: ErrorGuaranteed,
+    ) -> QueryResult<'tcx>;
+
+    /// A type implements an `auto trait` if its components do as well. These components
+    /// are given by built-in rules from [`instantiate_constituent_tys_for_auto_trait`].
     fn consider_auto_trait_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
 
-    // A trait alias holds if the RHS traits and `where` clauses hold.
+    /// A trait alias holds if the RHS traits and `where` clauses hold.
     fn consider_trait_alias_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
 
-    // A type is `Copy` or `Clone` if its components are `Sized`. These components
-    // are given by built-in rules from [`instantiate_constituent_tys_for_sized_trait`].
+    /// A type is `Copy` or `Clone` if its components are `Sized`. These components
+    /// are given by built-in rules from [`instantiate_constituent_tys_for_sized_trait`].
     fn consider_builtin_sized_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
 
-    // A type is `Copy` or `Clone` if its components are `Copy` or `Clone`. These
-    // components are given by built-in rules from [`instantiate_constituent_tys_for_copy_clone_trait`].
+    /// A type is `Copy` or `Clone` if its components are `Copy` or `Clone`. These
+    /// components are given by built-in rules from [`instantiate_constituent_tys_for_copy_clone_trait`].
     fn consider_builtin_copy_clone_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
 
-    // A type is `PointerLike` if we can compute its layout, and that layout
-    // matches the layout of `usize`.
+    /// A type is `PointerLike` if we can compute its layout, and that layout
+    /// matches the layout of `usize`.
     fn consider_builtin_pointer_like_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
 
-    // A type is a `FnPtr` if it is of `FnPtr` type.
+    /// A type is a `FnPtr` if it is of `FnPtr` type.
     fn consider_builtin_fn_ptr_trait_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
 
-    // A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn<A>`
-    // family of traits where `A` is given by the signature of the type.
+    /// A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn<A>`
+    /// family of traits where `A` is given by the signature of the type.
     fn consider_builtin_fn_trait_candidates(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
         kind: ty::ClosureKind,
     ) -> QueryResult<'tcx>;
 
-    // `Tuple` is implemented if the `Self` type is a tuple.
+    /// `Tuple` is implemented if the `Self` type is a tuple.
     fn consider_builtin_tuple_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
 
-    // `Pointee` is always implemented.
-    //
-    // See the projection implementation for the `Metadata` types for all of
-    // the built-in types. For structs, the metadata type is given by the struct
-    // tail.
+    /// `Pointee` is always implemented.
+    ///
+    /// See the projection implementation for the `Metadata` types for all of
+    /// the built-in types. For structs, the metadata type is given by the struct
+    /// tail.
     fn consider_builtin_pointee_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
 
-    // A generator (that comes from an `async` desugaring) is known to implement
-    // `Future<Output = O>`, where `O` is given by the generator's return type
-    // that was computed during type-checking.
+    /// A generator (that comes from an `async` desugaring) is known to implement
+    /// `Future<Output = O>`, where `O` is given by the generator's return type
+    /// that was computed during type-checking.
     fn consider_builtin_future_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
 
-    // A generator (that doesn't come from an `async` desugaring) is known to
-    // implement `Generator<R, Yield = Y, Return = O>`, given the resume, yield,
-    // and return types of the generator computed during type-checking.
+    /// A generator (that doesn't come from an `async` desugaring) is known to
+    /// implement `Generator<R, Yield = Y, Return = O>`, given the resume, yield,
+    /// and return types of the generator computed during type-checking.
     fn consider_builtin_generator_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
 
-    // The most common forms of unsizing are array to slice, and concrete (Sized)
-    // type into a `dyn Trait`. ADTs and Tuples can also have their final field
-    // unsized if it's generic.
+    /// The most common forms of unsizing are array to slice, and concrete (Sized)
+    /// type into a `dyn Trait`. ADTs and Tuples can also have their final field
+    /// unsized if it's generic.
     fn consider_builtin_unsize_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
 
-    // `dyn Trait1` can be unsized to `dyn Trait2` if they are the same trait, or
-    // if `Trait2` is a (transitive) supertrait of `Trait2`.
+    /// `dyn Trait1` can be unsized to `dyn Trait2` if they are the same trait, or
+    /// if `Trait2` is a (transitive) supertrait of `Trait2`.
     fn consider_builtin_dyn_upcast_candidates(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
@@ -299,35 +311,60 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         goal: Goal<'tcx, G>,
     ) -> Vec<Candidate<'tcx>> {
         debug_assert_eq!(goal, self.resolve_vars_if_possible(goal));
+        if let Some(ambig) = self.self_ty_infer_ambiguity_hack(goal) {
+            return ambig;
+        }
+
+        let mut candidates = self.assemble_candidates_via_self_ty(goal);
+
+        self.assemble_blanket_impl_candidates(goal, &mut candidates);
+
+        self.assemble_param_env_candidates(goal, &mut candidates);
 
-        // HACK: `_: Trait` is ambiguous, because it may be satisfied via a builtin rule,
-        // object bound, alias bound, etc. We are unable to determine this until we can at
-        // least structurally resolve the type one layer.
-        if goal.predicate.self_ty().is_ty_var() {
-            return vec![Candidate {
+        candidates
+    }
+
+    fn self_ty_infer_ambiguity_hack<G: GoalKind<'tcx>>(
+        &mut self,
+        goal: Goal<'tcx, G>,
+    ) -> Option<Vec<Candidate<'tcx>>> {
+        goal.predicate.self_ty().is_ty_var().then(|| {
+            vec![Candidate {
                 source: CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity),
                 result: self
                     .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
                     .unwrap(),
-            }];
+            }]
+        })
+    }
+
+    /// Assemble candidates which apply to the self type. This only looks at candidate which
+    /// apply to the specific self type and ignores all others.
+    ///
+    /// Returns `None` if the self type is still ambiguous.
+    fn assemble_candidates_via_self_ty<G: GoalKind<'tcx>>(
+        &mut self,
+        goal: Goal<'tcx, G>,
+    ) -> Vec<Candidate<'tcx>> {
+        debug_assert_eq!(goal, self.resolve_vars_if_possible(goal));
+        if let Some(ambig) = self.self_ty_infer_ambiguity_hack(goal) {
+            return ambig;
         }
 
         let mut candidates = Vec::new();
 
-        self.assemble_candidates_after_normalizing_self_ty(goal, &mut candidates);
-
-        self.assemble_impl_candidates(goal, &mut candidates);
+        self.assemble_non_blanket_impl_candidates(goal, &mut candidates);
 
         self.assemble_builtin_impl_candidates(goal, &mut candidates);
 
-        self.assemble_param_env_candidates(goal, &mut candidates);
-
         self.assemble_alias_bound_candidates(goal, &mut candidates);
 
         self.assemble_object_bound_candidates(goal, &mut candidates);
 
         self.assemble_coherence_unknowable_candidates(goal, &mut candidates);
 
+        self.assemble_candidates_after_normalizing_self_ty(goal, &mut candidates);
+
         candidates
     }
 
@@ -385,7 +422,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
                         // have a `Normalized` candidate. This doesn't work as long as we
                         // use `CandidateSource` in winnowing.
                         let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty));
-                        Ok(ecx.assemble_and_evaluate_candidates(goal))
+                        Ok(ecx.assemble_candidates_via_self_ty(goal))
                     },
                 )
             });
@@ -396,22 +433,125 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
     }
 
     #[instrument(level = "debug", skip_all)]
-    fn assemble_impl_candidates<G: GoalKind<'tcx>>(
+    fn assemble_non_blanket_impl_candidates<G: GoalKind<'tcx>>(
         &mut self,
         goal: Goal<'tcx, G>,
         candidates: &mut Vec<Candidate<'tcx>>,
     ) {
         let tcx = self.tcx();
-        tcx.for_each_relevant_impl_treating_projections(
-            goal.predicate.trait_def_id(tcx),
-            goal.predicate.self_ty(),
-            TreatProjections::NextSolverLookup,
-            |impl_def_id| match G::consider_impl_candidate(self, goal, impl_def_id) {
+        let self_ty = goal.predicate.self_ty();
+        let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx));
+        let mut consider_impls_for_simplified_type = |simp| {
+            if let Some(impls_for_type) = trait_impls.non_blanket_impls().get(&simp) {
+                for &impl_def_id in impls_for_type {
+                    match G::consider_impl_candidate(self, goal, impl_def_id) {
+                        Ok(result) => candidates
+                            .push(Candidate { source: CandidateSource::Impl(impl_def_id), result }),
+                        Err(NoSolution) => (),
+                    }
+                }
+            }
+        };
+
+        match self_ty.kind() {
+            ty::Bool
+            | ty::Char
+            | ty::Int(_)
+            | ty::Uint(_)
+            | ty::Float(_)
+            | ty::Adt(_, _)
+            | ty::Foreign(_)
+            | ty::Str
+            | ty::Array(_, _)
+            | ty::Slice(_)
+            | ty::RawPtr(_)
+            | ty::Ref(_, _, _)
+            | ty::FnDef(_, _)
+            | ty::FnPtr(_)
+            | ty::Dynamic(_, _, _)
+            | ty::Closure(_, _)
+            | ty::Generator(_, _, _)
+            | ty::Never
+            | ty::Tuple(_) => {
+                let simp =
+                    fast_reject::simplify_type(tcx, self_ty, TreatParams::ForLookup).unwrap();
+                consider_impls_for_simplified_type(simp);
+            }
+
+            // HACK: For integer and float variables we have to manually look at all impls
+            // which have some integer or float as a self type.
+            ty::Infer(ty::IntVar(_)) => {
+                use ty::IntTy::*;
+                use ty::UintTy::*;
+                // This causes a compiler error if any new integer kinds are added.
+                let (I8 | I16 | I32 | I64 | I128 | Isize): ty::IntTy;
+                let (U8 | U16 | U32 | U64 | U128 | Usize): ty::UintTy;
+                let possible_integers = [
+                    // signed integers
+                    SimplifiedType::Int(I8),
+                    SimplifiedType::Int(I16),
+                    SimplifiedType::Int(I32),
+                    SimplifiedType::Int(I64),
+                    SimplifiedType::Int(I128),
+                    SimplifiedType::Int(Isize),
+                    // unsigned integers
+                    SimplifiedType::Uint(U8),
+                    SimplifiedType::Uint(U16),
+                    SimplifiedType::Uint(U32),
+                    SimplifiedType::Uint(U64),
+                    SimplifiedType::Uint(U128),
+                    SimplifiedType::Uint(Usize),
+                ];
+                for simp in possible_integers {
+                    consider_impls_for_simplified_type(simp);
+                }
+            }
+
+            ty::Infer(ty::FloatVar(_)) => {
+                // This causes a compiler error if any new float kinds are added.
+                let (ty::FloatTy::F32 | ty::FloatTy::F64);
+                let possible_floats = [
+                    SimplifiedType::Float(ty::FloatTy::F32),
+                    SimplifiedType::Float(ty::FloatTy::F64),
+                ];
+
+                for simp in possible_floats {
+                    consider_impls_for_simplified_type(simp);
+                }
+            }
+
+            // The only traits applying to aliases and placeholders are blanket impls.
+            //
+            // Impls which apply to an alias after normalization are handled by
+            // `assemble_candidates_after_normalizing_self_ty`.
+            ty::Alias(_, _) | ty::Placeholder(..) | ty::Error(_) => (),
+
+            // FIXME: These should ideally not exist as a self type. It would be nice for
+            // the builtin auto trait impls of generators should instead directly recurse
+            // into the witness.
+            ty::GeneratorWitness(_) | ty::GeneratorWitnessMIR(_, _) => (),
+
+            // These variants should not exist as a self type.
+            ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
+            | ty::Param(_)
+            | ty::Bound(_, _) => bug!("unexpected self type: {self_ty}"),
+        }
+    }
+
+    fn assemble_blanket_impl_candidates<G: GoalKind<'tcx>>(
+        &mut self,
+        goal: Goal<'tcx, G>,
+        candidates: &mut Vec<Candidate<'tcx>>,
+    ) {
+        let tcx = self.tcx();
+        let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx));
+        for &impl_def_id in trait_impls.blanket_impls() {
+            match G::consider_impl_candidate(self, goal, impl_def_id) {
                 Ok(result) => candidates
                     .push(Candidate { source: CandidateSource::Impl(impl_def_id), result }),
                 Err(NoSolution) => (),
-            },
-        );
+            }
+        }
     }
 
     #[instrument(level = "debug", skip_all)]
@@ -420,8 +560,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         goal: Goal<'tcx, G>,
         candidates: &mut Vec<Candidate<'tcx>>,
     ) {
-        let lang_items = self.tcx().lang_items();
-        let trait_def_id = goal.predicate.trait_def_id(self.tcx());
+        let tcx = self.tcx();
+        let lang_items = tcx.lang_items();
+        let trait_def_id = goal.predicate.trait_def_id(tcx);
 
         // N.B. When assembling built-in candidates for lang items that are also
         // `auto` traits, then the auto trait candidate that is assembled in
@@ -430,9 +571,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         // Instead of adding the logic here, it's a better idea to add it in
         // `EvalCtxt::disqualify_auto_trait_candidate_due_to_possible_impl` in
         // `solve::trait_goals` instead.
-        let result = if self.tcx().trait_is_auto(trait_def_id) {
+        let result = if let Err(guar) = goal.predicate.error_reported() {
+            G::consider_error_guaranteed_candidate(self, guar)
+        } else if tcx.trait_is_auto(trait_def_id) {
             G::consider_auto_trait_candidate(self, goal)
-        } else if self.tcx().trait_is_alias(trait_def_id) {
+        } else if tcx.trait_is_alias(trait_def_id) {
             G::consider_trait_alias_candidate(self, goal)
         } else if lang_items.sized_trait() == Some(trait_def_id) {
             G::consider_builtin_sized_candidate(self, goal)
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index d677fbdc7f425..222ed9939ba24 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -2,7 +2,6 @@ use crate::traits::specialization_graph;
 
 use super::assembly::{self, structural_traits};
 use super::EvalCtxt;
-use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::LangItem;
@@ -15,7 +14,7 @@ use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::ProjectionPredicate;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
-use rustc_span::{sym, DUMMY_SP};
+use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP};
 
 impl<'tcx> EvalCtxt<'_, 'tcx> {
     #[instrument(level = "debug", skip(self), ret)]
@@ -246,6 +245,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
         })
     }
 
+    /// Fail to normalize if the predicate contains an error, alternatively, we could normalize to `ty::Error`
+    /// and succeed. Can experiment with this to figure out what results in better error messages.
+    fn consider_error_guaranteed_candidate(
+        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        _guar: ErrorGuaranteed,
+    ) -> QueryResult<'tcx> {
+        Err(NoSolution)
+    }
+
     fn consider_auto_trait_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 29889614620dd..930e62d638831 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -11,7 +11,7 @@ use rustc_middle::traits::Reveal;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections};
 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
 use rustc_middle::ty::{TraitPredicate, TypeVisitableExt};
-use rustc_span::DUMMY_SP;
+use rustc_span::{ErrorGuaranteed, DUMMY_SP};
 
 impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     fn self_ty(self) -> Ty<'tcx> {
@@ -78,6 +78,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         })
     }
 
+    fn consider_error_guaranteed_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        _guar: ErrorGuaranteed,
+    ) -> QueryResult<'tcx> {
+        ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+    }
+
     fn probe_and_match_goal_against_assumption(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
diff --git a/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.rs b/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.rs
new file mode 100644
index 0000000000000..727ce84ba3591
--- /dev/null
+++ b/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.rs
@@ -0,0 +1,25 @@
+// compile-flags: -Ztrait-solver=next
+
+// Checks that we do not get ambiguity by considering an impl
+// multiple times if we're able to normalize the self type.
+trait Trait<'a> {}
+
+impl<'a, T: 'a> Trait<'a> for T {}
+
+fn impls_trait<'a, T: Trait<'a>>() {}
+
+trait Id {
+    type Assoc;
+}
+impl<T> Id for T {
+    type Assoc = T;
+}
+
+fn call<T>() {
+    impls_trait::<<T as Id>::Assoc>();
+}
+
+fn main() {
+    call::<()>();
+    impls_trait::<<<() as Id>::Assoc as Id>::Assoc>();
+}
diff --git a/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.stderr b/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.stderr
new file mode 100644
index 0000000000000..91b635b35eb6c
--- /dev/null
+++ b/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.stderr
@@ -0,0 +1,23 @@
+error[E0283]: type annotations needed: cannot satisfy `<T as Id>::Assoc: Trait<'_>`
+  --> $DIR/assemble-normalizing-self-ty-impl-ambiguity.rs:19:5
+   |
+LL |     impls_trait::<<T as Id>::Assoc>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: cannot satisfy `<T as Id>::Assoc: Trait<'_>`
+note: required by a bound in `impls_trait`
+  --> $DIR/assemble-normalizing-self-ty-impl-ambiguity.rs:9:23
+   |
+LL | fn impls_trait<'a, T: Trait<'a>>() {}
+   |                       ^^^^^^^^^ required by this bound in `impls_trait`
+
+error[E0282]: type annotations needed
+  --> $DIR/assemble-normalizing-self-ty-impl-ambiguity.rs:24:5
+   |
+LL |     impls_trait::<<<() as Id>::Assoc as Id>::Assoc>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_trait`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0282, E0283.
+For more information about an error, try `rustc --explain E0282`.

From aa28b77b5a362a70e4c1e4f99047f903f735954d Mon Sep 17 00:00:00 2001
From: lcnr <rust@lcnr.de>
Date: Tue, 18 Jul 2023 18:15:14 +0200
Subject: [PATCH 3/6] add FIXME

---
 compiler/rustc_middle/src/ty/fast_reject.rs | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index deb4dcf1f760a..668aa4521c101 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -62,6 +62,9 @@ pub enum TreatParams {
     /// correct mode for *lookup*, as during candidate selection.
     ///
     /// N.B. during deep rejection, this acts identically to `ForLookup`.
+    ///
+    /// FIXME(-Ztrait-solver=next): Remove this variant and cleanup
+    /// the code.
     NextSolverLookup,
 }
 

From 7c97a76b76120bd982762a982d4254ece32c43dc Mon Sep 17 00:00:00 2001
From: lcnr <rust@lcnr.de>
Date: Tue, 18 Jul 2023 18:18:32 +0200
Subject: [PATCH 4/6] re-add comment

---
 compiler/rustc_trait_selection/src/solve/assembly/mod.rs | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 73cf15ff94b59..68e931aac8c12 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -324,6 +324,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         candidates
     }
 
+    /// HACK: `_: Trait` is ambiguous, because it may be satisfied via a builtin rule,
+    /// object bound, alias bound, etc. We are unable to determine this until we can at
+    /// least structurally resolve the type one layer.
+    ///
+    /// It would also require us to consider all impls of the trait, which is both pretty
+    /// bad for perf and would also constrain the self type if there is just a single impl.
     fn self_ty_infer_ambiguity_hack<G: GoalKind<'tcx>>(
         &mut self,
         goal: Goal<'tcx, G>,

From 2062f2ca8261b521caa9c34c195bf472dcb59e98 Mon Sep 17 00:00:00 2001
From: lcnr <rust@lcnr.de>
Date: Thu, 20 Jul 2023 10:40:59 +0200
Subject: [PATCH 5/6] review

---
 .../src/solve/assembly/mod.rs                 |  8 +++----
 ...mble-normalizing-self-ty-impl-ambiguity.rs |  2 ++
 ...-normalizing-self-ty-impl-ambiguity.stderr | 23 -------------------
 .../dont-normalize-proj-with-error.rs         | 22 ++++++++++++++++++
 .../dont-normalize-proj-with-error.stderr     |  9 ++++++++
 5 files changed, 37 insertions(+), 27 deletions(-)
 delete mode 100644 tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.stderr
 create mode 100644 tests/ui/traits/new-solver/dont-normalize-proj-with-error.rs
 create mode 100644 tests/ui/traits/new-solver/dont-normalize-proj-with-error.stderr

diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 68e931aac8c12..b661ff481a0a8 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -311,7 +311,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         goal: Goal<'tcx, G>,
     ) -> Vec<Candidate<'tcx>> {
         debug_assert_eq!(goal, self.resolve_vars_if_possible(goal));
-        if let Some(ambig) = self.self_ty_infer_ambiguity_hack(goal) {
+        if let Some(ambig) = self.assemble_self_ty_infer_ambiguity_response(goal) {
             return ambig;
         }
 
@@ -324,13 +324,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         candidates
     }
 
-    /// HACK: `_: Trait` is ambiguous, because it may be satisfied via a builtin rule,
+    /// `?0: Trait` is ambiguous, because it may be satisfied via a builtin rule,
     /// object bound, alias bound, etc. We are unable to determine this until we can at
     /// least structurally resolve the type one layer.
     ///
     /// It would also require us to consider all impls of the trait, which is both pretty
     /// bad for perf and would also constrain the self type if there is just a single impl.
-    fn self_ty_infer_ambiguity_hack<G: GoalKind<'tcx>>(
+    fn assemble_self_ty_infer_ambiguity_response<G: GoalKind<'tcx>>(
         &mut self,
         goal: Goal<'tcx, G>,
     ) -> Option<Vec<Candidate<'tcx>>> {
@@ -353,7 +353,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         goal: Goal<'tcx, G>,
     ) -> Vec<Candidate<'tcx>> {
         debug_assert_eq!(goal, self.resolve_vars_if_possible(goal));
-        if let Some(ambig) = self.self_ty_infer_ambiguity_hack(goal) {
+        if let Some(ambig) = self.assemble_self_ty_infer_ambiguity_response(goal) {
             return ambig;
         }
 
diff --git a/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.rs b/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.rs
index 727ce84ba3591..826e8c1e0b131 100644
--- a/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.rs
+++ b/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.rs
@@ -1,7 +1,9 @@
 // compile-flags: -Ztrait-solver=next
+// check-pass
 
 // Checks that we do not get ambiguity by considering an impl
 // multiple times if we're able to normalize the self type.
+
 trait Trait<'a> {}
 
 impl<'a, T: 'a> Trait<'a> for T {}
diff --git a/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.stderr b/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.stderr
deleted file mode 100644
index 91b635b35eb6c..0000000000000
--- a/tests/ui/traits/new-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-error[E0283]: type annotations needed: cannot satisfy `<T as Id>::Assoc: Trait<'_>`
-  --> $DIR/assemble-normalizing-self-ty-impl-ambiguity.rs:19:5
-   |
-LL |     impls_trait::<<T as Id>::Assoc>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: cannot satisfy `<T as Id>::Assoc: Trait<'_>`
-note: required by a bound in `impls_trait`
-  --> $DIR/assemble-normalizing-self-ty-impl-ambiguity.rs:9:23
-   |
-LL | fn impls_trait<'a, T: Trait<'a>>() {}
-   |                       ^^^^^^^^^ required by this bound in `impls_trait`
-
-error[E0282]: type annotations needed
-  --> $DIR/assemble-normalizing-self-ty-impl-ambiguity.rs:24:5
-   |
-LL |     impls_trait::<<<() as Id>::Assoc as Id>::Assoc>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_trait`
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0282, E0283.
-For more information about an error, try `rustc --explain E0282`.
diff --git a/tests/ui/traits/new-solver/dont-normalize-proj-with-error.rs b/tests/ui/traits/new-solver/dont-normalize-proj-with-error.rs
new file mode 100644
index 0000000000000..19a6fa990ff14
--- /dev/null
+++ b/tests/ui/traits/new-solver/dont-normalize-proj-with-error.rs
@@ -0,0 +1,22 @@
+// compile-flags: -Ztrait-solver=next
+
+// Test that we don't incorrectly leak unconstrained inference variables
+// if the projection contained an error. This caused an ICE in writeback.
+
+trait Mirror {
+    type Assoc: ?Sized;
+}
+
+struct Wrapper<T: ?Sized>(T);
+impl<T: ?Sized> Mirror for Wrapper<T> {
+    type Assoc = T;
+}
+
+fn mirror<W: Mirror>(_: W) -> Box<W::Assoc> { todo!() }
+
+fn type_error() -> TypeError { todo!() }
+//~^ ERROR cannot find type `TypeError` in this scope
+
+fn main() {
+    let x = mirror(type_error());
+}
diff --git a/tests/ui/traits/new-solver/dont-normalize-proj-with-error.stderr b/tests/ui/traits/new-solver/dont-normalize-proj-with-error.stderr
new file mode 100644
index 0000000000000..5a7459ec1fdee
--- /dev/null
+++ b/tests/ui/traits/new-solver/dont-normalize-proj-with-error.stderr
@@ -0,0 +1,9 @@
+error[E0412]: cannot find type `TypeError` in this scope
+  --> $DIR/dont-normalize-proj-with-error.rs:17:20
+   |
+LL | fn type_error() -> TypeError { todo!() }
+   |                    ^^^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.

From 5c75bc5317b4326bdc3d8a4708d0602bd0ec219d Mon Sep 17 00:00:00 2001
From: lcnr <rust@lcnr.de>
Date: Thu, 20 Jul 2023 11:26:22 +0200
Subject: [PATCH 6/6] update doc comments

---
 .../src/solve/assembly/mod.rs                 | 27 ++++++++++++-------
 1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index b661ff481a0a8..6920e790e71ae 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -184,18 +184,21 @@ pub(super) trait GoalKind<'tcx>:
         impl_def_id: DefId,
     ) -> QueryResult<'tcx>;
 
-    /// If the predicate contained an error, we want to avoid emitting unnecessary trait errors but
-    /// still want to emit errors for other trait goals. We have some special handling for this case.
+    /// If the predicate contained an error, we want to avoid emitting unnecessary trait
+    /// errors but still want to emit errors for other trait goals. We have some special
+    /// handling for this case.
     ///
-    /// Trait goals always hold while projection goals never do. This is a bit arbitrary but prevents
-    /// incorrect normalization while hiding any trait errors.
+    /// Trait goals always hold while projection goals never do. This is a bit arbitrary
+    /// but prevents incorrect normalization while hiding any trait errors.
     fn consider_error_guaranteed_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         guar: ErrorGuaranteed,
     ) -> QueryResult<'tcx>;
 
-    /// A type implements an `auto trait` if its components do as well. These components
-    /// are given by built-in rules from [`instantiate_constituent_tys_for_auto_trait`].
+    /// A type implements an `auto trait` if its components do as well.
+    ///
+    /// These components are given by built-in rules from
+    /// [`structural_traits::instantiate_constituent_tys_for_auto_trait`].
     fn consider_auto_trait_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
@@ -207,15 +210,19 @@ pub(super) trait GoalKind<'tcx>:
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
 
-    /// A type is `Copy` or `Clone` if its components are `Sized`. These components
-    /// are given by built-in rules from [`instantiate_constituent_tys_for_sized_trait`].
+    /// A type is `Copy` or `Clone` if its components are `Sized`.
+    ///
+    /// These components are given by built-in rules from
+    /// [`structural_traits::instantiate_constituent_tys_for_sized_trait`].
     fn consider_builtin_sized_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
 
-    /// A type is `Copy` or `Clone` if its components are `Copy` or `Clone`. These
-    /// components are given by built-in rules from [`instantiate_constituent_tys_for_copy_clone_trait`].
+    /// A type is `Copy` or `Clone` if its components are `Copy` or `Clone`.
+    ///
+    /// These components are given by built-in rules from
+    /// [`structural_traits::instantiate_constituent_tys_for_copy_clone_trait`].
     fn consider_builtin_copy_clone_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,