about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2025-01-22 20:13:36 +0000
committerMichael Goulet <michael@errs.io>2025-01-31 18:21:58 +0000
commit304b3cfcb298c6bd6f7644ec3c78f28dd72eba1c (patch)
tree8decd8ff3c6d7247a91d1537ae460656630b22a3
parentd8b176f6836fa7efa0cdeb3488bceebbd5b219fb (diff)
downloadrust-304b3cfcb298c6bd6f7644ec3c78f28dd72eba1c.tar.gz
rust-304b3cfcb298c6bd6f7644ec3c78f28dd72eba1c.zip
Manually walk into WF obligations in BestObligation proof tree visitor
-rw-r--r--compiler/rustc_trait_selection/src/solve/delegate.rs9
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs60
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect/analyse.rs82
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs10
-rw-r--r--tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-88119.stderr34
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr12
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs4
-rw-r--r--tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr5
-rw-r--r--tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr4
-rw-r--r--tests/ui/traits/next-solver/specialization-transmute.stderr7
-rw-r--r--tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.next.stderr2
-rw-r--r--tests/ui/union/union-derive-eq.next.stderr2
-rw-r--r--tests/ui/wf/wf-normalization-sized.next.stderr6
-rw-r--r--tests/ui/wf/wf-trait-fn-arg.next.stderr5
-rw-r--r--tests/ui/wf/wf-trait-fn-ret.next.stderr5
-rw-r--r--tests/ui/wf/wf-trait-fn-where-clause.next.stderr5
18 files changed, 160 insertions, 100 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs
index acd00d9f74f..abb79493432 100644
--- a/compiler/rustc_trait_selection/src/solve/delegate.rs
+++ b/compiler/rustc_trait_selection/src/solve/delegate.rs
@@ -1,7 +1,7 @@
 use std::ops::Deref;
 
 use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
 use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
 use rustc_infer::infer::canonical::{
     Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarValues,
@@ -98,9 +98,10 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
         param_env: ty::ParamEnv<'tcx>,
         arg: ty::GenericArg<'tcx>,
     ) -> Option<Vec<Goal<'tcx, ty::Predicate<'tcx>>>> {
-        crate::traits::wf::unnormalized_obligations(&self.0, param_env, arg).map(|obligations| {
-            obligations.into_iter().map(|obligation| obligation.into()).collect()
-        })
+        crate::traits::wf::unnormalized_obligations(&self.0, param_env, arg, DUMMY_SP, CRATE_DEF_ID)
+            .map(|obligations| {
+                obligations.into_iter().map(|obligation| obligation.into()).collect()
+            })
     }
 
     fn clone_opaque_types_for_query_response(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> {
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
index 2c55f13a0df..c64bc19835b 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
@@ -10,13 +10,13 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as _};
-use rustc_type_ir::solve::NoSolution;
+use rustc_type_ir::solve::{Goal, NoSolution};
 use tracing::{instrument, trace};
 
 use crate::solve::Certainty;
 use crate::solve::delegate::SolverDelegate;
 use crate::solve::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor};
-use crate::traits::{FulfillmentError, FulfillmentErrorCode};
+use crate::traits::{FulfillmentError, FulfillmentErrorCode, wf};
 
 pub(super) fn fulfillment_error_for_no_solution<'tcx>(
     infcx: &InferCtxt<'tcx>,
@@ -207,14 +207,10 @@ impl<'tcx> BestObligation<'tcx> {
                                             | GoalSource::AliasBoundConstCondition
                                             | GoalSource::InstantiateHigherRanked
                                             | GoalSource::AliasWellFormed
-                                    ) && match self.consider_ambiguities {
-                                        true => {
-                                            matches!(
-                                                nested_goal.result(),
-                                                Ok(Certainty::Maybe(MaybeCause::Ambiguity))
-                                            )
-                                        }
-                                        false => matches!(nested_goal.result(), Err(_)),
+                                    ) && match (self.consider_ambiguities, nested_goal.result()) {
+                                        (true, Ok(Certainty::Maybe(MaybeCause::Ambiguity)))
+                                        | (false, Err(_)) => true,
+                                        _ => false,
                                     }
                                 },
                             )
