diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index 9e51a53ae95fa..9a66bd0574c9d 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 81893cdcc7e68..ce5a4edeaaa06 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 7da622aaabac6..0000000000000 --- a/tests/crashes/139905.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ known-bug: #139905 -trait a {} -impl a<{}> for () {} -trait c {} -impl c for () where (): a {} -impl c for () {}