Skip to content

Commit af8db51

Browse files
committed
move coherence stuff out of analyse
1 parent 028d9cc commit af8db51

File tree

4 files changed

+147
-155
lines changed

4 files changed

+147
-155
lines changed

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

+2-146
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,13 @@
11
use std::ops::ControlFlow;
22

3-
use rustc_data_structures::fx::FxIndexSet;
4-
use rustc_infer::traits::TraitEngine;
5-
use rustc_infer::{infer::InferCtxt, traits::PredicateObligation};
3+
use rustc_infer::infer::InferCtxt;
64
use rustc_middle::traits::query::NoSolution;
75
use rustc_middle::traits::solve::{inspect, QueryResult};
86
use rustc_middle::traits::solve::{Certainty, Goal};
9-
use rustc_middle::traits::ObligationCause;
10-
use rustc_middle::ty::print::with_no_trimmed_paths;
11-
use rustc_middle::ty::TypeVisitableExt;
12-
use rustc_middle::ty::{self, Ty};
7+
use rustc_middle::ty;
138

149
use crate::solve::inspect::ProofTreeBuilder;
1510
use crate::solve::{GenerateProofTree, InferCtxtEvalExt, UseGlobalCache};
16-
use crate::traits::coherence::{self, Conflict};
17-
use crate::traits::TraitEngineExt;
18-
use crate::traits::{IntercrateAmbiguityCause, StructurallyNormalizeExt};
1911

