From 398fd901d5f8afa982eeb0f9318d9d0e4e791f44 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Wed, 27 Nov 2024 21:27:37 +0000
Subject: [PATCH] Assert that obligations are empty before deeply normalizing

---
 .../src/obligation_forest/mod.rs                    |  4 ++++
 compiler/rustc_hir_analysis/src/check/wfcheck.rs    |  3 +--
 compiler/rustc_infer/src/traits/engine.rs           |  2 ++
 compiler/rustc_trait_selection/src/solve/fulfill.rs |  4 ++++
 .../rustc_trait_selection/src/traits/fulfill.rs     |  4 ++++
 .../rustc_trait_selection/src/traits/normalize.rs   |  9 +++++++++
 .../traits/query/type_op/implied_outlives_bounds.rs |  3 +++
 .../ui/higher-ranked/structually-relate-aliases.rs  |  1 -
 .../higher-ranked/structually-relate-aliases.stderr | 13 +------------
 .../in-trait/alias-bounds-when-not-wf.stderr        |  4 ++--
 .../traits/next-solver/issue-118950-root-region.rs  |  2 +-
 .../next-solver/issue-118950-root-region.stderr     | 13 ++++++-------
 12 files changed, 37 insertions(+), 25 deletions(-)

diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
index 34a2464972a..78d69a66edc 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
@@ -415,6 +415,10 @@ impl<O: ForestObligation> ObligationForest<O> {
             .collect()
     }
 
+    pub fn has_pending_obligations(&self) -> bool {
+        self.nodes.iter().any(|node| node.state.get() == NodeState::Pending)
+    }
+
     fn insert_into_error_cache(&mut self, index: usize) {
         let node = &self.nodes[index];
         self.error_cache
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 8fa797db246..68045403932 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -116,13 +116,12 @@ where
     }
     f(&mut wfcx)?;
 
-    let assumed_wf_types = wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id)?;
-
     let errors = wfcx.select_all_or_error();
     if !errors.is_empty() {
         return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
     }
 
+    let assumed_wf_types = wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id)?;
     debug!(?assumed_wf_types);
 
     let infcx_compat = infcx.fork();
diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs
index ba1516655b0..51282b900ed 100644
--- a/compiler/rustc_infer/src/traits/engine.rs
+++ b/compiler/rustc_infer/src/traits/engine.rs
@@ -84,6 +84,8 @@ pub trait TraitEngine<'tcx, E: 'tcx>: 'tcx {
         self.collect_remaining_errors(infcx)
     }
 
+    fn has_pending_obligations(&self) -> bool;
+
     fn pending_obligations(&self) -> PredicateObligations<'tcx>;
 
     /// Among all pending obligations, collect those are stalled on a inference variable which has
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index 0f90c45d032..2b2623a050e 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -199,6 +199,10 @@ where
         errors
     }
 
+    fn has_pending_obligations(&self) -> bool {
+        !self.obligations.pending.is_empty() || !self.obligations.overflowed.is_empty()
+    }
+
     fn pending_obligations(&self) -> PredicateObligations<'tcx> {
         self.obligations.clone_pending()
     }
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 03e483f555d..7529ee128f5 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -213,6 +213,10 @@ where
         }
     }
 
+    fn has_pending_obligations(&self) -> bool {
+        self.predicates.has_pending_obligations()
+    }
+
     fn pending_obligations(&self) -> PredicateObligations<'tcx> {
         self.predicates.map_pending_obligations(|o| o.obligation.clone())
     }
diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs
index 2891df3ed2d..ad62b456ad4 100644
--- a/compiler/rustc_trait_selection/src/traits/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/normalize.rs
@@ -7,6 +7,7 @@ use rustc_infer::traits::{
     FromSolverError, Normalized, Obligation, PredicateObligations, TraitEngine,
 };
 use rustc_macros::extension;
