about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs5
-rw-r--r--compiler/rustc_errors/src/diagnostic_impls.rs6
-rw-r--r--compiler/rustc_hir/src/hir.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs26
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs20
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs43
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs73
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs105
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs15
-rw-r--r--compiler/rustc_type_ir/src/interner.rs17
-rw-r--r--compiler/rustc_type_ir/src/ir_print.rs5
-rw-r--r--compiler/rustc_type_ir/src/predicate.rs2
-rw-r--r--compiler/rustc_type_ir/src/ty_kind.rs81
-rw-r--r--src/doc/rustc/src/linker-plugin-lto.md3
-rw-r--r--src/rustdoc-json-types/lib.rs14
-rw-r--r--tests/codegen/float/f128.rs194
-rw-r--r--tests/codegen/float/f16.rs202
-rw-r--r--tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr6
-rw-r--r--tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr9
-rw-r--r--tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr36
-rw-r--r--tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr12
-rw-r--r--tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs2
-rw-r--r--tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr41
-rw-r--r--tests/ui/traits/next-solver/cycles/mixed-cycles-1.rs2
-rw-r--r--tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr39
-rw-r--r--tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs2
-rw-r--r--tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr25
-rw-r--r--tests/ui/traits/next-solver/diagnostics/ambiguous-fail.rs21
-rw-r--r--tests/ui/traits/next-solver/diagnostics/ambiguous-fail.stderr12
-rw-r--r--tests/ui/traits/next-solver/diagnostics/ambiguous-pass.rs21
-rw-r--r--tests/ui/traits/next-solver/diagnostics/ambiguous-pass.stderr12
-rw-r--r--tests/ui/traits/next-solver/overflow/exponential-trait-goals.rs2
-rw-r--r--tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr9
-rw-r--r--tests/ui/traits/next-solver/overflow/global-cache.stderr9
34 files changed, 725 insertions, 348 deletions
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index fdeccb90700..9fd6eb8edab 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -247,7 +247,10 @@ pub trait BuilderMethods<'a, 'tcx>:
         } else {
             (in_ty, dest_ty)
         };
-        assert!(matches!(self.cx().type_kind(float_ty), TypeKind::Float | TypeKind::Double));
+        assert!(matches!(
+            self.cx().type_kind(float_ty),
+            TypeKind::Half | TypeKind::Float | TypeKind::Double | TypeKind::FP128
+        ));
         assert_eq!(self.cx().type_kind(int_ty), TypeKind::Integer);
 
         if let Some(false) = self.cx().sess().opts.unstable_opts.saturating_float_casts {
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index d9add1c9b3b..4bf7dccab92 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -112,6 +112,12 @@ impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::UnevaluatedConst
     }
 }
 
+impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::FnSig<I> {
+    fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
+        format!("{self:?}").into_diag_arg()
+    }
+}
+
 into_diag_arg_for_number!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize);
 
 impl IntoDiagArg for bool {
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 6e4cef068c5..904abe45a23 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -3191,7 +3191,7 @@ pub enum Unsafety {
 }
 
 impl Unsafety {
-    pub fn prefix_str(&self) -> &'static str {
+    pub fn prefix_str(self) -> &'static str {
         match self {
             Self::Unsafe => "unsafe ",
             Self::Normal => "",
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index d7e185dd5e1..6f70231337a 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -92,7 +92,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type DefiningOpaqueTypes = &'tcx ty::List<LocalDefId>;
     type AdtDef = ty::AdtDef<'tcx>;
     type GenericArgs = ty::GenericArgsRef<'tcx>;
-    type GenericArgsSlice = &'tcx [ty::GenericArg<'tcx>];
+    type OwnItemArgs = &'tcx [ty::GenericArg<'tcx>];
     type GenericArg = ty::GenericArg<'tcx>;
 
     type Term = ty::Term<'tcx>;
@@ -103,6 +103,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type CanonicalVars = CanonicalVarInfos<'tcx>;
     type Ty = Ty<'tcx>;
     type Tys = &'tcx List<Ty<'tcx>>;
+    type FnInputTys = &'tcx [Ty<'tcx>];
     type ParamTy = ParamTy;
     type BoundTy = ty::BoundTy;
     type PlaceholderTy = ty::PlaceholderType;
@@ -113,21 +114,24 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type AllocId = crate::mir::interpret::AllocId;
 
     type Pat = Pattern<'tcx>;
+    type Unsafety = hir::Unsafety;
+    type Abi = abi::Abi;
+
     type Const = ty::Const<'tcx>;
     type AliasConst = ty::UnevaluatedConst<'tcx>;
     type PlaceholderConst = ty::PlaceholderConst;
     type ParamConst = ty::ParamConst;
     type BoundConst = ty::BoundVar;
     type ValueConst = ty::ValTree<'tcx>;
-
     type ExprConst = ty::Expr<'tcx>;
+
     type Region = Region<'tcx>;
     type EarlyParamRegion = ty::EarlyParamRegion;
     type LateParamRegion = ty::LateParamRegion;
     type BoundRegion = ty::BoundRegion;
     type InferRegion = ty::RegionVid;
-
     type PlaceholderRegion = ty::PlaceholderRegion;
+
     type Predicate = Predicate<'tcx>;
     type TraitPredicate = ty::TraitPredicate<'tcx>;
     type RegionOutlivesPredicate = ty::RegionOutlivesPredicate<'tcx>;
@@ -135,10 +139,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type ProjectionPredicate = ty::ProjectionPredicate<'tcx>;
     type NormalizesTo = ty::NormalizesTo<'tcx>;
     type SubtypePredicate = ty::SubtypePredicate<'tcx>;
+
     type CoercePredicate = ty::CoercePredicate<'tcx>;
     type ClosureKind = ty::ClosureKind;
 
     type Clauses = ty::Clauses<'tcx>;
+
     fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars {
         self.mk_canonical_var_infos(infos)
     }
@@ -191,7 +197,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         self,
         def_id: Self::DefId,
         args: Self::GenericArgs,
-    ) -> (rustc_type_ir::TraitRef<Self>, Self::GenericArgsSlice) {
+    ) -> (rustc_type_ir::TraitRef<Self>, Self::OwnItemArgs) {
         assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst);
         let trait_def_id = self.parent(def_id);
         assert_matches!(self.def_kind(trait_def_id), DefKind::Trait);
@@ -223,6 +229,18 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     }
 }
 
+impl<'tcx> rustc_type_ir::inherent::Abi<TyCtxt<'tcx>> for abi::Abi {
+    fn is_rust(self) -> bool {
+        matches!(self, abi::Abi::Rust)
+    }
+}
+
+impl<'tcx> rustc_type_ir::inherent::Unsafety<TyCtxt<'tcx>> for hir::Unsafety {
+    fn prefix_str(self) -> &'static str {
+        self.prefix_str()
+    }
+}
+
 type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>;
 
 pub struct CtxtInterners<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 3577db7234d..d9043d43cd7 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -3034,6 +3034,16 @@ forward_display_to_print! {
 define_print! {
     (self, cx):
 
+    ty::FnSig<'tcx> {
+        p!(write("{}", self.unsafety.prefix_str()));
+
+        if self.abi != Abi::Rust {
+            p!(write("extern {} ", self.abi));
+        }
+
+        p!("fn", pretty_fn_sig(self.inputs(), self.c_variadic, self.output()));
+    }
+
     ty::TraitRef<'tcx> {
         p!(write("<{} as {}>", self.self_ty(), self.print_only_trait_path()))
     }
@@ -3169,16 +3179,6 @@ define_print_and_forward_display! {
         p!("{{", comma_sep(self.iter()), "}}")
     }
 
