1 //! Defines a Chalk-based `TraitEngine`
3 use crate::infer::canonical::OriginalQueryValues;
4 use crate::infer::InferCtxt;
5 use crate::traits::query::NoSolution;
7 ChalkEnvironmentAndGoal, FulfillmentError, FulfillmentErrorCode, PredicateObligation,
8 SelectionError, TraitEngine,
10 use rustc_data_structures::fx::FxIndexSet;
11 use rustc_middle::ty::TypeVisitable;
13 pub struct FulfillmentContext<'tcx> {
14 obligations: FxIndexSet<PredicateObligation<'tcx>>,
16 usable_in_snapshot: bool,
19 impl FulfillmentContext<'_> {
20 pub(super) fn new() -> Self {
21 FulfillmentContext { obligations: FxIndexSet::default(), usable_in_snapshot: false }
24 pub(crate) fn new_in_snapshot() -> Self {
25 FulfillmentContext { usable_in_snapshot: true, ..Self::new() }
29 impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
30 fn register_predicate_obligation(
32 infcx: &InferCtxt<'tcx>,
33 obligation: PredicateObligation<'tcx>,
35 if !self.usable_in_snapshot {
36 assert!(!infcx.is_in_snapshot());
38 let obligation = infcx.resolve_vars_if_possible(obligation);
40 self.obligations.insert(obligation);
43 fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>> {
44 // any remaining obligations are errors
47 .map(|obligation| FulfillmentError {
48 obligation: obligation.clone(),
49 code: FulfillmentErrorCode::CodeAmbiguity,
50 // FIXME - does Chalk have a notation of 'root obligation'?
51 // This is just for diagnostics, so it's okay if this is wrong
52 root_obligation: obligation.clone(),
57 fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
58 if !self.usable_in_snapshot {
59 assert!(!infcx.is_in_snapshot());
62 let mut errors = Vec::new();
63 let mut next_round = FxIndexSet::default();
64 let mut making_progress;
67 making_progress = false;
69 // We iterate over all obligations, and record if we are able
70 // to unambiguously prove at least one obligation.
71 for obligation in self.obligations.drain(..) {
72 let obligation = infcx.resolve_vars_if_possible(obligation);
73 let environment = obligation.param_env.caller_bounds();
74 let goal = ChalkEnvironmentAndGoal { environment, goal: obligation.predicate };
75 let mut orig_values = OriginalQueryValues::default();
76 if goal.references_error() {
81 infcx.canonicalize_query_preserving_universes(goal, &mut orig_values);
83 match infcx.tcx.evaluate_goal(canonical_goal) {
85 if response.is_proven() {
86 making_progress = true;
88 match infcx.instantiate_query_response_and_region_obligations(
94 Ok(infer_ok) => next_round.extend(
95 infer_ok.obligations.into_iter().map(|obligation| {
96 assert!(!infcx.is_in_snapshot());
97 infcx.resolve_vars_if_possible(obligation)
101 Err(_err) => errors.push(FulfillmentError {
102 obligation: obligation.clone(),
103 code: FulfillmentErrorCode::CodeSelectionError(
104 SelectionError::Unimplemented,
106 // FIXME - does Chalk have a notation of 'root obligation'?
107 // This is just for diagnostics, so it's okay if this is wrong
108 root_obligation: obligation,
112 // Ambiguous: retry at next round.
113 next_round.insert(obligation);
117 Err(NoSolution) => errors.push(FulfillmentError {
118 obligation: obligation.clone(),
119 code: FulfillmentErrorCode::CodeSelectionError(
120 SelectionError::Unimplemented,
122 // FIXME - does Chalk have a notation of 'root obligation'?
123 // This is just for diagnostics, so it's okay if this is wrong
124 root_obligation: obligation,
128 next_round = std::mem::replace(&mut self.obligations, next_round);
130 if !making_progress {
138 fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
139 self.obligations.iter().cloned().collect()