+use rustc_middle::span_bug;
 use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::{
     self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt,
@@ -63,6 +64,14 @@ impl<'tcx> At<'_, 'tcx> {
         if self.infcx.next_trait_solver() {
             crate::solve::deeply_normalize(self, value)
         } else {
+            if fulfill_cx.has_pending_obligations() {
+                let pending_obligations = fulfill_cx.pending_obligations();
+                span_bug!(
+                    pending_obligations[0].cause.span,
+                    "deeply_normalize should not be called with pending obligations: \
+                    {pending_obligations:#?}"
+                );
+            }
             let value = self
                 .normalize(value)
                 .into_value_registering_obligations(self.infcx, &mut *fulfill_cx);
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 224a7271472..fe47e837dfb 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
@@ -60,6 +60,9 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
     ty: Ty<'tcx>,
 ) -> Result<Vec<OutlivesBound<'tcx>>, NoSolution> {
     let normalize_op = |ty| -> Result<_, NoSolution> {
+        // We must normalize the type so we can compute the right outlives components.
+        // for example, if we have some constrained param type like `T: Trait<Out = U>`,
+        // and we know that `&'a T::Out` is WF, then we want to imply `U: 'a`.
         let ty = ocx
             .deeply_normalize(&ObligationCause::dummy(), param_env, ty)
             .map_err(|_| NoSolution)?;
diff --git a/tests/ui/higher-ranked/structually-relate-aliases.rs b/tests/ui/higher-ranked/structually-relate-aliases.rs
index 73c2cd23d86..1ed3767643a 100644
--- a/tests/ui/higher-ranked/structually-relate-aliases.rs
+++ b/tests/ui/higher-ranked/structually-relate-aliases.rs
@@ -12,6 +12,5 @@ impl<T> Overlap<T> for T {}
 
 impl<T> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T {}
 //~^ ERROR the trait bound `for<'a> T: ToUnit<'a>` is not satisfied
-//~| ERROR the trait bound `for<'a> T: ToUnit<'a>` is not satisfied
 
 fn main() {}
diff --git a/tests/ui/higher-ranked/structually-relate-aliases.stderr b/tests/ui/higher-ranked/structually-relate-aliases.stderr
index e9d91e45e21..cf3e4cc85b9 100644
--- a/tests/ui/higher-ranked/structually-relate-aliases.stderr
+++ b/tests/ui/higher-ranked/structually-relate-aliases.stderr
@@ -10,17 +10,6 @@ help: consider restricting type parameter `T`
 LL | impl<T: for<'a> ToUnit<'a>> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T {}
    |       ++++++++++++++++++++
 
-error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied
-  --> $DIR/structually-relate-aliases.rs:13:17
-   |
-LL | impl<T> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T {}
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `T`
-   |
-help: consider restricting type parameter `T`
-   |
-LL | impl<T: for<'a> ToUnit<'a>> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T {}
-   |       ++++++++++++++++++++
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0277`.
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 79581066a3a..1cfc2a6d944 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
@@ -8,10 +8,10 @@ LL | #![feature(lazy_type_alias)]
    = note: `#[warn(incomplete_features)]` on by default
 
 error[E0277]: the trait bound `usize: Foo` is not satisfied
-  --> $DIR/alias-bounds-when-not-wf.rs:16:13
+  --> $DIR/alias-bounds-when-not-wf.rs:16:15
    |
 LL | fn hello(_: W<A<usize>>) {}
-   |             ^^^^^^^^^^^ the trait `Foo` is not implemented for `usize`
+   |               ^^^^^^^^ the trait `Foo` is not implemented for `usize`
    |
 help: this trait has no implementations, consider adding one
   --> $DIR/alias-bounds-when-not-wf.rs:6:1
diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.rs b/tests/ui/traits/next-solver/issue-118950-root-region.rs
index e1bd234a275..8fe53d6773b 100644
--- a/tests/ui/traits/next-solver/issue-118950-root-region.rs
+++ b/tests/ui/traits/next-solver/issue-118950-root-region.rs
@@ -18,6 +18,6 @@ impl<T> Overlap<T> for T {}
 
 impl<T> Overlap<for<'a> fn(Assoc<'a, T>)> for T where Missing: Overlap<T> {}
 //~^ ERROR cannot find type `Missing` in this scope
-//~| ERROR the trait bound `for<'a> *const T: ToUnit<'a>` is not satisfied
+//~| ERROR the trait bound `T: Overlap<for<'a> fn(Assoc<'a, T>)>` is not satisfied
 
 fn main() {}
diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.stderr b/tests/ui/traits/next-solver/issue-118950-root-region.stderr
index f6545c6ebf9..09162970d33 100644
--- a/tests/ui/traits/next-solver/issue-118950-root-region.stderr
+++ b/tests/ui/traits/next-solver/issue-118950-root-region.stderr
@@ -26,17 +26,16 @@ LL | trait ToUnit<'a> {
    | ^^^^^^^^^^^^^^^^
 
  WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), .. }
-error[E0277]: the trait bound `for<'a> *const T: ToUnit<'a>` is not satisfied
-  --> $DIR/issue-118950-root-region.rs:19:17
+error[E0277]: the trait bound `T: Overlap<for<'a> fn(Assoc<'a, T>)>` is not satisfied
+  --> $DIR/issue-118950-root-region.rs:19:47
    |
 LL | impl<T> Overlap<for<'a> fn(Assoc<'a, T>)> for T where Missing: Overlap<T> {}
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `*const T`
+   |                                               ^ the trait `Overlap<for<'a> fn(Assoc<'a, T>)>` is not implemented for `T`
    |
-help: this trait has no implementations, consider adding one
-  --> $DIR/issue-118950-root-region.rs:8:1
+help: consider further restricting type parameter `T`
    |
-LL | trait ToUnit<'a> {
-   | ^^^^^^^^^^^^^^^^
+LL | impl<T> Overlap<for<'a> fn(Assoc<'a, T>)> for T where Missing: Overlap<T>, T: Overlap<for<'a> fn(Assoc<'a, T>)> {}
+   |                                                                          ++++++++++++++++++++++++++++++++++++++
 
 error: aborting due to 3 previous errors; 1 warning emitted