-    ty::FnSig<'tcx> {
-        p!(write("{}", self.unsafety.prefix_str()));
-
-        if self.abi != Abi::Rust {
-            p!(write("extern {} ", self.abi));
-        }
-
-        p!("fn", pretty_fn_sig(self.inputs(), self.c_variadic, self.output()));
-    }
-
     TraitRefPrintOnlyTraitPath<'tcx> {
         p!(print_def_path(self.0.def_id, self.0.args));
     }
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 7523cd15320..eed11422a44 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -83,49 +83,6 @@ impl fmt::Debug for ty::LateParamRegion {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::FnSig<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        WithInfcx::with_no_infcx(self).fmt(f)
-    }
-}
-impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::FnSig<'tcx> {
-    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
-        this: WithInfcx<'_, Infcx, &Self>,
-        f: &mut core::fmt::Formatter<'_>,
-    ) -> core::fmt::Result {
-        let sig = this.data;
-        let ty::FnSig { inputs_and_output: _, c_variadic, unsafety, abi } = sig;
-
-        write!(f, "{}", unsafety.prefix_str())?;
-        match abi {
-            rustc_target::spec::abi::Abi::Rust => (),
-            abi => write!(f, "extern \"{abi:?}\" ")?,
-        };
-
-        write!(f, "fn(")?;
-        let inputs = sig.inputs();
-        match inputs.len() {
-            0 if *c_variadic => write!(f, "...)")?,
-            0 => write!(f, ")")?,
-            _ => {
-                for ty in &sig.inputs()[0..(sig.inputs().len() - 1)] {
-                    write!(f, "{:?}, ", &this.wrap(ty))?;
-                }
-                write!(f, "{:?}", &this.wrap(sig.inputs().last().unwrap()))?;
-                if *c_variadic {
-                    write!(f, "...")?;
-                }
-                write!(f, ")")?;
-            }
-        }
-
-        match sig.output().kind() {
-            ty::Tuple(list) if list.is_empty() => Ok(()),
-            _ => write!(f, " -> {:?}", &this.wrap(sig.output())),
-        }
-    }
-}
-
 impl<'tcx> ty::DebugWithInfcx<TyCtxt<'tcx>> for Ty<'tcx> {
     fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
         this: WithInfcx<'_, Infcx, &Self>,
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 74b03d6db66..9dbcd938e6e 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -39,6 +39,7 @@ use super::GenericParamDefKind;
 pub type TyKind<'tcx> = ir::TyKind<TyCtxt<'tcx>>;
 pub type TypeAndMut<'tcx> = ir::TypeAndMut<TyCtxt<'tcx>>;
 pub type AliasTy<'tcx> = ir::AliasTy<TyCtxt<'tcx>>;
+pub type FnSig<'tcx> = ir::FnSig<TyCtxt<'tcx>>;
 
 pub trait Article {
     fn article(&self) -> &'static str;
@@ -985,14 +986,6 @@ impl<'tcx, T> Binder<'tcx, T> {
         Binder { value: &self.value, bound_vars: self.bound_vars }
     }
 
-    pub fn map_bound_ref_unchecked<F, U>(&self, f: F) -> Binder<'tcx, U>
-    where
-        F: FnOnce(&T) -> U,
-    {
-        let value = f(&self.value);
-        Binder { value, bound_vars: self.bound_vars }
-    }
-
     pub fn map_bound_ref<F, U: TypeVisitable<TyCtxt<'tcx>>>(&self, f: F) -> Binder<'tcx, U>
     where
         F: FnOnce(&T) -> U,
@@ -1109,73 +1102,37 @@ pub struct GenSig<'tcx> {
     pub return_ty: Ty<'tcx>,
 }
 
-/// Signature of a function type, which we have arbitrarily
-/// decided to use to refer to the input/output types.
-///
-/// - `inputs`: is the list of arguments and their modes.
-/// - `output`: is the return type.
-/// - `c_variadic`: indicates whether this is a C-variadic function.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
-pub struct FnSig<'tcx> {
-    pub inputs_and_output: &'tcx List<Ty<'tcx>>,
-    pub c_variadic: bool,
-    pub unsafety: hir::Unsafety,
-    pub abi: abi::Abi,
-}
-
-impl<'tcx> FnSig<'tcx> {
-    pub fn inputs(&self) -> &'tcx [Ty<'tcx>] {
-        &self.inputs_and_output[..self.inputs_and_output.len() - 1]
-    }
-
-    pub fn output(&self) -> Ty<'tcx> {
-        self.inputs_and_output[self.inputs_and_output.len() - 1]
-    }
-
-    // Creates a minimal `FnSig` to be used when encountering a `TyKind::Error` in a fallible
-    // method.
-    fn fake() -> FnSig<'tcx> {
-        FnSig {
-            inputs_and_output: List::empty(),
-            c_variadic: false,
-            unsafety: hir::Unsafety::Normal,
-            abi: abi::Abi::Rust,
-        }
-    }
-}
-
-impl<'tcx> IntoDiagArg for FnSig<'tcx> {
-    fn into_diag_arg(self) -> DiagArgValue {
-        self.to_string().into_diag_arg()
-    }
-}
-
 pub type PolyFnSig<'tcx> = Binder<'tcx, FnSig<'tcx>>;
 
 impl<'tcx> PolyFnSig<'tcx> {
     #[inline]
     pub fn inputs(&self) -> Binder<'tcx, &'tcx [Ty<'tcx>]> {
-        self.map_bound_ref_unchecked(|fn_sig| fn_sig.inputs())
+        self.map_bound_ref(|fn_sig| fn_sig.inputs())
     }
+
     #[inline]
     #[track_caller]
     pub fn input(&self, index: usize) -> ty::Binder<'tcx, Ty<'tcx>> {
         self.map_bound_ref(|fn_sig| fn_sig.inputs()[index])
     }
+
     pub fn inputs_and_output(&self) -> ty::Binder<'tcx, &'tcx List<Ty<'tcx>>> {
         self.map_bound_ref(|fn_sig| fn_sig.inputs_and_output)
     }
+
     #[inline]
     pub fn output(&self) -> ty::Binder<'tcx, Ty<'tcx>> {
         self.map_bound_ref(|fn_sig| fn_sig.output())
     }
+
     pub fn c_variadic(&self) -> bool {
         self.skip_binder().c_variadic
     }
+
     pub fn unsafety(&self) -> hir::Unsafety {
         self.skip_binder().unsafety
     }
+
     pub fn abi(&self) -> abi::Abi {
         self.skip_binder().abi
     }
@@ -2031,7 +1988,12 @@ impl<'tcx> Ty<'tcx> {
             FnPtr(f) => *f,
             Error(_) => {
                 // ignore errors (#54954)
-                ty::Binder::dummy(FnSig::fake())
+                ty::Binder::dummy(ty::FnSig {
+                    inputs_and_output: ty::List::empty(),
+                    c_variadic: false,
+                    unsafety: hir::Unsafety::Normal,
+                    abi: abi::Abi::Rust,
+                })
             }
             Closure(..) => bug!(
                 "to get the signature of a closure, use `args.as_closure().sig()` not `fn_sig()`",
@@ -2624,6 +2586,13 @@ impl<'tcx> Ty<'tcx> {
     }
 }
 
+impl<'tcx> rustc_type_ir::inherent::Tys<TyCtxt<'tcx>> for &'tcx ty::List<Ty<'tcx>> {
+    fn split_inputs_and_output(self) -> (&'tcx [Ty<'tcx>], Ty<'tcx>) {
+        let (output, inputs) = self.split_last().unwrap();
+        (inputs, *output)
+    }
+}
+
 /// Extra information about why we ended up with a particular variance.
 /// This is only used to add more information to error messages, and
 /// has no effect on soundness. While choosing the 'wrong' `VarianceDiagInfo`
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index 3323f1bbf39..3379c1d51a8 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -244,16 +244,23 @@ fn fulfillment_error_for_no_solution<'tcx>(
 
 fn fulfillment_error_for_stalled<'tcx>(
     infcx: &InferCtxt<'tcx>,
-    obligation: PredicateObligation<'tcx>,
+    root_obligation: PredicateObligation<'tcx>,
 ) -> FulfillmentError<'tcx> {
