Skip to content

Commit 228441d

Browse files
Use fulfillment in next trait solver coherence
1 parent bccb9bb commit 228441d

File tree

5 files changed

+97
-37
lines changed

5 files changed

+97
-37
lines changed

compiler/rustc_trait_selection/src/solve/inspect/analyse.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,10 @@ impl<'tcx> ProofTreeInferCtxtExt<'tcx> for InferCtxt<'tcx> {
230230
goal: Goal<'tcx, ty::Predicate<'tcx>>,
231231
visitor: &mut V,
232232
) -> ControlFlow<V::BreakTy> {
233-
let (_, proof_tree) = self.evaluate_root_goal(goal, GenerateProofTree::Yes);
234-
let proof_tree = proof_tree.unwrap();
235-
visitor.visit_goal(&InspectGoal::new(self, 0, &proof_tree))
233+
self.probe(|_| {
234+
let (_, proof_tree) = self.evaluate_root_goal(goal, GenerateProofTree::Yes);
235+
let proof_tree = proof_tree.unwrap();
236+
visitor.visit_goal(&InspectGoal::new(self, 0, &proof_tree))
237+
})
236238
}
237239
}

compiler/rustc_trait_selection/src/traits/coherence.rs

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

338342
/// Check if both impls can be satisfied by a common type by considering whether
@@ -522,15 +526,13 @@ fn try_prove_negated_where_clause<'tcx>(
522526
// Without this, we over-eagerly register coherence ambiguity candidates when
523527
// impl candidates do exist.
524528
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() {
529+
let mut fulfill_cx = FulfillmentCtxt::new(infcx);
530+
531+
fulfill_cx.register_predicate_obligation(
532+
infcx,
533+
Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, negative_predicate),
534+
);
535+
if !fulfill_cx.select_all_or_error(infcx).is_empty() {
534536
return false;
535537
}
536538

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() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//@ compile-flags: -Znext-solver=coherence
2+
3+
trait Mirror {
4+
type Assoc;
5+
}
6+
impl<T> Mirror for T {
7+
type Assoc = T;
8+
}
9+
10+
trait Foo {}
11+
12+
// Even though using fulfillment in coherence allows us to figure out that
13+
// `?T = ()`, we still treat it as incoherent because `(): Iterator` may be
14+
// added upstream.
15+
impl<T> Foo for T where (): Mirror<Assoc = T> {}
16+
//~^ NOTE first implementation here
17+
impl<T> Foo for T where T: Iterator {}
18+
//~^ ERROR conflicting implementations of trait `Foo` for type `()`
19+
//~| NOTE conflicting implementation for `()`
20+
//~| NOTE upstream crates may add a new impl of trait `std::iter::Iterator` for type `()` in future versions
21+
22+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0119]: conflicting implementations of trait `Foo` for type `()`
2+
--> $DIR/incoherent-even-though-we-fulfill.rs:17:1
3+
|
4+
LL | impl<T> Foo for T where (): Mirror<Assoc = T> {}
5+
| --------------------------------------------- first implementation here
6+
LL |
7+
LL | impl<T> Foo for T where T: Iterator {}
8+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()`
9+
|
10+
= note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `()` in future versions
11+
12+
error: aborting due to 1 previous error
13+
14+
For more information about this error, try `rustc --explain E0119`.

0 commit comments

Comments
 (0)