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