-    let code = infcx.probe(|_| {
-        match infcx.evaluate_root_goal(obligation.clone().into(), GenerateProofTree::Never).0 {
+    let (code, refine_obligation) = infcx.probe(|_| {
+        match infcx.evaluate_root_goal(root_obligation.clone().into(), GenerateProofTree::Never).0 {
             Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => {
-                FulfillmentErrorCode::Ambiguity { overflow: None }
-            }
-            Ok((_, Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit }))) => {
-                FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) }
+                (FulfillmentErrorCode::Ambiguity { overflow: None }, true)
             }
+            Ok((_, Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit }))) => (
+                FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) },
+                // Don't look into overflows because we treat overflows weirdly anyways.
+                // In `instantiate_response_discarding_overflow` we set `has_changed = false`,
+                // recomputing the goal again during `find_best_leaf_obligation` may apply
+                // inference guidance that makes other goals go from ambig -> pass, for example.
+                //
+                // FIXME: We should probably just look into overflows here.
+                false,
+            ),
             Ok((_, Certainty::Yes)) => {
                 bug!("did not expect successful goal when collecting ambiguity errors")
             }
@@ -264,9 +271,13 @@ fn fulfillment_error_for_stalled<'tcx>(
     });
 
     FulfillmentError {
-        obligation: find_best_leaf_obligation(infcx, &obligation, true),
+        obligation: if refine_obligation {
+            find_best_leaf_obligation(infcx, &root_obligation, true)
+        } else {
+            root_obligation.clone()
+        },
         code,
-        root_obligation: obligation,
+        root_obligation,
     }
 }
 
@@ -302,41 +313,50 @@ impl<'tcx> BestObligation<'tcx> {
         res
     }
 
