]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_trait_selection/src/solve/fulfill.rs
Rollup merge of #107150 - Nilstrieb:thread-local-cleanups, r=cjgillot
[rust.git] / compiler / rustc_trait_selection / src / solve / fulfill.rs
1 use std::mem;
2
3 use rustc_infer::infer::InferCtxt;
4 use rustc_infer::traits::{
5     query::NoSolution, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes,
6     PredicateObligation, SelectionError, TraitEngine,
7 };
8 use rustc_middle::ty;
9 use rustc_middle::ty::error::{ExpectedFound, TypeError};
10
11 use super::{Certainty, InferCtxtEvalExt};
12
13 /// A trait engine using the new trait solver.
14 ///
15 /// This is mostly identical to how `evaluate_all` works inside of the
16 /// solver, except that the requirements are slightly different.
17 ///
18 /// Unlike `evaluate_all` it is possible to add new obligations later on
19 /// and we also have to track diagnostics information by using `Obligation`
20 /// instead of `Goal`.
21 ///
22 /// It is also likely that we want to use slightly different datastructures
23 /// here as this will have to deal with far more root goals than `evaluate_all`.
24 pub struct FulfillmentCtxt<'tcx> {
25     obligations: Vec<PredicateObligation<'tcx>>,
26 }
27
28 impl<'tcx> FulfillmentCtxt<'tcx> {
29     pub fn new() -> FulfillmentCtxt<'tcx> {
30         FulfillmentCtxt { obligations: Vec::new() }
31     }
32 }
33
34 impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
35     fn register_predicate_obligation(
36         &mut self,
37         _infcx: &InferCtxt<'tcx>,
38         obligation: PredicateObligation<'tcx>,
39     ) {
40         self.obligations.push(obligation);
41     }
42
43     fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
44         let errors = self.select_where_possible(infcx);
45         if !errors.is_empty() {
46             return errors;
47         }
48
49         self.obligations
50             .drain(..)
51             .map(|obligation| FulfillmentError {
52                 obligation: obligation.clone(),
53                 code: FulfillmentErrorCode::CodeAmbiguity,
54                 root_obligation: obligation,
55             })
56             .collect()
57     }
58
59     fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
60         let mut errors = Vec::new();
61         for i in 0.. {
62             if !infcx.tcx.recursion_limit().value_within_limit(i) {
63                 unimplemented!("overflowed on pending obligations: {:?}", self.obligations);
64             }
65
66             let mut has_changed = false;
67             for obligation in mem::take(&mut self.obligations) {
68                 let goal = obligation.clone().into();
69                 let (changed, certainty) = match infcx.evaluate_root_goal(goal) {
70                     Ok(result) => result,
71                     Err(NoSolution) => {
72                         errors.push(FulfillmentError {
73                             obligation: obligation.clone(),
74                             code: match goal.predicate.kind().skip_binder() {
75                                 ty::PredicateKind::Clause(ty::Clause::Projection(_)) => {
76                                     FulfillmentErrorCode::CodeProjectionError(
77                                         // FIXME: This could be a `Sorts` if the term is a type
78                                         MismatchedProjectionTypes { err: TypeError::Mismatch },
79                                     )
80                                 }
81                                 ty::PredicateKind::Subtype(pred) => {
82                                     let (a, b) = infcx.replace_bound_vars_with_placeholders(
83                                         goal.predicate.kind().rebind((pred.a, pred.b)),
84                                     );
85                                     let expected_found = ExpectedFound::new(true, a, b);
86                                     FulfillmentErrorCode::CodeSubtypeError(
87                                         expected_found,
88                                         TypeError::Sorts(expected_found),
89                                     )
90                                 }
91                                 ty::PredicateKind::Coerce(pred) => {
92                                     let (a, b) = infcx.replace_bound_vars_with_placeholders(
93                                         goal.predicate.kind().rebind((pred.a, pred.b)),
94                                     );
95                                     let expected_found = ExpectedFound::new(false, a, b);
96                                     FulfillmentErrorCode::CodeSubtypeError(
97                                         expected_found,
98                                         TypeError::Sorts(expected_found),
99                                     )
100                                 }
101                                 ty::PredicateKind::ConstEquate(a, b) => {
102                                     let (a, b) = infcx.replace_bound_vars_with_placeholders(
103                                         goal.predicate.kind().rebind((a, b)),
104                                     );
105                                     let expected_found = ExpectedFound::new(true, a, b);
106                                     FulfillmentErrorCode::CodeConstEquateError(
107                                         expected_found,
108                                         TypeError::ConstMismatch(expected_found),
109                                     )
110                                 }
111                                 ty::PredicateKind::Clause(_)
112                                 | ty::PredicateKind::WellFormed(_)
113                                 | ty::PredicateKind::ObjectSafe(_)
114                                 | ty::PredicateKind::ClosureKind(_, _, _)
115                                 | ty::PredicateKind::ConstEvaluatable(_)
116                                 | ty::PredicateKind::TypeWellFormedFromEnv(_)
117                                 | ty::PredicateKind::Ambiguous => {
118                                     FulfillmentErrorCode::CodeSelectionError(
119                                         SelectionError::Unimplemented,
120                                     )
121                                 }
122                             },
123                             root_obligation: obligation,
124                         });
125                         continue;
126                     }
127                 };
128
129                 has_changed |= changed;
130                 match certainty {
131                     Certainty::Yes => {}
132                     Certainty::Maybe(_) => self.obligations.push(obligation),
133                 }
134             }
135
136             if !has_changed {
137                 break;
138             }
139         }
140
141         errors
142     }
143
144     fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
145         self.obligations.clone()
146     }
147 }