Skip to content

Commit 121195a

Browse files
committed
wip, support intercrate_ambiguity_causes
1 parent c12e623 commit 121195a

File tree

4 files changed

+65
-25
lines changed

4 files changed

+65
-25
lines changed

compiler/rustc_trait_selection/src/solve/inspect.rs

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ use super::{EvalCtxt, GenerateProofTree, GoalEvaluationKind};
88

99
pub use rustc_middle::traits::solve::inspect::*;
1010

11+
pub(super) mod analyse;
12+
1113
#[derive(Eq, PartialEq, Debug, Hash, HashStable)]
1214
pub struct WipRootGoalEvaluation<'tcx> {
1315
goal: Goal<'tcx, ty::Predicate<'tcx>>,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
use rustc_data_structures::fx::FxIndexSet;
2+
use rustc_infer::{infer::InferCtxt, traits::PredicateObligation};
3+
use rustc_middle::traits::query::NoSolution;
4+
use rustc_middle::traits::solve::{Certainty, MaybeCause};
5+
use rustc_middle::traits::solve::inspect::RootGoalEvaluation;
6+
7+
use crate::solve::{InferCtxtEvalExt, GenerateProofTree, UseGlobalCache};
8+
use crate::traits::IntercrateAmbiguityCause;
9+
10+
pub(crate) fn compute_intercrate_ambiguity_causes<'tcx>(
11+
infcx: &InferCtxt<'tcx>,
12+
obligations: &[PredicateObligation<'tcx>],
13+
) -> FxIndexSet<IntercrateAmbiguityCause> {
14+
let mut causes: FxIndexSet<IntercrateAmbiguityCause> = Default::default();
15+
16+
for obligation in obligations {
17+
infcx.probe(|_| {
18+
let (result, proof_tree) = infcx.evaluate_root_goal(obligation.clone().into(), GenerateProofTree::Yes(UseGlobalCache::No));
19+
let proof_tree = proof_tree.unwrap();
20+
match result {
21+
Ok((_has_changed, certainty, _nested)) => {
22+
if certainty == Certainty::Maybe(MaybeCause::Ambiguity) {
23+
search_ambiguity_causes(proof_tree, &mut causes);
24+
}
25+
},
26+
Err(NoSolution) => unreachable!(),
27+
}
28+
})
29+
}
30+
31+
causes
32+
}
33+
34+
fn search_ambiguity_causes<'tcx>(proof_tree: RootGoalEvaluation<'tcx>, causes: &mut FxIndexSet<IntercrateAmbiguityCause>) {
35+
// TODO
36+
}

compiler/rustc_trait_selection/src/solve/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ pub use eval_ctxt::{
4444
EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt, UseGlobalCache,
4545
};
4646
pub use fulfill::FulfillmentCtxt;
47+
pub(crate) use inspect::analyse::compute_intercrate_ambiguity_causes;
4748
pub(crate) use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes};
4849

4950
#[derive(Debug, Clone, Copy)]

compiler/rustc_trait_selection/src/traits/coherence.rs

+26-25
Original file line numberDiff line numberDiff line change
@@ -204,18 +204,25 @@ fn overlap<'tcx>(
204204

205205
// Equate the headers to find their intersection (the general type, with infer vars,
206206
// that may apply both impls).
207-
let equate_obligations = equate_impl_headers(selcx.infcx, &impl1_header, &impl2_header)?;
207+
let mut obligations = equate_impl_headers(selcx.infcx, &impl1_header, &impl2_header)?;
208208
debug!("overlap: unification check succeeded");
209209

210-
if overlap_mode.use_implicit_negative()
211-
&& impl_intersection_has_impossible_obligation(
212-
selcx,
213-
param_env,
214-
&impl1_header,
215-
impl2_header,
216-
equate_obligations,
217-
)
218-
{
210+
if !overlap_mode.use_implicit_negative() {
211+
let impl_header = selcx.infcx.resolve_vars_if_possible(impl1_header);
212+
return Some(OverlapResult {
213+
impl_header,
214+
intercrate_ambiguity_causes: Default::default(),
215+
involves_placeholder: false,
216+
});
217+
};
218+
219+
obligations.extend(
220+
[&impl1_header.predicates, &impl2_header.predicates].into_iter().flatten().map(
221+
|&predicate| Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, predicate),
222+
),
223+
);
224+
225+
if impl_intersection_has_impossible_obligation(selcx, &obligations) {
219226
return None;
220227
}
221228

@@ -226,7 +233,12 @@ fn overlap<'tcx>(
226233
return None;
227234
}
228235

229-
let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes();
236+
let intercrate_ambiguity_causes = if infcx.next_trait_solver() {
237+
crate::solve::compute_intercrate_ambiguity_causes(&infcx, &obligations)
238+
} else {
239+
selcx.take_intercrate_ambiguity_causes()
240+
};
241+
230242
debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes);
231243
let involves_placeholder = infcx
232244
.inner
@@ -282,14 +294,11 @@ fn equate_impl_headers<'tcx>(
282294
/// Importantly, this works even if there isn't a `impl !Error for MyLocalType`.
283295
fn impl_intersection_has_impossible_obligation<'cx, 'tcx>(
284296
selcx: &mut SelectionContext<'cx, 'tcx>,
285-
param_env: ty::ParamEnv<'tcx>,
286-
impl1_header: &ty::ImplHeader<'tcx>,
287-
impl2_header: ty::ImplHeader<'tcx>,
288-
obligations: PredicateObligations<'tcx>,
297+
obligations: &[PredicateObligation<'tcx>],
289298
) -> bool {
290299
let infcx = selcx.infcx;
291300

292-
let obligation_guaranteed_to_fail = move |obligation: &PredicateObligation<'tcx>| {
301+
let obligation_guaranteed_to_fail = move |obligation: &&PredicateObligation<'tcx>| {
293302
if infcx.next_trait_solver() {
294303
infcx.evaluate_obligation(obligation).map_or(false, |result| !result.may_apply())
295304
} else {
@@ -303,15 +312,7 @@ fn impl_intersection_has_impossible_obligation<'cx, 'tcx>(
303312
}
304313
};
305314

306-
let opt_failing_obligation = [&impl1_header.predicates, &impl2_header.predicates]
307-
.into_iter()
308-
.flatten()
309-
.map(|&predicate| {
310-
Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, predicate)
311-
})
312-
.chain(obligations)
313-
.find(obligation_guaranteed_to_fail);
314-
315+
let opt_failing_obligation = obligations.iter().find(obligation_guaranteed_to_fail);
315316
if let Some(failing_obligation) = opt_failing_obligation {
316317
debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
317318
true

0 commit comments

Comments
 (0)