@@ -233,6 +229,39 @@ impl<'tcx> BestObligation<'tcx> {
 
         candidates
     }
+
+    /// HACK: We walk the nested obligations for a well-formed arg manually,
+    /// since there's nontrivial logic in `wf.rs` to set up an obligation cause.
+    /// Ideally we'd be able to track this better.
+    fn visit_well_formed_goal(
+        &mut self,
+        candidate: &inspect::InspectCandidate<'_, 'tcx>,
+        arg: ty::GenericArg<'tcx>,
+    ) -> ControlFlow<PredicateObligation<'tcx>> {
+        let infcx = candidate.goal().infcx();
+        let param_env = candidate.goal().goal().param_env;
+        let body_id = self.obligation.cause.body_id;
+
+        for obligation in wf::unnormalized_obligations(infcx, param_env, arg, self.span(), body_id)
+            .into_iter()
+            .flatten()
+        {
+            let nested_goal = candidate.instantiate_proof_tree_for_nested_goal(
+                GoalSource::Misc,
+                Goal::new(infcx.tcx, obligation.param_env, obligation.predicate),
+                self.span(),
+            );
+            // Skip nested goals that aren't the *reason* for our goal's failure.
+            match (self.consider_ambiguities, nested_goal.result()) {
+                (true, Ok(Certainty::Maybe(MaybeCause::Ambiguity))) | (false, Err(_)) => {}
+                _ => continue,
+            }
+
+            self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?;
+        }
+
+        ControlFlow::Break(self.obligation.clone())
+    }
 }
 
 impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
@@ -283,6 +312,9 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
                     polarity: ty::PredicatePolarity::Positive,
                 }))
             }
+            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
+                return self.visit_well_formed_goal(candidate, arg);
+            }
             _ => ChildMode::PassThrough,
         };
 
@@ -355,12 +387,8 @@ 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(MaybeCause::Ambiguity))
-                ) => {}
-                false if matches!(nested_goal.result(), Err(_)) => {}
+            match (self.consider_ambiguities, nested_goal.result()) {
+                (true, Ok(Certainty::Maybe(MaybeCause::Ambiguity))) | (false, Err(_)) => {}
                 _ => continue,
             }
 
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
index e735020a63e..9ba48cd588f 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
@@ -194,47 +194,57 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
 
         let goals = instantiated_goals
             .into_iter()
-            .map(|(source, goal)| match goal.predicate.kind().no_bound_vars() {
-                Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })) => {
-                    let unconstrained_term = match term.unpack() {
-                        ty::TermKind::Ty(_) => infcx.next_ty_var(span).into(),
-                        ty::TermKind::Const(_) => infcx.next_const_var(span).into(),
-                    };
-                    let goal =
-                        goal.with(infcx.tcx, ty::NormalizesTo { alias, term: unconstrained_term });
-                    // We have to use a `probe` here as evaluating a `NormalizesTo` can constrain the
-                    // expected term. This means that candidates which only fail due to nested goals
-                    // and which normalize to a different term then the final result could ICE: when
-                    // building their proof tree, the expected term was unconstrained, but when
-                    // instantiating the candidate it is already constrained to the result of another
-                    // candidate.
-                    let proof_tree = infcx
-                        .probe(|_| infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes).1);
-                    InspectGoal::new(
-                        infcx,
-                        self.goal.depth + 1,
-                        proof_tree.unwrap(),
-                        Some(NormalizesToTermHack { term, unconstrained_term }),
-                        source,
-                    )
-                }
-                _ => {
-                    // We're using a probe here as evaluating a goal could constrain
-                    // inference variables by choosing one candidate. If we then recurse
-                    // into another candidate who ends up with different inference
-                    // constraints, we get an ICE if we already applied the constraints
-                    // from the chosen candidate.
-                    let proof_tree = infcx
-                        .probe(|_| infcx.evaluate_root_goal(goal, GenerateProofTree::Yes).1)
-                        .unwrap();
-                    InspectGoal::new(infcx, self.goal.depth + 1, proof_tree, None, source)
-                }
-            })
+            .map(|(source, goal)| self.instantiate_proof_tree_for_nested_goal(source, goal, span))
             .collect();
 
         (goals, opt_impl_args)
     }
 
