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, ObligationCause,
8 PredicateObligation, SelectionError, TraitEngine,
10 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
11 use rustc_middle::ty::{self, Ty, TypeVisitable};
13 pub struct FulfillmentContext<'tcx> {
14 obligations: FxIndexSet<PredicateObligation<'tcx>>,
16 relationships: FxHashMap<ty::TyVid, ty::FoundRelationships>,
18 usable_in_snapshot: bool,
21 impl FulfillmentContext<'_> {
22 pub(super) fn new() -> Self {
24 obligations: FxIndexSet::default(),
25 relationships: FxHashMap::default(),
26 usable_in_snapshot: false,
30 pub(crate) fn new_in_snapshot() -> Self {
31 FulfillmentContext { usable_in_snapshot: true, ..Self::new() }
35 impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
36 fn normalize_projection_type(
38 infcx: &InferCtxt<'tcx>,
39 _param_env: ty::ParamEnv<'tcx>,
40 projection_ty: ty::ProjectionTy<'tcx>,
41 _cause: ObligationCause<'tcx>,
43 infcx.tcx.mk_ty(ty::Projection(projection_ty))
46 fn register_predicate_obligation(
48 infcx: &InferCtxt<'tcx>,
49 obligation: PredicateObligation<'tcx>,
51 if !self.usable_in_snapshot {
52 assert!(!infcx.is_in_snapshot());
54 let obligation = infcx.resolve_vars_if_possible(obligation);
56 super::relationships::update(self, infcx, &obligation);
58 self.obligations.insert(obligation);
61 fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
63 let errors = self.select_where_possible(infcx);
65 if !errors.is_empty() {
70 // any remaining obligations are errors
73 .map(|obligation| FulfillmentError {
74 obligation: obligation.clone(),
75 code: FulfillmentErrorCode::CodeAmbiguity,
76 // FIXME - does Chalk have a notation of 'root obligation'?
77 // This is just for diagnostics, so it's okay if this is wrong
78 root_obligation: obligation.clone(),
83 fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
84 if !self.usable_in_snapshot {
85 assert!(!infcx.is_in_snapshot());
88 let mut errors = Vec::new();
89 let mut next_round = FxIndexSet::default();
90 let mut making_progress;
93 making_progress = false;
95 // We iterate over all obligations, and record if we are able
96 // to unambiguously prove at least one obligation.
97 for obligation in self.obligations.drain(..) {
98 let obligation = infcx.resolve_vars_if_possible(obligation);
99 let environment = obligation.param_env.caller_bounds();
100 let goal = ChalkEnvironmentAndGoal { environment, goal: obligation.predicate };
101 let mut orig_values = OriginalQueryValues::default();
102 if goal.references_error() {
107 infcx.canonicalize_query_preserving_universes(goal, &mut orig_values);
109 match infcx.tcx.evaluate_goal(canonical_goal) {
111 if response.is_proven() {
112 making_progress = true;
114 match infcx.instantiate_query_response_and_region_obligations(
116 obligation.param_env,
120 Ok(infer_ok) => next_round.extend(
121 infer_ok.obligations.into_iter().map(|obligation| {
122 assert!(!infcx.is_in_snapshot());
123 infcx.resolve_vars_if_possible(obligation)
127 Err(_err) => errors.push(FulfillmentError {
128 obligation: obligation.clone(),
129 code: FulfillmentErrorCode::CodeSelectionError(
130 SelectionError::Unimplemented,
132 // FIXME - does Chalk have a notation of 'root obligation'?
133 // This is just for diagnostics, so it's okay if this is wrong
134 root_obligation: obligation,
138 // Ambiguous: retry at next round.
139 next_round.insert(obligation);
143 Err(NoSolution) => errors.push(FulfillmentError {
144 obligation: obligation.clone(),
145 code: FulfillmentErrorCode::CodeSelectionError(
146 SelectionError::Unimplemented,
148 // FIXME - does Chalk have a notation of 'root obligation'?
149 // This is just for diagnostics, so it's okay if this is wrong
150 root_obligation: obligation,
154 next_round = std::mem::replace(&mut self.obligations, next_round);
156 if !making_progress {
164 fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
165 self.obligations.iter().cloned().collect()
168 fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships> {
169 &mut self.relationships