]>
Commit | Line | Data |
---|---|---|
1b1a35ee XL |
1 | //! Defines a Chalk-based `TraitEngine` |
2 | ||
3 | use crate::infer::canonical::OriginalQueryValues; | |
4 | use crate::infer::InferCtxt; | |
5 | use crate::traits::query::NoSolution; | |
6 | use crate::traits::{ | |
7 | ChalkEnvironmentAndGoal, FulfillmentError, FulfillmentErrorCode, ObligationCause, | |
8 | PredicateObligation, SelectionError, TraitEngine, | |
9 | }; | |
c295e0f8 | 10 | use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; |
1b1a35ee XL |
11 | use rustc_middle::ty::{self, Ty}; |
12 | ||
13 | pub struct FulfillmentContext<'tcx> { | |
14 | obligations: FxIndexSet<PredicateObligation<'tcx>>, | |
c295e0f8 XL |
15 | |
16 | relationships: FxHashMap<ty::TyVid, ty::FoundRelationships>, | |
1b1a35ee XL |
17 | } |
18 | ||
a2a8927a | 19 | impl FulfillmentContext<'_> { |
1b1a35ee | 20 | crate fn new() -> Self { |
c295e0f8 XL |
21 | FulfillmentContext { |
22 | obligations: FxIndexSet::default(), | |
23 | relationships: FxHashMap::default(), | |
24 | } | |
1b1a35ee XL |
25 | } |
26 | } | |
27 | ||
a2a8927a | 28 | impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { |
1b1a35ee XL |
29 | fn normalize_projection_type( |
30 | &mut self, | |
31 | infcx: &InferCtxt<'_, 'tcx>, | |
32 | _param_env: ty::ParamEnv<'tcx>, | |
33 | projection_ty: ty::ProjectionTy<'tcx>, | |
34 | _cause: ObligationCause<'tcx>, | |
35 | ) -> Ty<'tcx> { | |
36 | infcx.tcx.mk_ty(ty::Projection(projection_ty)) | |
37 | } | |
38 | ||
39 | fn register_predicate_obligation( | |
40 | &mut self, | |
41 | infcx: &InferCtxt<'_, 'tcx>, | |
42 | obligation: PredicateObligation<'tcx>, | |
43 | ) { | |
44 | assert!(!infcx.is_in_snapshot()); | |
fc512014 | 45 | let obligation = infcx.resolve_vars_if_possible(obligation); |
1b1a35ee | 46 | |
c295e0f8 XL |
47 | super::relationships::update(self, infcx, &obligation); |
48 | ||
1b1a35ee XL |
49 | self.obligations.insert(obligation); |
50 | } | |
51 | ||
3c0e092e XL |
52 | fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>> { |
53 | { | |
54 | let errors = self.select_where_possible(infcx); | |
55 | ||
56 | if !errors.is_empty() { | |
57 | return errors; | |
58 | } | |
1b1a35ee | 59 | } |
3c0e092e XL |
60 | |
61 | // any remaining obligations are errors | |
62 | self.obligations | |
63 | .iter() | |
64 | .map(|obligation| FulfillmentError { | |
65 | obligation: obligation.clone(), | |
66 | code: FulfillmentErrorCode::CodeAmbiguity, | |
67 | // FIXME - does Chalk have a notation of 'root obligation'? | |
68 | // This is just for diagnostics, so it's okay if this is wrong | |
69 | root_obligation: obligation.clone(), | |
70 | }) | |
71 | .collect() | |
1b1a35ee XL |
72 | } |
73 | ||
74 | fn select_where_possible( | |
75 | &mut self, | |
76 | infcx: &InferCtxt<'_, 'tcx>, | |
3c0e092e | 77 | ) -> Vec<FulfillmentError<'tcx>> { |
1b1a35ee XL |
78 | assert!(!infcx.is_in_snapshot()); |
79 | ||
80 | let mut errors = Vec::new(); | |
81 | let mut next_round = FxIndexSet::default(); | |
82 | let mut making_progress; | |
83 | ||
84 | loop { | |
85 | making_progress = false; | |
86 | ||
87 | // We iterate over all obligations, and record if we are able | |
88 | // to unambiguously prove at least one obligation. | |
89 | for obligation in self.obligations.drain(..) { | |
fc512014 | 90 | let obligation = infcx.resolve_vars_if_possible(obligation); |
1b1a35ee XL |
91 | let environment = obligation.param_env.caller_bounds(); |
92 | let goal = ChalkEnvironmentAndGoal { environment, goal: obligation.predicate }; | |
93 | let mut orig_values = OriginalQueryValues::default(); | |
fc512014 | 94 | let canonical_goal = infcx.canonicalize_query(goal, &mut orig_values); |
1b1a35ee XL |
95 | |
96 | match infcx.tcx.evaluate_goal(canonical_goal) { | |
97 | Ok(response) => { | |
98 | if response.is_proven() { | |
99 | making_progress = true; | |
100 | ||
101 | match infcx.instantiate_query_response_and_region_obligations( | |
102 | &obligation.cause, | |
103 | obligation.param_env, | |
104 | &orig_values, | |
105 | &response, | |
106 | ) { | |
107 | Ok(infer_ok) => next_round.extend( | |
108 | infer_ok.obligations.into_iter().map(|obligation| { | |
109 | assert!(!infcx.is_in_snapshot()); | |
fc512014 | 110 | infcx.resolve_vars_if_possible(obligation) |
1b1a35ee XL |
111 | }), |
112 | ), | |
113 | ||
114 | Err(_err) => errors.push(FulfillmentError { | |
136023e0 | 115 | obligation: obligation.clone(), |
1b1a35ee XL |
116 | code: FulfillmentErrorCode::CodeSelectionError( |
117 | SelectionError::Unimplemented, | |
118 | ), | |
136023e0 XL |
119 | // FIXME - does Chalk have a notation of 'root obligation'? |
120 | // This is just for diagnostics, so it's okay if this is wrong | |
121 | root_obligation: obligation, | |
1b1a35ee XL |
122 | }), |
123 | } | |
124 | } else { | |
125 | // Ambiguous: retry at next round. | |
126 | next_round.insert(obligation); | |
127 | } | |
128 | } | |
129 | ||
130 | Err(NoSolution) => errors.push(FulfillmentError { | |
136023e0 | 131 | obligation: obligation.clone(), |
1b1a35ee XL |
132 | code: FulfillmentErrorCode::CodeSelectionError( |
133 | SelectionError::Unimplemented, | |
134 | ), | |
136023e0 XL |
135 | // FIXME - does Chalk have a notation of 'root obligation'? |
136 | // This is just for diagnostics, so it's okay if this is wrong | |
137 | root_obligation: obligation, | |
1b1a35ee XL |
138 | }), |
139 | } | |
140 | } | |
141 | next_round = std::mem::replace(&mut self.obligations, next_round); | |
142 | ||
143 | if !making_progress { | |
144 | break; | |
145 | } | |
146 | } | |
147 | ||
3c0e092e | 148 | errors |
1b1a35ee XL |
149 | } |
150 | ||
151 | fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> { | |
152 | self.obligations.iter().cloned().collect() | |
153 | } | |
c295e0f8 XL |
154 | |
155 | fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships> { | |
156 | &mut self.relationships | |
157 | } | |
1b1a35ee | 158 | } |