+    pub fn instantiate_proof_tree_for_nested_goal(
+        &self,
+        source: GoalSource,
+        goal: Goal<'tcx, ty::Predicate<'tcx>>,
+        span: Span,
+    ) -> InspectGoal<'a, 'tcx> {
+        let infcx = self.goal.infcx;
+        match goal.predicate.kind().no_bound_vars() {
+            Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })) => {
+                let unconstrained_term = match term.unpack() {
+                    ty::TermKind::Ty(_) => infcx.next_ty_var(span).into(),
+                    ty::TermKind::Const(_) => infcx.next_const_var(span).into(),
+                };
+                let goal =
+                    goal.with(infcx.tcx, ty::NormalizesTo { alias, term: unconstrained_term });
+                // We have to use a `probe` here as evaluating a `NormalizesTo` can constrain the
+                // expected term. This means that candidates which only fail due to nested goals
+                // and which normalize to a different term then the final result could ICE: when
+                // building their proof tree, the expected term was unconstrained, but when
+                // instantiating the candidate it is already constrained to the result of another
+                // candidate.
+                let proof_tree =
+                    infcx.probe(|_| infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes).1);
+                InspectGoal::new(
+                    infcx,
+                    self.goal.depth + 1,
+                    proof_tree.unwrap(),
+                    Some(NormalizesToTermHack { term, unconstrained_term }),
+                    source,
+                )
+            }
+            _ => {
+                // We're using a probe here as evaluating a goal could constrain
+                // inference variables by choosing one candidate. If we then recurse
+                // into another candidate who ends up with different inference
+                // constraints, we get an ICE if we already applied the constraints
+                // from the chosen candidate.
+                let proof_tree = infcx
+                    .probe(|_| infcx.evaluate_root_goal(goal, GenerateProofTree::Yes).1)
+                    .unwrap();
+                InspectGoal::new(infcx, self.goal.depth + 1, proof_tree, None, source)
+            }
+        }
+    }
+
     /// Visit all nested goals of this candidate, rolling back
     /// all inference constraints.
     pub fn visit_nested_in_probe<V: ProofTreeVisitor<'tcx>>(&self, visitor: &mut V) -> V::Result {
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
index 1339739ce7f..ec0b7903396 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
@@ -5,8 +5,8 @@ use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds;
 use rustc_middle::infer::canonical::CanonicalQueryResponse;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFolder, TypeVisitableExt};
-use rustc_span::Span;
 use rustc_span::def_id::CRATE_DEF_ID;
+use rustc_span::{DUMMY_SP, Span};
 use rustc_type_ir::outlives::{Component, push_outlives_components};
 use smallvec::{SmallVec, smallvec};
 use tracing::debug;
@@ -92,7 +92,9 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
 
         // From the full set of obligations, just filter down to the region relationships.
         for obligation in
