Skip to content

Commit 9bbdd9e

Browse files
Use fulfillment in next trait solver coherence
1 parent ae9d7b0 commit 9bbdd9e

File tree

2 files changed

+58
-34
lines changed

2 files changed

+58
-34
lines changed

compiler/rustc_trait_selection/src/traits/coherence.rs

+38-34
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,21 @@ use crate::infer::outlives::env::OutlivesEnvironment;
88
use crate::infer::InferOk;
99
use crate::regions::InferCtxtRegionExt;
1010
use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
11-
use crate::solve::{deeply_normalize_for_diagnostics, inspect};
12-
use crate::traits::engine::TraitEngineExt;
13-
use crate::traits::query::evaluate_obligation::InferCtxtExt;
11+
use crate::solve::{deeply_normalize_for_diagnostics, inspect, FulfillmentCtxt};
12+
use crate::traits::engine::TraitEngineExt as _;
1413
use crate::traits::select::IntercrateAmbiguityCause;
1514
use crate::traits::structural_normalize::StructurallyNormalizeExt;
1615
use crate::traits::NormalizeExt;
1716
use crate::traits::SkipLeakCheck;
1817
use crate::traits::{
19-
Obligation, ObligationCause, ObligationCtxt, PredicateObligation, PredicateObligations,
20-
SelectionContext,
18+
Obligation, ObligationCause, PredicateObligation, PredicateObligations, SelectionContext,
2119
};
2220
use rustc_data_structures::fx::FxIndexSet;
2321
use rustc_errors::Diagnostic;
2422
use rustc_hir::def::DefKind;
2523
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
2624
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
27-
use rustc_infer::traits::{util, TraitEngine};
25+
use rustc_infer::traits::{util, TraitEngine, TraitEngineExt};
2826
use rustc_middle::traits::query::NoSolution;
2927
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal};
3028
use rustc_middle::traits::specialization_graph::OverlapMode;
@@ -310,29 +308,37 @@ fn equate_impl_headers<'tcx>(
310308
fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
311309
selcx: &mut SelectionContext<'cx, 'tcx>,
312310
obligations: &'a [PredicateObligation<'tcx>],
313-
) -> Option<&'a PredicateObligation<'tcx>> {
311+
) -> Option<PredicateObligation<'tcx>> {
314312
let infcx = selcx.infcx;
315313

316-
obligations.iter().find(|obligation| {
317-
let evaluation_result = if infcx.next_trait_solver() {
318-
infcx.evaluate_obligation(obligation)
319-
} else {
314+
if infcx.next_trait_solver() {
315+
infcx.probe(|_| {
316+
let mut fulfill_cx = FulfillmentCtxt::new(infcx);
317+
fulfill_cx.register_predicate_obligations(infcx, obligations.iter().cloned());
318+
319+
// We only care about the obligations that are *definitely* true errors.
320+
// Ambiguities do not prove the disjointness of two impls.
321+
let mut errors = fulfill_cx.select_where_possible(infcx);
322+
errors.pop().map(|err| err.obligation)
323+
})
324+
} else {
325+
obligations.iter().cloned().find(|obligation| {
320326
// We use `evaluate_root_obligation` to correctly track intercrate
321327
// ambiguity clauses. We cannot use this in the new solver.
322-
selcx.evaluate_root_obligation(obligation)
323-
};
324-
325-
match evaluation_result {
326-
Ok(result) => !result.may_apply(),
327-
// If overflow occurs, we need to conservatively treat the goal as possibly holding,
328-
// since there can be instantiations of this goal that don't overflow and result in
329-
// success. This isn't much of a problem in the old solver, since we treat overflow
330-
// fatally (this still can be encountered: <https://github.com/rust-lang/rust/issues/105231>),
331-
// but in the new solver, this is very important for correctness, since overflow
332-
// *must* be treated as ambiguity for completeness.
333-
Err(_overflow) => false,
334-
}
335-
})
328+
let evaluation_result = selcx.evaluate_root_obligation(obligation);
329+
330+
match evaluation_result {
331+
Ok(result) => !result.may_apply(),
332+
// If overflow occurs, we need to conservatively treat the goal as possibly holding,
333+
// since there can be instantiations of this goal that don't overflow and result in
334+
// success. This isn't much of a problem in the old solver, since we treat overflow
335+
// fatally (this still can be encountered: <https://github.com/rust-lang/rust/issues/105231>),
336+
// but in the new solver, this is very important for correctness, since overflow
337+
// *must* be treated as ambiguity for completeness.
338+
Err(_overflow) => false,
339+
}
340+
})
341+
}
336342
}
337343

338344
/// Check if both impls can be satisfied by a common type by considering whether
@@ -522,15 +528,13 @@ fn try_prove_negated_where_clause<'tcx>(
522528
// Without this, we over-eagerly register coherence ambiguity candidates when
523529
// impl candidates do exist.
524530
let ref infcx = root_infcx.fork_with_intercrate(false);
525-
let ocx = ObligationCtxt::new(infcx);
526-
527-
ocx.register_obligation(Obligation::new(
528-
infcx.tcx,
529-
ObligationCause::dummy(),
530-
param_env,
531-
negative_predicate,
532-
));
533-
if !ocx.select_all_or_error().is_empty() {
531+
let mut fulfill_cx = FulfillmentCtxt::new(infcx);
532+
533+
fulfill_cx.register_predicate_obligation(
534+
infcx,
535+
Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, negative_predicate),
536+
);
537+
if !fulfill_cx.select_all_or_error(infcx).is_empty() {
534538
return false;
535539
}
536540

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// compile-flags: -Znext-solver=coherence
2+
// check-pass
3+
4+
trait Mirror {
5+
type Assoc;
6+
}
7+
impl<T> Mirror for T {
8+
type Assoc = T;
9+
}
10+
11+
trait Foo {}
12+
trait Bar {}
13+
14+
// self type starts out as `?0` but is constrained to `()`
15+
// due to the where clause below. Because `(): Bar` does not
16+
// hold in intercrate mode, we can prove the impls disjoint.
17+
impl<T> Foo for T where (): Mirror<Assoc = T> {}
18+
impl<T> Foo for T where T: Bar {}
19+
20+
fn main() {}

0 commit comments

Comments
 (0)