2012
pub struct InspectGoal<'a, 'tcx> {
2113
infcx: &'a InferCtxt<'tcx>,
@@ -216,139 +208,3 @@ impl<'tcx> ProofTreeInferCtxtExt<'tcx> for InferCtxt<'tcx> {
216208
visitor.visit_goal(&InspectGoal::new(self, 0, &proof_tree))
217209
}
218210
}
219-
220-
pub(crate) fn compute_intercrate_ambiguity_causes<'tcx>(
221-
infcx: &InferCtxt<'tcx>,
222-
obligations: &[PredicateObligation<'tcx>],
223-
) -> FxIndexSet<IntercrateAmbiguityCause> {
224-
let mut causes: FxIndexSet<IntercrateAmbiguityCause> = Default::default();
225-
226-
for obligation in obligations {
227-
infcx.probe(|_| {
228-
search_ambiguity_causes(infcx, obligation.clone().into(), &mut causes);
229-
})
230-
}
231-
232-
causes
233-
}
234-
235-
struct AmbiguityCausesVisitor<'a> {
236-
causes: &'a mut FxIndexSet<IntercrateAmbiguityCause>,
237-
}
238-
239-
impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a> {
240-
type BreakTy = !;
241-
fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) -> ControlFlow<Self::BreakTy> {
242-
let infcx = goal.infcx();
243-
for cand in goal.candidates() {
244-
cand.visit_nested(self)?;
245-
}
246-
// When searching for intercrate ambiguity causes, we only need to look
247-
// at ambiguous goals, as for others the coherence unknowable candidate
248-
// was irrelevant.
249-
match goal.result() {
250-
Ok(Certainty::Maybe(_)) => {}
251-
Ok(Certainty::Yes) | Err(NoSolution) => return ControlFlow::Continue(()),
252-
}
253-
254-
let Goal { param_env, predicate } = goal.goal();
255-
256-
let trait_ref = match predicate.kind().no_bound_vars() {
257-
Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr))) => tr.trait_ref,
258-
Some(ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj))) => {
259-
proj.projection_ty.trait_ref(infcx.tcx)
260-
}
261-
_ => return ControlFlow::Continue(()),
262-
};
263-
264-
let mut ambiguity_cause = None;
265-
for cand in goal.candidates() {
266-
match cand.result() {
267-
Ok(Certainty::Maybe(_)) => {}
268-
// We only add intercrate ambiguity causes if the goal would
269-
// otherwise result in an error.
270-
//
271-
// FIXME: this isn't quite right. Changing a goal from YES with
272-
// inference contraints to AMBIGUOUS can also cause a goal to not
273-
// fail.
274-
Ok(Certainty::Yes) => {
275-
ambiguity_cause = None;
276-
break;
277-
}
278-
Err(NoSolution) => continue,
279-
}
280-
281-
// FIXME: boiiii, using string comparisions here sure is scuffed.
282-
if let inspect::ProbeKind::MiscCandidate { name: "coherence unknowable", result: _ } =
283-
cand.kind()
284-
{
285-
let lazily_normalize_ty = |ty: Ty<'tcx>| {
286-
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(infcx);
287-
if matches!(ty.kind(), ty::Alias(..)) {
288-
match infcx
289-
.at(&ObligationCause::dummy(), param_env)
290-
.structurally_normalize(ty, &mut *fulfill_cx)
291-
{
292-
Ok(ty) => Ok(ty),
293-
Err(_errs) => Err(()),
294-
}
295-
} else {
296-
Ok(ty)
297-
}
298-
};
299-
300-
infcx.probe(|_| {
301-
match coherence::trait_ref_is_knowable(
302-
infcx.tcx,
303-
trait_ref,
304-
lazily_normalize_ty,
305-
) {
306-
Err(()) => {}
307-
Ok(Ok(())) => warn!("expected an unknowable trait ref: {trait_ref:?}"),
308-
Ok(Err(conflict)) => {
309-
let trait_ref = infcx.resolve_vars_if_possible(trait_ref);
310-
if !trait_ref.references_error() {
311-
let self_ty = trait_ref.self_ty();
312-
let (trait_desc, self_desc) = with_no_trimmed_paths!({
313-
let trait_desc = trait_ref.print_only_trait_path().to_string();
314-
let self_desc = self_ty
315-
.has_concrete_skeleton()
316-
.then(|| self_ty.to_string());
317-
(trait_desc, self_desc)
318-
});
319-
ambiguity_cause = Some(match conflict {
320-
Conflict::Upstream => {
321-
IntercrateAmbiguityCause::UpstreamCrateUpdate {
322-
trait_desc,
323-
self_desc,
324-
}
325-
}
326-
Conflict::Downstream => {
327-
IntercrateAmbiguityCause::DownstreamCrate {
328-
trait_desc,
329-
self_desc,
330-
}
331-
}
332-
});
333-
}
334-
}
335-
}
336-
})
337-
}
338-
}
339-
340-
if let Some(ambiguity_cause) = ambiguity_cause {
341-
self.causes.insert(ambiguity_cause);
342-
}
343-
344-
ControlFlow::Continue(())
345-
}
346-
}
347-
348-
fn search_ambiguity_causes<'tcx>(
349-
infcx: &InferCtxt<'tcx>,
350-
goal: Goal<'tcx, ty::Predicate<'tcx>>,
351-
causes: &mut FxIndexSet<IntercrateAmbiguityCause>,
352-
) {
353-
infcx.visit_proof_tree(goal, &mut AmbiguityCausesVisitor { causes });
354-
}
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
pub use rustc_middle::traits::solve::inspect::*;
22

3-
pub(in crate::solve) mod build;
3+
mod build;
44
pub(in crate::solve) use build::*;
55

6-
pub mod analyse;
6+
mod analyse;
77
pub use analyse::*;

compiler/rustc_trait_selection/src/solve/mod.rs

-2
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,6 @@ pub use eval_ctxt::{
4545
EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt, UseGlobalCache,
4646
};
4747
pub use fulfill::FulfillmentCtxt;
48-
pub(crate) use inspect::analyse::compute_intercrate_ambiguity_causes;
49-
pub use inspect::analyse::{InspectCandidate, InspectGoal, ProofTreeInferCtxtExt};
5048
pub(crate) use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes};
5149

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

compiler/rustc_trait_selection/src/traits/coherence.rs