-            wf::unnormalized_obligations(ocx.infcx, param_env, arg).into_iter().flatten()
+            wf::unnormalized_obligations(ocx.infcx, param_env, arg, DUMMY_SP, CRATE_DEF_ID)
+                .into_iter()
+                .flatten()
         {
             assert!(!obligation.has_escaping_bound_vars());
             let Some(pred) = obligation.predicate.kind().no_bound_vars() else {
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 20b675bcb76..37d49cc2f55 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -8,8 +8,8 @@ use rustc_middle::ty::{
     self, GenericArg, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable,
     TypeVisitable, TypeVisitableExt, TypeVisitor,
 };
-use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
-use rustc_span::{DUMMY_SP, Span};
+use rustc_span::Span;
+use rustc_span::def_id::{DefId, LocalDefId};
 use tracing::{debug, instrument, trace};
 
 use crate::infer::InferCtxt;
@@ -89,6 +89,8 @@ pub fn unnormalized_obligations<'tcx>(
     infcx: &InferCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     arg: GenericArg<'tcx>,
+    span: Span,
+    body_id: LocalDefId,
 ) -> Option<PredicateObligations<'tcx>> {
     debug_assert_eq!(arg, infcx.resolve_vars_if_possible(arg));
 
@@ -106,8 +108,8 @@ pub fn unnormalized_obligations<'tcx>(
     let mut wf = WfPredicates {
         infcx,
         param_env,
-        body_id: CRATE_DEF_ID,
-        span: DUMMY_SP,
+        body_id,
+        span,
         out: PredicateObligations::new(),
         recursion_depth: 0,
         item: None,
diff --git a/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr b/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr
index bf53089675d..81ace4ebb6d 100644
--- a/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr
+++ b/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr
@@ -5,6 +5,8 @@ LL | fn main() -> Foo::Bar::<Vec<[u32]>> {}
    |                         ^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `[u32]`
+note: required by an implicit `Sized` bound in `Vec`
+  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/issues/issue-88119.stderr b/tests/ui/const-generics/issues/issue-88119.stderr
index f219c90849a..c497f1b6d0b 100644
--- a/tests/ui/const-generics/issues/issue-88119.stderr
+++ b/tests/ui/const-generics/issues/issue-88119.stderr
@@ -6,35 +6,29 @@ LL | #![feature(const_trait_impl, generic_const_exprs)]
    |
    = help: remove one of these features
 
-error[E0284]: type annotations needed: cannot normalize `<&T as ConstName>::{constant#0}`
-  --> $DIR/issue-88119.rs:19:49
+error[E0284]: type annotations needed: cannot satisfy `the constant `name_len::<T>()` can be evaluated`
+  --> $DIR/issue-88119.rs:21:5
    |
-LL | impl<T: ?Sized + ConstName> const ConstName for &T
-   |                                                 ^^ cannot normalize `<&T as ConstName>::{constant#0}`
+LL |     [(); name_len::<T>()]:,
+   |     ^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `name_len::<T>()` can be evaluated`
    |
-note: required for `&T` to implement `~const ConstName`
-  --> $DIR/issue-88119.rs:19:35
+note: required by a bound in `<&T as ConstName>`
+  --> $DIR/issue-88119.rs:21:10
    |
-LL | impl<T: ?Sized + ConstName> const ConstName for &T
-   |                                   ^^^^^^^^^     ^^
-LL | where
 LL |     [(); name_len::<T>()]:,
-   |     --------------------- unsatisfied trait bound introduced here
+   |          ^^^^^^^^^^^^^^^ required by this bound in `<&T as ConstName>`
 
-error[E0284]: type annotations needed: cannot normalize `<&mut T as ConstName>::{constant#0}`
-  --> $DIR/issue-88119.rs:26:49
+error[E0284]: type annotations needed: cannot satisfy `the constant `name_len::<T>()` can be evaluated`
+  --> $DIR/issue-88119.rs:28:5
    |
-LL | impl<T: ?Sized + ConstName> const ConstName for &mut T
-   |                                                 ^^^^^^ cannot normalize `<&mut T as ConstName>::{constant#0}`
+LL |     [(); name_len::<T>()]:,
+   |     ^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `name_len::<T>()` can be evaluated`
    |
-note: required for `&mut T` to implement `~const ConstName`
-  --> $DIR/issue-88119.rs:26:35
+note: required by a bound in `<&mut T as ConstName>`
+  --> $DIR/issue-88119.rs:28:10
    |
-LL | impl<T: ?Sized + ConstName> const ConstName for &mut T
-   |                                   ^^^^^^^^^     ^^^^^^
-LL | where
 LL |     [(); name_len::<T>()]:,
-   |     --------------------- unsatisfied trait bound introduced here
+   |          ^^^^^^^^^^^^^^^ required by this bound in `<&mut T as ConstName>`
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr
index 1b76669ccb0..4f685c508c7 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr
@@ -16,23 +16,13 @@ LL |     where
 LL |         T: AsExpression<Self::SqlType>,
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::check`
 
-error[E0277]: the trait bound `&str: AsExpression<Integer>` is not satisfied
-  --> $DIR/as_expression.rs:55:15
-   |
-LL |     SelectInt.check("bar");
-   |               ^^^^^ the trait `AsExpression<Integer>` is not implemented for `&str`
-   |
-   = help: the trait `AsExpression<Integer>` is not implemented for `&str`
-           but trait `AsExpression<Text>` is implemented for it
-   = help: for that trait implementation, expected `Text`, found `Integer`
-
 error[E0271]: type mismatch resolving `<SelectInt as Expression>::SqlType == Text`
   --> $DIR/as_expression.rs:55:5
    |
 LL |     SelectInt.check("bar");
    |     ^^^^^^^^^^^^^^^^^^^^^^ expected `Text`, found `Integer`
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0271, E0277.
 For more information about an error, try `rustc --explain E0271`.
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs
index 583b3c4675a..48c1ed2b02d 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs
@@ -53,7 +53,7 @@ impl<T> Foo for T where T: Expression {}
 
 fn main() {
     SelectInt.check("bar");
-    //~^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
-    //[next]~| the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
+    //[current]~^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
+    //[next]~^^ the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
     //[next]~| type mismatch
 }
diff --git a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr
index 1cfc2a6d944..a95670ced86 100644
--- a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr
+++ b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr
@@ -18,6 +18,11 @@ help: this trait has no implementations, consider adding one
    |
 LL | trait Foo {}
    | ^^^^^^^^^
+note: required by a bound in `A`
+  --> $DIR/alias-bounds-when-not-wf.rs:8:11
+   |
+LL | type A<T: Foo> = T;
+   |           ^^^ required by this bound in `A`
 
 error[E0277]: the trait bound `usize: Foo` is not satisfied
   --> $DIR/alias-bounds-when-not-wf.rs:16:10
diff --git a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
index 377dfc8b529..425f2d59222 100644
--- a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
+++ b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
@@ -1,8 +1,8 @@
-error[E0284]: type annotations needed: cannot normalize `X::{constant#0}`
+error[E0284]: type annotations needed: cannot satisfy `the constant `{ || {} }` can be evaluated`
   --> $DIR/const-region-infer-to-static-in-binder.rs:4:10
    |
 LL | struct X<const FN: fn() = { || {} }>;
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `X::{constant#0}`
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `{ || {} }` can be evaluated`
 
 error: using function pointers as const generic parameters is forbidden
   --> $DIR/const-region-infer-to-static-in-binder.rs:4:20
diff --git a/tests/ui/traits/next-solver/specialization-transmute.stderr b/tests/ui/traits/next-solver/specialization-transmute.stderr
index b96bfab927d..2d0c503bc95 100644
--- a/tests/ui/traits/next-solver/specialization-transmute.stderr
+++ b/tests/ui/traits/next-solver/specialization-transmute.stderr
@@ -10,11 +10,11 @@ LL | #![feature(specialization)]
 
 error: cannot normalize `<T as Default>::Id: '_`
 
-error[E0284]: type annotations needed: cannot normalize `<T as Default>::Id`
+error[E0282]: type annotations needed
   --> $DIR/specialization-transmute.rs:15:23
    |
 LL |     fn intu(&self) -> &Self::Id {
-   |                       ^^^^^^^^^ cannot normalize `<T as Default>::Id`
+   |                       ^^^^^^^^^ cannot infer type for reference `&<T as Default>::Id`
 
 error[E0284]: type annotations needed: cannot satisfy `<T as Default>::Id normalizes-to T`
   --> $DIR/specialization-transmute.rs:17:9
@@ -36,4 +36,5 @@ LL | fn transmute<T: Default<Id = U>, U: Copy>(t: T) -> U {
 
 error: aborting due to 4 previous errors; 1 warning emitted
 
-For more information about this error, try `rustc --explain E0284`.
+Some errors have detailed explanations: E0282, E0284.
+For more information about an error, try `rustc --explain E0282`.
diff --git a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.next.stderr b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.next.stderr
index 1bcc0dbaf67..92ad83c3300 100644
--- a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.next.stderr
+++ b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.next.stderr
@@ -9,6 +9,8 @@ error: the constant `N` is not of type `usize`
    |
 LL |     fn func<const N: u32>() -> [(); N];
    |                                ^^^^^^^ expected `usize`, found `u32`
+   |
+   = note: the length of array `[(); N]` must be type `usize`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/union/union-derive-eq.next.stderr b/tests/ui/union/union-derive-eq.next.stderr
index 3952b1f1284..151ceebe1ba 100644
--- a/tests/ui/union/union-derive-eq.next.stderr
+++ b/tests/ui/union/union-derive-eq.next.stderr
@@ -7,6 +7,8 @@ LL | union U2 {
 LL |     a: PartialEqNotEq,
    |     ^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `PartialEqNotEq`
    |
+note: required by a bound in `AssertParamIsEq`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
    = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider annotating `PartialEqNotEq` with `#[derive(Eq)]`
    |
diff --git a/tests/ui/wf/wf-normalization-sized.next.stderr b/tests/ui/wf/wf-normalization-sized.next.stderr
index 1e898fb7b78..83b56bb6b19 100644
--- a/tests/ui/wf/wf-normalization-sized.next.stderr
+++ b/tests/ui/wf/wf-normalization-sized.next.stderr
@@ -5,6 +5,7 @@ LL | const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = ();
    |           ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `[[[[[u8]]]]]`
+   = note: slice and array elements must have `Sized` type
 
 error[E0277]: the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time
   --> $DIR/wf-normalization-sized.rs:19:11
@@ -13,6 +14,7 @@ LL | const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = ();
    |           ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `[[[[[u8]]]]]`
+   = note: slice and array elements must have `Sized` type
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
@@ -22,6 +24,8 @@ LL | const _: <Vec<str> as WellUnformed>::RequestNormalize = ();
    |           ^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `str`
+note: required by an implicit `Sized` bound in `Vec`
+  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
   --> $DIR/wf-normalization-sized.rs:22:11
@@ -30,6 +34,8 @@ LL | const _: <Vec<str> as WellUnformed>::RequestNormalize = ();
    |           ^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `str`
+note: required by an implicit `Sized` bound in `Vec`
+  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: aborting due to 4 previous errors
diff --git a/tests/ui/wf/wf-trait-fn-arg.next.stderr b/tests/ui/wf/wf-trait-fn-arg.next.stderr
index c55dc5c8a12..d5dd36fad6d 100644
--- a/tests/ui/wf/wf-trait-fn-arg.next.stderr
+++ b/tests/ui/wf/wf-trait-fn-arg.next.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `Self: Eq` is not satisfied
 LL |     fn bar(&self, x: &Bar<Self>);
    |                       ^^^^^^^^^ the trait `Eq` is not implemented for `Self`
    |
+note: required by a bound in `Bar`
+  --> $DIR/wf-trait-fn-arg.rs:11:15
+   |
+LL | struct Bar<T: Eq + ?Sized> {
+   |               ^^ required by this bound in `Bar`
 help: consider further restricting `Self`
    |
 LL |     fn bar(&self, x: &Bar<Self>) where Self: Eq;
diff --git a/tests/ui/wf/wf-trait-fn-ret.next.stderr b/tests/ui/wf/wf-trait-fn-ret.next.stderr
index b3dca17672d..0ad786c2fd5 100644
--- a/tests/ui/wf/wf-trait-fn-ret.next.stderr
+++ b/tests/ui/wf/wf-trait-fn-ret.next.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `Self: Eq` is not satisfied
 LL |     fn bar(&self) -> &Bar<Self>;
    |                       ^^^^^^^^^ the trait `Eq` is not implemented for `Self`
    |
+note: required by a bound in `Bar`
+  --> $DIR/wf-trait-fn-ret.rs:10:15
+   |
+LL | struct Bar<T: Eq + ?Sized> {
+   |               ^^ required by this bound in `Bar`
 help: consider further restricting `Self`
    |
 LL |     fn bar(&self) -> &Bar<Self> where Self: Eq;
diff --git a/tests/ui/wf/wf-trait-fn-where-clause.next.stderr b/tests/ui/wf/wf-trait-fn-where-clause.next.stderr
index 8c8a5fa3e70..db5454d0f3c 100644
--- a/tests/ui/wf/wf-trait-fn-where-clause.next.stderr
+++ b/tests/ui/wf/wf-trait-fn-where-clause.next.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `Self: Eq` is not satisfied
 LL |         Bar<Self>: Copy;
    |                    ^^^^ the trait `Eq` is not implemented for `Self`
    |
+note: required by a bound in `Bar`
+  --> $DIR/wf-trait-fn-where-clause.rs:10:15
+   |
+LL | struct Bar<T: Eq + ?Sized> {
+   |               ^^ required by this bound in `Bar`
 help: consider further restricting `Self`
    |
 LL |         Bar<Self>: Copy, Self: Eq;