about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_infer/src/traits/engine.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs43
-rw-r--r--tests/crashes/139905.rs6
3 files changed, 28 insertions, 24 deletions
diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs
index 9e51a53ae95..9a66bd0574c 100644
--- a/compiler/rustc_infer/src/traits/engine.rs
+++ b/compiler/rustc_infer/src/traits/engine.rs
@@ -19,7 +19,8 @@ pub enum ScrubbedTraitError<'tcx> {
     TrueError,
     /// An ambiguity. This goal may hold if further inference is done.
     Ambiguity,
-    /// An old-solver-style cycle error, which will fatal.
+    /// An old-solver-style cycle error, which will fatal. This is not
+    /// returned by the new solver.
     Cycle(PredicateObligations<'tcx>),
 }
 
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 {
diff --git a/tests/crashes/139905.rs b/tests/crashes/139905.rs
deleted file mode 100644
index 7da622aaaba..00000000000
--- a/tests/crashes/139905.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//@ known-bug: #139905
-trait a<const b: bool> {}
-impl a<{}> for () {}
-trait c {}
-impl<const d: u8> c for () where (): a<d> {}
-impl c for () {}