about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection/src
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2025-06-17 21:35:11 +0000
committerMichael Goulet <michael@errs.io>2025-06-25 15:32:08 +0000
commit83044357930a7c55f8d429bd4cd7dcb7426d4b01 (patch)
tree66fc514c8556f7d94e139b14c933a27095c645a6 /compiler/rustc_trait_selection/src
parent2801f9aaf9b7580d9b230b532b0700709857cc88 (diff)
Compute hard errors without diagnostics in impl_intersection_has_impossible_obligation
Diffstat (limited to 'compiler/rustc_trait_selection/src')
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs43
1 files changed, 26 insertions, 17 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 81893cdcc7e..ce5a4edeaaa 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -356,29 +356,38 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
             return IntersectionHasImpossibleObligations::Yes;
         }
 
-        let ocx = ObligationCtxt::new_with_diagnostics(infcx);
+        let ocx = ObligationCtxt::new(infcx);
         ocx.register_obligations(obligations.iter().cloned());
+        let hard_errors = ocx.select_where_possible();
+        if !hard_errors.is_empty() {
+            assert!(
+                hard_errors.iter().all(|e| e.is_true_error()),
+                "should not have detected ambiguity during first pass"
+            );
+            return IntersectionHasImpossibleObligations::Yes;
+        }
+
+        // Make a new `ObligationCtxt` and re-prove the ambiguities with a richer
+        // `FulfillmentError`. This is so that we can detect overflowing obligations
+        // without needing to run the `BestObligation` visitor on true errors.
+        let ambiguities = ocx.into_pending_obligations();
+        let ocx = ObligationCtxt::new_with_diagnostics(infcx);
+        ocx.register_obligations(ambiguities);
         let errors_and_ambiguities = ocx.select_all_or_error();
         // We only care about the obligations that are *definitely* true errors.
         // Ambiguities do not prove the disjointness of two impls.
         let (errors, ambiguities): (Vec<_>, Vec<_>) =
             errors_and_ambiguities.into_iter().partition(|error| error.is_true_error());
-
-        if errors.is_empty() {
-            IntersectionHasImpossibleObligations::No {
-                overflowing_predicates: ambiguities
-                    .into_iter()
-                    .filter(|error| {
-                        matches!(
-                            error.code,
-                            FulfillmentErrorCode::Ambiguity { overflow: Some(true) }
-                        )
-                    })
-                    .map(|e| infcx.resolve_vars_if_possible(e.obligation.predicate))
-                    .collect(),
-            }
-        } else {
-            IntersectionHasImpossibleObligations::Yes
+        assert!(errors.is_empty(), "should not have ambiguities during second pass");
+
+        IntersectionHasImpossibleObligations::No {
+            overflowing_predicates: ambiguities
+                .into_iter()
+                .filter(|error| {
+                    matches!(error.code, FulfillmentErrorCode::Ambiguity { overflow: Some(true) })
+                })
+                .map(|e| infcx.resolve_vars_if_possible(e.obligation.predicate))
+                .collect(),
         }
     } else {
         for obligation in obligations {