-    /// Filter out the candidates that aren't either error or ambiguous (depending
-    /// on what we are looking for), and also throw out candidates that have no
-    /// failing WC (or higher-ranked obligations, for which there should only be
-    /// one candidate anyways -- but I digress). This most likely means that the
-    /// goal just didn't unify at all, e.g. a param candidate with an alias in it.
+    /// Filter out the candidates that aren't interesting to visit for the
+    /// purposes of reporting errors. For ambiguities, we only consider
+    /// candidates that may hold. For errors, we only consider candidates that
+    /// *don't* hold and which have impl-where clauses that also don't hold.
     fn non_trivial_candidates<'a>(
         &self,
         goal: &'a InspectGoal<'a, 'tcx>,
     ) -> Vec<InspectCandidate<'a, 'tcx>> {
-        let mut candidates = goal
-            .candidates()
-            .into_iter()
-            .filter(|candidate| match self.consider_ambiguities {
-                true => matches!(candidate.result(), Ok(Certainty::Maybe(_))),
-                false => matches!(candidate.result(), Err(_)),
-            })
-            .collect::<Vec<_>>();
-
-        // If we have >1 candidate, one may still be due to "boring" reasons, like
-        // an alias-relate that failed to hold when deeply evaluated. We really
-        // don't care about reasons like this.
-        if candidates.len() > 1 {
-            candidates.retain(|candidate| {
-                goal.infcx().probe(|_| {
-                    candidate.instantiate_nested_goals(self.span()).iter().any(|nested_goal| {
-                        matches!(
-                            nested_goal.source(),
-                            GoalSource::ImplWhereBound | GoalSource::InstantiateHigherRanked
-                        ) && match self.consider_ambiguities {
-                            true => matches!(nested_goal.result(), Ok(Certainty::Maybe(_))),
-                            false => matches!(nested_goal.result(), Err(_)),
-                        }
-                    })
-                })
-            });
+        let mut candidates = goal.candidates();
+        match self.consider_ambiguities {
+            true => {
+                // If we have an ambiguous obligation, we must consider *all* candidates
+                // that hold, or else we may guide inference causing other goals to go
+                // from ambig -> pass/fail.
+                candidates.retain(|candidate| candidate.result().is_ok());
+            }
+            false => {
+                // If we have >1 candidate, one may still be due to "boring" reasons, like
+                // an alias-relate that failed to hold when deeply evaluated. We really
+                // don't care about reasons like this.
+                if candidates.len() > 1 {
+                    candidates.retain(|candidate| {
+                        goal.infcx().probe(|_| {
+                            candidate.instantiate_nested_goals(self.span()).iter().any(
+                                |nested_goal| {
+                                    matches!(
+                                        nested_goal.source(),
+                                        GoalSource::ImplWhereBound
+                                            | GoalSource::InstantiateHigherRanked
+                                    ) && match self.consider_ambiguities {
+                                        true => {
+                                            matches!(
+                                                nested_goal.result(),
+                                                Ok(Certainty::Maybe(MaybeCause::Ambiguity))
+                                            )
+                                        }
+                                        false => matches!(nested_goal.result(), Err(_)),
+                                    }
+                                },
+                            )
+                        })
+                    });
+                }
+            }
         }
 
         candidates
@@ -401,7 +421,10 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
 
             // Skip nested goals that aren't the *reason* for our goal's failure.
             match self.consider_ambiguities {
-                true if matches!(nested_goal.result(), Ok(Certainty::Maybe(_))) => {}
+                true if matches!(
+                    nested_goal.result(),
+                    Ok(Certainty::Maybe(MaybeCause::Ambiguity))
+                ) => {}
                 false if matches!(nested_goal.result(), Err(_)) => {}
                 _ => continue,
             }
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index 92b1e08ab0a..484f6c31258 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -26,6 +26,21 @@ pub trait Ty<I: Interner<Ty = Self>>:
     fn new_alias(interner: I, kind: AliasTyKind, alias_ty: AliasTy<I>) -> Self;
 }
 
+pub trait Tys<I: Interner<Tys = Self>>:
+    Copy + Debug + Hash + Eq + IntoIterator<Item = I::Ty> + Deref<Target: Deref<Target = [I::Ty]>>
+{
+    fn split_inputs_and_output(self) -> (I::FnInputTys, I::Ty);
+}
+
+pub trait Abi<I: Interner<Abi = Self>>: Copy + Debug + Hash + Eq {
+    /// Whether this ABI is `extern "Rust"`.
+    fn is_rust(self) -> bool;
+}
+
+pub trait Unsafety<I: Interner<Unsafety = Self>>: Copy + Debug + Hash + Eq {
+    fn prefix_str(self) -> &'static str;
+}
+
 pub trait Region<I: Interner<Region = Self>>:
     Copy + DebugWithInfcx<I> + Hash + Eq + Into<I::GenericArg> + IntoKind<Kind = RegionKind<I>> + Flags
 {
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index d6680977168..c0179d33ac5 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -1,14 +1,15 @@
 use smallvec::SmallVec;
 use std::fmt::Debug;
 use std::hash::Hash;
+use std::ops::Deref;
 
 use crate::inherent::*;
 use crate::ir_print::IrPrint;
 use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
 use crate::{
     AliasTerm, AliasTermKind, AliasTy, AliasTyKind, CanonicalVarInfo, CoercePredicate,
-    DebugWithInfcx, ExistentialProjection, ExistentialTraitRef, NormalizesTo, ProjectionPredicate,
-    SubtypePredicate, TraitPredicate, TraitRef,
+    DebugWithInfcx, ExistentialProjection, ExistentialTraitRef, FnSig, NormalizesTo,
+    ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef,
 };
 
 pub trait Interner:
@@ -24,13 +25,16 @@ pub trait Interner:
     + IrPrint<NormalizesTo<Self>>
     + IrPrint<SubtypePredicate<Self>>
     + IrPrint<CoercePredicate<Self>>
+    + IrPrint<FnSig<Self>>
 {
     type DefId: Copy + Debug + Hash + Eq;
     type DefiningOpaqueTypes: Copy + Debug + Hash + Default + Eq + TypeVisitable<Self>;
     type AdtDef: Copy + Debug + Hash + Eq;
 
     type GenericArgs: GenericArgs<Self>;
-    type GenericArgsSlice: Copy + Debug + Hash + Eq;
+    /// The slice of args for a specific item. For a GAT like `type Foo<'a>`, it will be `['a]`,
+    /// not including the args from the parent item (trait or impl).
+    type OwnItemArgs: Copy + Debug + Hash + Eq;
     type GenericArg: Copy + DebugWithInfcx<Self> + Hash + Eq;
     type Term: Copy + Debug + Hash + Eq;
 
@@ -42,7 +46,8 @@ pub trait Interner:
 
     // Kinds of tys
     type Ty: Ty<Self>;
-    type Tys: Copy + Debug + Hash + Eq + IntoIterator<Item = Self::Ty>;
+    type Tys: Tys<Self>;
+    type FnInputTys: Copy + Debug + Hash + Eq + Deref<Target = [Self::Ty]>;
     type ParamTy: Copy + Debug + Hash + Eq;
     type BoundTy: Copy + Debug + Hash + Eq;
     type PlaceholderTy: PlaceholderLike;
@@ -53,6 +58,8 @@ pub trait Interner:
     type PolyFnSig: Copy + DebugWithInfcx<Self> + Hash + Eq;
     type AllocId: Copy + Debug + Hash + Eq;
     type Pat: Copy + Debug + Hash + Eq + DebugWithInfcx<Self>;
+    type Unsafety: Unsafety<Self>;
+    type Abi: Abi<Self>;
 
     // Kinds of consts
     type Const: Const<Self>;
@@ -99,7 +106,7 @@ pub trait Interner:
         self,
         def_id: Self::DefId,
         args: Self::GenericArgs,
-    ) -> (TraitRef<Self>, Self::GenericArgsSlice);
+    ) -> (TraitRef<Self>, Self::OwnItemArgs);
 
     fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs;
 
diff --git a/compiler/rustc_type_ir/src/ir_print.rs b/compiler/rustc_type_ir/src/ir_print.rs
index 2a766d0bc09..af4b9eef14b 100644
--- a/compiler/rustc_type_ir/src/ir_print.rs
+++ b/compiler/rustc_type_ir/src/ir_print.rs
@@ -1,8 +1,8 @@
 use std::fmt;
 
 use crate::{
-    AliasTerm, AliasTy, CoercePredicate, ExistentialProjection, ExistentialTraitRef, Interner,
-    NormalizesTo, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef,
+    AliasTerm, AliasTy, CoercePredicate, ExistentialProjection, ExistentialTraitRef, FnSig,
+    Interner, NormalizesTo, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef,
 };
 
 pub trait IrPrint<T> {
@@ -45,6 +45,7 @@ define_display_via_print!(
     CoercePredicate,
     AliasTy,
     AliasTerm,
+    FnSig,
 );
 
 define_debug_via_print!(TraitRef, ExistentialTraitRef, ExistentialProjection);
diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs
index b6c7c2c348c..b0309a622f1 100644
--- a/compiler/rustc_type_ir/src/predicate.rs
+++ b/compiler/rustc_type_ir/src/predicate.rs
@@ -497,7 +497,7 @@ impl<I: Interner> AliasTerm<I> {
     /// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
     /// then this function would return a `T: StreamingIterator` trait reference and
     /// `['a]` as the own args.
-    pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef<I>, I::GenericArgsSlice) {
+    pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef<I>, I::OwnItemArgs) {
         interner.trait_ref_and_own_args_for_alias(self.def_id, self.args)
     }
 
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index 672c890f94e..b0158cafa33 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -342,7 +342,7 @@ impl<I: Interner> PartialEq for TyKind<I> {
 impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
     fn fmt<Infcx: InferCtxtLike<Interner = I>>(
         this: WithInfcx<'_, Infcx, &Self>,
-        f: &mut core::fmt::Formatter<'_>,
+        f: &mut fmt::Formatter<'_>,
     ) -> fmt::Result {
         match this.data {
             Bool => write!(f, "bool"),
@@ -514,7 +514,7 @@ impl<I: Interner> AliasTy<I> {
     /// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
     /// then this function would return a `T: StreamingIterator` trait reference and
     /// `['a]` as the own args.
-    pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef<I>, I::GenericArgsSlice) {
+    pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef<I>, I::OwnItemArgs) {
         debug_assert_eq!(self.kind(interner), AliasTyKind::Projection);
         interner.trait_ref_and_own_args_for_alias(self.def_id, self.args)
     }
@@ -561,8 +561,8 @@ impl<I: Interner> fmt::Debug for AliasTy<I> {
 impl<I: Interner> DebugWithInfcx<I> for AliasTy<I> {
     fn fmt<Infcx: InferCtxtLike<Interner = I>>(
         this: WithInfcx<'_, Infcx, &Self>,
-        f: &mut core::fmt::Formatter<'_>,
-    ) -> core::fmt::Result {
+        f: &mut fmt::Formatter<'_>,
+    ) -> fmt::Result {
         f.debug_struct("AliasTy")
             .field("args", &this.map(|data| data.args))
             .field("def_id", &this.data.def_id)
@@ -952,3 +952,76 @@ pub struct TypeAndMut<I: Interner> {
     pub ty: I::Ty,
     pub mutbl: Mutability,
 }
+
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = ""),
+    Hash(bound = "")
+)]
+#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+pub struct FnSig<I: Interner> {
+    pub inputs_and_output: I::Tys,
+    pub c_variadic: bool,
+    pub unsafety: I::Unsafety,
+    pub abi: I::Abi,
+}
+
+impl<I: Interner> FnSig<I> {
+    pub fn split_inputs_and_output(self) -> (I::FnInputTys, I::Ty) {
+        self.inputs_and_output.split_inputs_and_output()
+    }
+
+    pub fn inputs(self) -> I::FnInputTys {
+        self.split_inputs_and_output().0
+    }
+
+    pub fn output(self) -> I::Ty {
+        self.split_inputs_and_output().1
+    }
+}
+
+impl<I: Interner> fmt::Debug for FnSig<I> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        WithInfcx::with_no_infcx(self).fmt(f)
+    }
+}
+impl<I: Interner> DebugWithInfcx<I> for FnSig<I> {
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
+        f: &mut fmt::Formatter<'_>,
+    ) -> fmt::Result {
+        let sig = this.data;
+        let FnSig { inputs_and_output: _, c_variadic, unsafety, abi } = sig;
+
+        write!(f, "{}", unsafety.prefix_str())?;
+        if !abi.is_rust() {
+            write!(f, "extern \"{abi:?}\" ")?;
+        }
+
+        write!(f, "fn(")?;
+        let (inputs, output) = sig.split_inputs_and_output();
+        for (i, ty) in inputs.iter().enumerate() {
+            if i > 0 {
+                write!(f, ", ")?;
+            }
+            write!(f, "{:?}", &this.wrap(ty))?;
+        }
+        if *c_variadic {
+            if inputs.is_empty() {
+                write!(f, "...")?;
+            } else {
+                write!(f, ", ...")?;
+            }
+        }
+        write!(f, ")")?;
+
+        match output.kind() {
+            Tuple(list) if list.is_empty() => Ok(()),
+            _ => write!(f, " -> {:?}", &this.wrap(sig.output())),
+        }
+    }
+}
diff --git a/src/doc/rustc/src/linker-plugin-lto.md b/src/doc/rustc/src/linker-plugin-lto.md
index ff80f140482..ab95aa2e5a1 100644
--- a/src/doc/rustc/src/linker-plugin-lto.md
+++ b/src/doc/rustc/src/linker-plugin-lto.md
@@ -200,6 +200,7 @@ The following table shows known good combinations of toolchain versions.
 | 1.60 - 1.64  |      14       |
 | 1.65 - 1.69  |      15       |
 | 1.70 - 1.72  |      16       |
-| 1.73 - 1.74  |      17       |
+| 1.73 - 1.77  |      17       |
+| 1.78         |      18       |
 
 Note that the compatibility policy for this feature might change in the future.
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index e788069ea80..1c5a6dcfb1f 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -188,7 +188,19 @@ pub enum TypeBindingKind {
     Constraint(Vec<GenericBound>),
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+/// An opaque identifier for an item.
+///
+/// It can be used to lookup in [Crate::index] or [Crate::paths] to resolve it
+/// to an [Item].
+///
+/// Id's are only valid within a single JSON blob. They cannot be used to
+/// resolve references between the JSON output's for different crates.
+///
+/// Rustdoc makes no guarantees about the inner value of Id's. Applications
+/// should treat them as opaque keys to lookup items, and avoid attempting
+/// to parse them, or otherwise depend on any implementation details.
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+// FIXME(aDotInTheVoid): Consider making this non-public in rustdoc-types.
 pub struct Id(pub String);
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
diff --git a/tests/codegen/float/f128.rs b/tests/codegen/float/f128.rs
index 97d545e0283..32c5be1ec65 100644
--- a/tests/codegen/float/f128.rs
+++ b/tests/codegen/float/f128.rs
@@ -2,6 +2,7 @@
 
 #![crate_type = "lib"]
 #![feature(f128)]
+#![feature(f16)]
 #![feature(core_intrinsics)]
 
 // CHECK-LABEL: i1 @f128_eq(
@@ -127,3 +128,196 @@ pub fn f128_rem_assign(a: &mut f128, b: f128) {
     // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}}
     *a %= b
 }
+
+/* float to float conversions */
+
+// CHECK-LABEL: half @f128_as_f16(
+#[no_mangle]
+pub fn f128_as_f16(a: f128) -> f16 {
+    // CHECK: fptrunc fp128 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: float @f128_as_f32(
+#[no_mangle]
+pub fn f128_as_f32(a: f128) -> f32 {
+    // CHECK: fptrunc fp128 %{{.+}} to float
+    a as f32
+}
+
+// CHECK-LABEL: double @f128_as_f64(
+#[no_mangle]
+pub fn f128_as_f64(a: f128) -> f64 {
+    // CHECK: fptrunc fp128 %{{.+}} to double
+    a as f64
+}
+
+// CHECK-LABEL: fp128 @f128_as_self(
+#[no_mangle]
+pub fn f128_as_self(a: f128) -> f128 {
+    // CHECK: ret fp128 %{{.+}}
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @f16_as_f128(
+#[no_mangle]
+pub fn f16_as_f128(a: f16) -> f128 {
+    // CHECK: fpext half %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @f32_as_f128(
+#[no_mangle]
+pub fn f32_as_f128(a: f32) -> f128 {
+    // CHECK: fpext float %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @f64_as_f128(
+#[no_mangle]
+pub fn f64_as_f128(a: f64) -> f128 {
+    // CHECK: fpext double %{{.+}} to fp128
+    a as f128
+}
+
+/* float to int conversions */
+
+// CHECK-LABEL: i8 @f128_as_u8(
+#[no_mangle]
+pub fn f128_as_u8(a: f128) -> u8 {
+    // CHECK: call i8 @llvm.fptoui.sat.i8.f128(fp128 %{{.+}})
+    a as u8
+}
+
+#[no_mangle]
+pub fn f128_as_u16(a: f128) -> u16 {
+    // CHECK: call i16 @llvm.fptoui.sat.i16.f128(fp128 %{{.+}})
+    a as u16
+}
+
+// CHECK-LABEL: i32 @f128_as_u32(
+#[no_mangle]
+pub fn f128_as_u32(a: f128) -> u32 {
+    // CHECK: call i32 @llvm.fptoui.sat.i32.f128(fp128 %{{.+}})
+    a as u32
+}
+
+// CHECK-LABEL: i64 @f128_as_u64(
+#[no_mangle]
+pub fn f128_as_u64(a: f128) -> u64 {
+    // CHECK: call i64 @llvm.fptoui.sat.i64.f128(fp128 %{{.+}})
+    a as u64
+}
+
+// CHECK-LABEL: i128 @f128_as_u128(
+#[no_mangle]
+pub fn f128_as_u128(a: f128) -> u128 {
+    // CHECK: call i128 @llvm.fptoui.sat.i128.f128(fp128 %{{.+}})
+    a as u128
+}
+
+// CHECK-LABEL: i8 @f128_as_i8(
+#[no_mangle]
+pub fn f128_as_i8(a: f128) -> i8 {
+    // CHECK: call i8 @llvm.fptosi.sat.i8.f128(fp128 %{{.+}})
+    a as i8
+}
+
+// CHECK-LABEL: i16 @f128_as_i16(
+#[no_mangle]
+pub fn f128_as_i16(a: f128) -> i16 {
+    // CHECK: call i16 @llvm.fptosi.sat.i16.f128(fp128 %{{.+}})
+    a as i16
+}
+// CHECK-LABEL: i32 @f128_as_i32(
+#[no_mangle]
+pub fn f128_as_i32(a: f128) -> i32 {
+    // CHECK: call i32 @llvm.fptosi.sat.i32.f128(fp128 %{{.+}})
+    a as i32
+}
+
+// CHECK-LABEL: i64 @f128_as_i64(
+#[no_mangle]
+pub fn f128_as_i64(a: f128) -> i64 {
+    // CHECK: call i64 @llvm.fptosi.sat.i64.f128(fp128 %{{.+}})
+    a as i64
+}
+
+// CHECK-LABEL: i128 @f128_as_i128(
+#[no_mangle]
+pub fn f128_as_i128(a: f128) -> i128 {
+    // CHECK: call i128 @llvm.fptosi.sat.i128.f128(fp128 %{{.+}})
+    a as i128
+}
+
+/* int to float conversions */
+
+// CHECK-LABEL: fp128 @u8_as_f128(
+#[no_mangle]
+pub fn u8_as_f128(a: u8) -> f128 {
+    // CHECK: uitofp i8 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @u16_as_f128(
+#[no_mangle]
+pub fn u16_as_f128(a: u16) -> f128 {
+    // CHECK: uitofp i16 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @u32_as_f128(
+#[no_mangle]
+pub fn u32_as_f128(a: u32) -> f128 {
+    // CHECK: uitofp i32 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @u64_as_f128(
+#[no_mangle]
+pub fn u64_as_f128(a: u64) -> f128 {
+    // CHECK: uitofp i64 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @u128_as_f128(
+#[no_mangle]
+pub fn u128_as_f128(a: u128) -> f128 {
+    // CHECK: uitofp i128 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @i8_as_f128(
+#[no_mangle]
+pub fn i8_as_f128(a: i8) -> f128 {
+    // CHECK: sitofp i8 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @i16_as_f128(
+#[no_mangle]
+pub fn i16_as_f128(a: i16) -> f128 {
+    // CHECK: sitofp i16 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @i32_as_f128(
+#[no_mangle]
+pub fn i32_as_f128(a: i32) -> f128 {
+    // CHECK: sitofp i32 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @i64_as_f128(
+#[no_mangle]
+pub fn i64_as_f128(a: i64) -> f128 {
+    // CHECK: sitofp i64 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @i128_as_f128(
+#[no_mangle]
+pub fn i128_as_f128(a: i128) -> f128 {
+    // CHECK: sitofp i128 %{{.+}} to fp128
+    a as f128
+}
diff --git a/tests/codegen/float/f16.rs b/tests/codegen/float/f16.rs
index d1f75cc3b68..96daac869c2 100644
--- a/tests/codegen/float/f16.rs
+++ b/tests/codegen/float/f16.rs
@@ -1,9 +1,12 @@
 // Verify that our intrinsics generate the correct LLVM calls for f16
 
 #![crate_type = "lib"]
+#![feature(f128)]
 #![feature(f16)]
 #![feature(core_intrinsics)]
 
+/* arithmetic */
+
 // CHECK-LABEL: i1 @f16_eq(
 #[no_mangle]
 pub fn f16_eq(a: f16, b: f16) -> bool {
@@ -109,7 +112,7 @@ pub fn f16_sub_assign(a: &mut f16, b: f16) {
 pub fn f16_mul_assign(a: &mut f16, b: f16) {
     // CHECK: fmul half %{{.+}}, %{{.+}}
     // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}}
-    *a *= b
+    *a *= b;
 }
 
 // CHECK-LABEL: void @f16_div_assign(
@@ -117,7 +120,7 @@ pub fn f16_mul_assign(a: &mut f16, b: f16) {
 pub fn f16_div_assign(a: &mut f16, b: f16) {
     // CHECK: fdiv half %{{.+}}, %{{.+}}
     // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}}
-    *a /= b
+    *a /= b;
 }
 
 // CHECK-LABEL: void @f16_rem_assign(
@@ -125,5 +128,198 @@ pub fn f16_div_assign(a: &mut f16, b: f16) {
 pub fn f16_rem_assign(a: &mut f16, b: f16) {
     // CHECK: frem half %{{.+}}, %{{.+}}
     // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}}
-    *a %= b
+    *a %= b;
+}
+
+/* float to float conversions */
+
+// CHECK-LABEL: half @f16_as_self(
+#[no_mangle]
+pub fn f16_as_self(a: f16) -> f16 {
+    // CHECK: ret half %{{.+}}
+    a as f16
+}
+
+// CHECK-LABEL: float @f16_as_f32(
+#[no_mangle]
+pub fn f16_as_f32(a: f16) -> f32 {
+    // CHECK: fpext half %{{.+}} to float
+    a as f32
+}
+
+// CHECK-LABEL: double @f16_as_f64(
+#[no_mangle]
+pub fn f16_as_f64(a: f16) -> f64 {
+    // CHECK: fpext half %{{.+}} to double
+    a as f64
+}
+
+// CHECK-LABEL: fp128 @f16_as_f128(
+#[no_mangle]
+pub fn f16_as_f128(a: f16) -> f128 {
+    // CHECK: fpext half %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: half @f32_as_f16(
+#[no_mangle]
+pub fn f32_as_f16(a: f32) -> f16 {
+    // CHECK: fptrunc float %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @f64_as_f16(
+#[no_mangle]
+pub fn f64_as_f16(a: f64) -> f16 {
+    // CHECK: fptrunc double %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @f128_as_f16(
+#[no_mangle]
+pub fn f128_as_f16(a: f128) -> f16 {
+    // CHECK: fptrunc fp128 %{{.+}} to half
+    a as f16
+}
+
+/* float to int conversions */
+
+// CHECK-LABEL: i8 @f16_as_u8(
+#[no_mangle]
+pub fn f16_as_u8(a: f16) -> u8 {
+    // CHECK: call i8 @llvm.fptoui.sat.i8.f16(half %{{.+}})
+    a as u8
+}
+
+#[no_mangle]
+pub fn f16_as_u16(a: f16) -> u16 {
+    // CHECK: call i16 @llvm.fptoui.sat.i16.f16(half %{{.+}})
+    a as u16
+}
+
+// CHECK-LABEL: i32 @f16_as_u32(
+#[no_mangle]
+pub fn f16_as_u32(a: f16) -> u32 {
+    // CHECK: call i32 @llvm.fptoui.sat.i32.f16(half %{{.+}})
+    a as u32
+}
+
+// CHECK-LABEL: i64 @f16_as_u64(
+#[no_mangle]
+pub fn f16_as_u64(a: f16) -> u64 {
+    // CHECK: call i64 @llvm.fptoui.sat.i64.f16(half %{{.+}})
+    a as u64
+}
+
+// CHECK-LABEL: i128 @f16_as_u128(
+#[no_mangle]
+pub fn f16_as_u128(a: f16) -> u128 {
+    // CHECK: call i128 @llvm.fptoui.sat.i128.f16(half %{{.+}})
+    a as u128
+}
+
+// CHECK-LABEL: i8 @f16_as_i8(
+#[no_mangle]
+pub fn f16_as_i8(a: f16) -> i8 {
+    // CHECK: call i8 @llvm.fptosi.sat.i8.f16(half %{{.+}})
+    a as i8
+}
+
+// CHECK-LABEL: i16 @f16_as_i16(
+#[no_mangle]
+pub fn f16_as_i16(a: f16) -> i16 {
+    // CHECK: call i16 @llvm.fptosi.sat.i16.f16(half %{{.+}})
+    a as i16
+}
+// CHECK-LABEL: i32 @f16_as_i32(
+#[no_mangle]
+pub fn f16_as_i32(a: f16) -> i32 {
+    // CHECK: call i32 @llvm.fptosi.sat.i32.f16(half %{{.+}})
+    a as i32
+}
+
+// CHECK-LABEL: i64 @f16_as_i64(
+#[no_mangle]
+pub fn f16_as_i64(a: f16) -> i64 {
+    // CHECK: call i64 @llvm.fptosi.sat.i64.f16(half %{{.+}})
+    a as i64
+}
+
+// CHECK-LABEL: i128 @f16_as_i128(
+#[no_mangle]
+pub fn f16_as_i128(a: f16) -> i128 {
+    // CHECK: call i128 @llvm.fptosi.sat.i128.f16(half %{{.+}})
+    a as i128
+}
+
+/* int to float conversions */
+
+// CHECK-LABEL: half @u8_as_f16(
+#[no_mangle]
+pub fn u8_as_f16(a: u8) -> f16 {
+    // CHECK: uitofp i8 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @u16_as_f16(
+#[no_mangle]
+pub fn u16_as_f16(a: u16) -> f16 {
+    // CHECK: uitofp i16 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @u32_as_f16(
+#[no_mangle]
+pub fn u32_as_f16(a: u32) -> f16 {
+    // CHECK: uitofp i32 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @u64_as_f16(
+#[no_mangle]
+pub fn u64_as_f16(a: u64) -> f16 {
+    // CHECK: uitofp i64 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @u128_as_f16(
+#[no_mangle]
+pub fn u128_as_f16(a: u128) -> f16 {
+    // CHECK: uitofp i128 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @i8_as_f16(
+#[no_mangle]
+pub fn i8_as_f16(a: i8) -> f16 {
+    // CHECK: sitofp i8 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @i16_as_f16(
+#[no_mangle]
+pub fn i16_as_f16(a: i16) -> f16 {
+    // CHECK: sitofp i16 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @i32_as_f16(
+#[no_mangle]
+pub fn i32_as_f16(a: i32) -> f16 {
+    // CHECK: sitofp i32 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @i64_as_f16(
+#[no_mangle]
+pub fn i64_as_f16(a: i64) -> f16 {
+    // CHECK: sitofp i64 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @i128_as_f16(
+#[no_mangle]
+pub fn i128_as_f16(a: i128) -> f16 {
+    // CHECK: sitofp i128 %{{.+}} to half
+    a as f16
 }
diff --git a/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr b/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr
index 6e68646fbe4..57cba790b55 100644
--- a/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr
+++ b/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr
@@ -1,12 +1,12 @@
-error[E0119]: conflicting implementations of trait `Trait` for type `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>>`
+error[E0119]: conflicting implementations of trait `Trait` for type `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>`
   --> $DIR/coherence-fulfill-overflow.rs:12:1
    |
 LL | impl<T: ?Sized + TwoW> Trait for W<T> {}
    | ------------------------------------- first implementation here
 LL | impl<T: ?Sized + TwoW> Trait for T {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>>`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>`
    |
-   = note: overflow evaluating the requirement `W<W<W<W<_>>>>: TwoW`
+   = note: overflow evaluating the requirement `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>: TwoW`
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`coherence_fulfill_overflow`)
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr b/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr
index df25150c21f..8d7d8cee08a 100644
--- a/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr
+++ b/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr
@@ -1,16 +1,9 @@
-error[E0275]: overflow evaluating the requirement `_: Sized`
+error[E0275]: overflow evaluating the requirement `W<_>: Trait`
   --> $DIR/fixpoint-exponential-growth.rs:33:13
    |
 LL |     impls::<W<_>>();
    |             ^^^^
    |
-note: required for `W<(W<_>, W<_>)>` to implement `Trait`
-  --> $DIR/fixpoint-exponential-growth.rs:23:12
-   |
-LL | impl<T, U> Trait for W<(W<T>, W<U>)>
-   |      -     ^^^^^     ^^^^^^^^^^^^^^^
-   |      |
-   |      unsatisfied trait bound introduced here
 note: required by a bound in `impls`
   --> $DIR/fixpoint-exponential-growth.rs:30:13
    |
diff --git a/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr b/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr
index 86c71ad92ff..7cedb4d36c9 100644
--- a/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr
+++ b/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr
@@ -1,53 +1,21 @@
-error[E0275]: overflow evaluating the requirement `(): Inductive`
+error[E0275]: overflow evaluating the requirement `(): Trait`
   --> $DIR/double-cycle-inductive-coinductive.rs:32:19
    |
 LL |     impls_trait::<()>();
    |                   ^^
    |
-note: required for `()` to implement `Trait`
-  --> $DIR/double-cycle-inductive-coinductive.rs:9:34
-   |
-LL | impl<T: Inductive + Coinductive> Trait for T {}
-   |         ---------                ^^^^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-note: required for `()` to implement `Inductive`
-  --> $DIR/double-cycle-inductive-coinductive.rs:12:16
-   |
-LL | impl<T: Trait> Inductive for T {}
-   |         -----  ^^^^^^^^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-   = note: 7 redundant requirements hidden
-   = note: required for `()` to implement `Trait`
 note: required by a bound in `impls_trait`
   --> $DIR/double-cycle-inductive-coinductive.rs:17:19
    |
 LL | fn impls_trait<T: Trait>() {}
    |                   ^^^^^ required by this bound in `impls_trait`
 
-error[E0275]: overflow evaluating the requirement `(): CoinductiveRev`
+error[E0275]: overflow evaluating the requirement `(): TraitRev`
   --> $DIR/double-cycle-inductive-coinductive.rs:35:23
    |
 LL |     impls_trait_rev::<()>();
    |                       ^^
    |
-note: required for `()` to implement `TraitRev`
-  --> $DIR/double-cycle-inductive-coinductive.rs:21:40
-   |
-LL | impl<T: CoinductiveRev + InductiveRev> TraitRev for T {}
-   |         --------------                 ^^^^^^^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-note: required for `()` to implement `CoinductiveRev`
-  --> $DIR/double-cycle-inductive-coinductive.rs:27:19
-   |
-LL | impl<T: TraitRev> CoinductiveRev for T {}
-   |         --------  ^^^^^^^^^^^^^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-   = note: 7 redundant requirements hidden
-   = note: required for `()` to implement `TraitRev`
 note: required by a bound in `impls_trait_rev`
   --> $DIR/double-cycle-inductive-coinductive.rs:29:23
    |
diff --git a/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr b/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr
index ea46c0fea97..a2a5c028cf8 100644
--- a/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr
+++ b/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr
@@ -1,19 +1,9 @@
-error[E0275]: overflow evaluating the requirement `W<W<_>>: Trait`
+error[E0275]: overflow evaluating the requirement `W<_>: Trait`
   --> $DIR/inductive-fixpoint-hang.rs:31:19
    |
 LL |     impls_trait::<W<_>>();
    |                   ^^^^
    |
-note: required for `W<W<W<_>>>` to implement `Trait`
-  --> $DIR/inductive-fixpoint-hang.rs:22:17
-   |
-LL | impl<T: ?Sized> Trait for W<W<T>>
-   |                 ^^^^^     ^^^^^^^
-LL | where
-LL |     W<T>: Trait,
-   |           ----- unsatisfied trait bound introduced here
-   = note: 8 redundant requirements hidden
-   = note: required for `W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>` to implement `Trait`
 note: required by a bound in `impls_trait`
   --> $DIR/inductive-fixpoint-hang.rs:28:19
    |
diff --git a/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs
index 9d0ea51b1b2..78683372580 100644
--- a/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs
+++ b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs
@@ -39,7 +39,7 @@ fn impls_ar<T: AR>() {}
 
 fn main() {
     impls_a::<()>();
-    //~^ ERROR overflow evaluating the requirement `(): B`
+    //~^ ERROR overflow evaluating the requirement `(): A`
 
     impls_ar::<()>();
     //~^ ERROR overflow evaluating the requirement `(): AR`
diff --git a/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr
index fe02d3c407c..e9cc6bc6c81 100644
--- a/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr
+++ b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr
@@ -1,25 +1,9 @@
-error[E0275]: overflow evaluating the requirement `(): B`
+error[E0275]: overflow evaluating the requirement `(): A`
   --> $DIR/inductive-not-on-stack.rs:41:15
    |
 LL |     impls_a::<()>();
    |               ^^
    |
-note: required for `()` to implement `A`
-  --> $DIR/inductive-not-on-stack.rs:21:16
-   |
-LL | impl<T: B + C> A for T {}
-   |         -      ^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-note: required for `()` to implement `B`
-  --> $DIR/inductive-not-on-stack.rs:22:12
-   |
-LL | impl<T: A> B for T {}
-   |         -  ^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-   = note: 7 redundant requirements hidden
-   = note: required for `()` to implement `A`
 note: required by a bound in `impls_a`
   --> $DIR/inductive-not-on-stack.rs:25:15
    |
@@ -32,29 +16,6 @@ error[E0275]: overflow evaluating the requirement `(): AR`
 LL |     impls_ar::<()>();
    |                ^^
    |
-note: required for `()` to implement `BR`
-  --> $DIR/inductive-not-on-stack.rs:35:13
-   |
-LL | impl<T: AR> BR for T {}
-   |         --  ^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-note: required for `()` to implement `CR`
-  --> $DIR/inductive-not-on-stack.rs:36:13
-   |
-LL | impl<T: BR> CR for T {}
-   |         --  ^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-note: required for `()` to implement `AR`
-  --> $DIR/inductive-not-on-stack.rs:34:18
-   |
-LL | impl<T: CR + BR> AR for T {}
-   |         --       ^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-   = note: 6 redundant requirements hidden
-   = note: required for `()` to implement `AR`
 note: required by a bound in `impls_ar`
   --> $DIR/inductive-not-on-stack.rs:38:16
    |
diff --git a/tests/ui/traits/next-solver/cycles/mixed-cycles-1.rs b/tests/ui/traits/next-solver/cycles/mixed-cycles-1.rs
index b90a354be1b..6d75d241864 100644
--- a/tests/ui/traits/next-solver/cycles/mixed-cycles-1.rs
+++ b/tests/ui/traits/next-solver/cycles/mixed-cycles-1.rs
@@ -35,5 +35,5 @@ fn impls_a<T: A>() {}
 
 fn main() {
     impls_a::<()>();
-    //~^ ERROR overflow evaluating the requirement `(): CInd`
+    //~^ ERROR overflow evaluating the requirement `(): A`
 }
diff --git a/tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr b/tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr
index 03e61dbf99c..17544eb1da5 100644
--- a/tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr
+++ b/tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr
@@ -1,46 +1,9 @@
-error[E0275]: overflow evaluating the requirement `(): CInd`
+error[E0275]: overflow evaluating the requirement `(): A`
   --> $DIR/mixed-cycles-1.rs:37:15
    |
 LL |     impls_a::<()>();
    |               ^^
    |
-note: required for `()` to implement `B`
-  --> $DIR/mixed-cycles-1.rs:31:28
-   |
-LL | impl<T: ?Sized + CInd + C> B for T {}
-   |                  ----      ^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
-note: required for `()` to implement `C`
-  --> $DIR/mixed-cycles-1.rs:32:25
-   |
-LL | impl<T: ?Sized + B + A> C for T {}
-   |                  -      ^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
-note: required for `()` to implement `CInd`
-  --> $DIR/mixed-cycles-1.rs:28:21
-   |
-LL | impl<T: ?Sized + C> CInd for T {}
-   |                  -  ^^^^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
-   = note: 4 redundant requirements hidden
-   = note: required for `()` to implement `B`
-note: required for `()` to implement `BInd`
-  --> $DIR/mixed-cycles-1.rs:23:21
-   |
-LL | impl<T: ?Sized + B> BInd for T {}
-   |                  -  ^^^^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
-note: required for `()` to implement `A`
-  --> $DIR/mixed-cycles-1.rs:30:28
-   |
-LL | impl<T: ?Sized + BInd + C> A for T {}
-   |                  ----      ^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
 note: required by a bound in `impls_a`
   --> $DIR/mixed-cycles-1.rs:34:15
    |
diff --git a/tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs b/tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs
index a3ffcaafb37..c939a6e5ef2 100644
--- a/tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs
+++ b/tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs
@@ -28,5 +28,5 @@ fn impls_a<T: A>() {}
 
 fn main() {
     impls_a::<()>();
-    //~^ ERROR overflow evaluating the requirement `(): BInd`
+    //~^ ERROR overflow evaluating the requirement `(): A`
 }
diff --git a/tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr b/tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr
index 892426abe82..a9be1016c74 100644
--- a/tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr
+++ b/tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr
@@ -1,32 +1,9 @@
-error[E0275]: overflow evaluating the requirement `(): BInd`
+error[E0275]: overflow evaluating the requirement `(): A`
   --> $DIR/mixed-cycles-2.rs:30:15
    |
 LL |     impls_a::<()>();
    |               ^^
    |
-note: required for `()` to implement `B`
-  --> $DIR/mixed-cycles-2.rs:25:24
-   |
-LL | impl<T: ?Sized + BInd> B for T {}
-   |                  ----  ^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
-note: required for `()` to implement `BInd`
-  --> $DIR/mixed-cycles-2.rs:22:21
-   |
-LL | impl<T: ?Sized + B> BInd for T {}
-   |                  -  ^^^^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
-   = note: 6 redundant requirements hidden
-   = note: required for `()` to implement `BInd`
-note: required for `()` to implement `A`
-  --> $DIR/mixed-cycles-2.rs:24:28
-   |
-LL | impl<T: ?Sized + BInd + B> A for T {}
-   |                  ----      ^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
 note: required by a bound in `impls_a`
   --> $DIR/mixed-cycles-2.rs:27:15
    |
diff --git a/tests/ui/traits/next-solver/diagnostics/ambiguous-fail.rs b/tests/ui/traits/next-solver/diagnostics/ambiguous-fail.rs
new file mode 100644
index 00000000000..4094ab84166
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/ambiguous-fail.rs
@@ -0,0 +1,21 @@
+//@ compile-flags: -Znext-solver
+
+trait Trait {
+    type Assoc;
+}
+
+struct W<T>(*mut T);
+impl<T> Trait for W<W<T>>
+where
+    W<T>: Trait,
+{
+    type Assoc = ();
+}
+
+trait NoOverlap {}
+impl<T: Trait> NoOverlap for T {}
+
+impl<T: Trait<Assoc = u32>> NoOverlap for W<T> {}
+//~^ ERROR conflicting implementations of trait `NoOverlap` for type `W<_>`
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/diagnostics/ambiguous-fail.stderr b/tests/ui/traits/next-solver/diagnostics/ambiguous-fail.stderr
new file mode 100644
index 00000000000..42be1960563
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/ambiguous-fail.stderr
@@ -0,0 +1,12 @@
+error[E0119]: conflicting implementations of trait `NoOverlap` for type `W<_>`
+  --> $DIR/ambiguous-fail.rs:18:1
+   |
+LL | impl<T: Trait> NoOverlap for T {}
+   | ------------------------------ first implementation here
+LL |
+LL | impl<T: Trait<Assoc = u32>> NoOverlap for W<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<_>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/traits/next-solver/diagnostics/ambiguous-pass.rs b/tests/ui/traits/next-solver/diagnostics/ambiguous-pass.rs
new file mode 100644
index 00000000000..2d40ba37a89
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/ambiguous-pass.rs
@@ -0,0 +1,21 @@
+//@ compile-flags: -Znext-solver
+
+trait Trait {
+    type Assoc;
+}
+
+struct W<T>(*mut T);
+impl<T> Trait for W<W<T>>
+where
+    W<T>: Trait,
+{
+    type Assoc = ();
+}
+
+trait NoOverlap {}
+impl<T: Trait> NoOverlap for T {}
+
+impl<T: Trait<Assoc = ()>> NoOverlap for W<T> {}
+//~^ ERROR conflicting implementations of trait `NoOverlap` for type `W<_>`
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/diagnostics/ambiguous-pass.stderr b/tests/ui/traits/next-solver/diagnostics/ambiguous-pass.stderr
new file mode 100644
index 00000000000..5c77fc71e55
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/ambiguous-pass.stderr
@@ -0,0 +1,12 @@
+error[E0119]: conflicting implementations of trait `NoOverlap` for type `W<_>`
+  --> $DIR/ambiguous-pass.rs:18:1
+   |
+LL | impl<T: Trait> NoOverlap for T {}
+   | ------------------------------ first implementation here
+LL |
+LL | impl<T: Trait<Assoc = ()>> NoOverlap for W<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<_>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/traits/next-solver/overflow/exponential-trait-goals.rs b/tests/ui/traits/next-solver/overflow/exponential-trait-goals.rs
index 052d803765d..186d0e8be56 100644
--- a/tests/ui/traits/next-solver/overflow/exponential-trait-goals.rs
+++ b/tests/ui/traits/next-solver/overflow/exponential-trait-goals.rs
@@ -15,5 +15,5 @@ fn impls<T: Trait>() {}
 
 fn main() {
     impls::<W<_>>();
-    //~^ ERROR overflow evaluating the requirement `_: Sized`
+    //~^ ERROR overflow evaluating the requirement `W<_>: Trait`
 }
diff --git a/tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr b/tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr
index 6583cae8bb9..b032ae3e740 100644
--- a/tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr
+++ b/tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr
@@ -1,16 +1,9 @@
-error[E0275]: overflow evaluating the requirement `_: Sized`
+error[E0275]: overflow evaluating the requirement `W<_>: Trait`
   --> $DIR/exponential-trait-goals.rs:17:13
    |
 LL |     impls::<W<_>>();
    |             ^^^^
    |
-note: required for `W<(W<_>, W<_>)>` to implement `Trait`
-  --> $DIR/exponential-trait-goals.rs:7:12
-   |
-LL | impl<T, U> Trait for W<(W<T>, W<U>)>
-   |      -     ^^^^^     ^^^^^^^^^^^^^^^
-   |      |
-   |      unsatisfied trait bound introduced here
 note: required by a bound in `impls`
   --> $DIR/exponential-trait-goals.rs:14:13
    |
diff --git a/tests/ui/traits/next-solver/overflow/global-cache.stderr b/tests/ui/traits/next-solver/overflow/global-cache.stderr
index 9e467721e83..67616619384 100644
--- a/tests/ui/traits/next-solver/overflow/global-cache.stderr
+++ b/tests/ui/traits/next-solver/overflow/global-cache.stderr
@@ -5,15 +5,6 @@ LL |     impls_trait::<Four<Four<Four<Four<()>>>>>();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "18"]` attribute to your crate (`global_cache`)
-note: required for `Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<()>>>>>>>>>>>` to implement `Trait`
-  --> $DIR/global-cache.rs:12:16
-   |
-LL | impl<T: Trait> Trait for Inc<T> {}
-   |         -----  ^^^^^     ^^^^^^
-   |         |
-   |         unsatisfied trait bound introduced here
-   = note: 5 redundant requirements hidden
-   = note: required for `Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<()>>>>>>>>>>>>>>>>` to implement `Trait`
 note: required by a bound in `impls_trait`
   --> $DIR/global-cache.rs:15:19
    |