+143-5
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,15 @@
66
77
use crate::infer::outlives::env::OutlivesEnvironment;
88
use crate::infer::InferOk;
9+
use crate::solve::inspect;
10+
use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
11+
use crate::traits::engine::TraitEngineExt;
912
use crate::traits::outlives_bounds::InferCtxtExt as _;
13+
use crate::traits::query::evaluate_obligation::InferCtxtExt;
1014
use crate::traits::select::{IntercrateAmbiguityCause, TreatInductiveCycleAs};
15+
use crate::traits::structural_normalize::StructurallyNormalizeExt;
1116
use crate::traits::util::impl_subject_and_oblig;
17+
use crate::traits::NormalizeExt;
1218
use crate::traits::SkipLeakCheck;
1319
use crate::traits::{
1420
self, Obligation, ObligationCause, ObligationCtxt, PredicateObligation, PredicateObligations,
@@ -18,10 +24,13 @@ use rustc_data_structures::fx::FxIndexSet;
1824
use rustc_errors::Diagnostic;
1925
use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
2026
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
21-
use rustc_infer::traits::util;
27+
use rustc_infer::traits::{util, TraitEngine};
28+
use rustc_middle::traits::query::NoSolution;
29+
use rustc_middle::traits::solve::{Certainty, Goal};
2230
use rustc_middle::traits::specialization_graph::OverlapMode;
2331
use rustc_middle::traits::DefiningAnchor;
2432
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
33+
use rustc_middle::ty::print::with_no_trimmed_paths;
2534
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
2635
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
2736
use rustc_session::lint::builtin::COINDUCTIVE_OVERLAP_IN_COHERENCE;
@@ -31,9 +40,6 @@ use std::fmt::Debug;
3140
use std::iter;
3241
use std::ops::ControlFlow;
3342

34-
use super::query::evaluate_obligation::InferCtxtExt;
35-
use super::NormalizeExt;
36-
3743
/// Whether we do the orphan check relative to this crate or
3844
/// to some remote crate.
3945
#[derive(Copy, Clone, Debug)]
@@ -289,7 +295,7 @@ fn overlap<'tcx>(
289295
}
290296

291297
let intercrate_ambiguity_causes = if infcx.next_trait_solver() {
292-
crate::solve::compute_intercrate_ambiguity_causes(&infcx, &obligations)
298+
compute_intercrate_ambiguity_causes(&infcx, &obligations)
293299
} else {
294300
selcx.take_intercrate_ambiguity_causes()
295301
};
@@ -884,3 +890,135 @@ where
884890
ControlFlow::Continue(())
885891
}
886892
}
893+
894+
/// Compute the `intercrate_ambiguity_causes` for the new solver using
895+
/// "proof trees".
896+
fn compute_intercrate_ambiguity_causes<'tcx>(
897+
infcx: &InferCtxt<'tcx>,
898+
obligations: &[PredicateObligation<'tcx>],
899+
) -> FxIndexSet<IntercrateAmbiguityCause> {
900+
let mut causes: FxIndexSet<IntercrateAmbiguityCause> = Default::default();
901+
902+
for obligation in obligations {
903+
search_ambiguity_causes(infcx, obligation.clone().into(), &mut causes);
904+
}
905+
906+
causes
907+
}
908+
909+
struct AmbiguityCausesVisitor<'a> {
910+
causes: &'a mut FxIndexSet<IntercrateAmbiguityCause>,
911+
}
912+
913+
impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a> {
914+
type BreakTy = !;
915+
fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) -> ControlFlow<Self::BreakTy> {
916+
let infcx = goal.infcx();
917+
for cand in goal.candidates() {
918+
cand.visit_nested(self)?;
919+
}
920+
// When searching for intercrate ambiguity causes, we only need to look
921+
// at ambiguous goals, as for others the coherence unknowable candidate
922+
// was irrelevant.
923+
match goal.result() {
924+
Ok(Certainty::Maybe(_)) => {}
925+
Ok(Certainty::Yes) | Err(NoSolution) => return ControlFlow::Continue(()),
926+
}
927+
928+
let Goal { param_env, predicate } = goal.goal();
929+
930+
let trait_ref = match predicate.kind().no_bound_vars() {
931+
Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr))) => tr.trait_ref,
932+
Some(ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj))) => {
933+
proj.projection_ty.trait_ref(infcx.tcx)
934+
}
935+
_ => return ControlFlow::Continue(()),
936+
};
937+
938+
let mut ambiguity_cause = None;
939+
for cand in goal.candidates() {
940+
match cand.result() {
941+
Ok(Certainty::Maybe(_)) => {}
942+
// We only add intercrate ambiguity causes if the goal would
943+
// otherwise result in an error.
944+
//
945+
// FIXME: this isn't quite right. Changing a goal from YES with
946+
// inference contraints to AMBIGUOUS can also cause a goal to not
947+
// fail.
948+
Ok(Certainty::Yes) => {
949+
ambiguity_cause = None;
950+
break;
951+
}
952+
Err(NoSolution) => continue,
953+
}
954+
955+
// FIXME: boiiii, using string comparisions here sure is scuffed.
956+
if let inspect::ProbeKind::MiscCandidate { name: "coherence unknowable", result: _ } =
957+
cand.kind()
958+
{
959+
let lazily_normalize_ty = |ty: Ty<'tcx>| {
960+
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(infcx);
961+
if matches!(ty.kind(), ty::Alias(..)) {
962+
match infcx
963+
.at(&ObligationCause::dummy(), param_env)
964+
.structurally_normalize(ty, &mut *fulfill_cx)
965+
{
966+
Ok(ty) => Ok(ty),
967+
Err(_errs) => Err(()),
968+
}
969+
} else {
970+
Ok(ty)
971+
}
972+
};
973+
974+
infcx.probe(|_| {
975+
match trait_ref_is_knowable(infcx.tcx, trait_ref, lazily_normalize_ty) {
976+
Err(()) => {}
977+
Ok(Ok(())) => warn!("expected an unknowable trait ref: {trait_ref:?}"),
978+
Ok(Err(conflict)) => {
979+
let trait_ref = infcx.resolve_vars_if_possible(trait_ref);
980+
if !trait_ref.references_error() {
981+
let self_ty = trait_ref.self_ty();
982+
let (trait_desc, self_desc) = with_no_trimmed_paths!({
983+
let trait_desc = trait_ref.print_only_trait_path().to_string();
984+
let self_desc = self_ty
985+
.has_concrete_skeleton()
986+
.then(|| self_ty.to_string());
987+
(trait_desc, self_desc)
988+
});
989+
ambiguity_cause = Some(match conflict {
990+
Conflict::Upstream => {
991+
IntercrateAmbiguityCause::UpstreamCrateUpdate {
992+
trait_desc,
993+
self_desc,
994+
}
995+
}
996+
Conflict::Downstream => {
997+
IntercrateAmbiguityCause::DownstreamCrate {
998+
trait_desc,
999+
self_desc,
1000+
}
1001+
}
1002+
});
1003+
}
1004+
}
1005+
}
1006+
})
1007+
}
1008+
}
1009+
1010+
if let Some(ambiguity_cause) = ambiguity_cause {
1011+
self.causes.insert(ambiguity_cause);
1012+
}
1013+
1014+
ControlFlow::Continue(())
1015+
}
1016+
}
1017+
1018+
fn search_ambiguity_causes<'tcx>(
1019+
infcx: &InferCtxt<'tcx>,
1020+
goal: Goal<'tcx, ty::Predicate<'tcx>>,
1021+
causes: &mut FxIndexSet<IntercrateAmbiguityCause>,
1022+
) {
1023+
infcx.visit_proof_tree(goal, &mut AmbiguityCausesVisitor { causes });
1024+
}

0 commit comments

Comments
 (0)