]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_trait_selection/src/solve/fulfill.rs
Auto merge of #107215 - Dylan-DPC:rollup-zqtiufk, r=Dylan-DPC
[rust.git] / compiler / rustc_trait_selection / src / solve / fulfill.rs
1 use std::mem;
2
3 use rustc_infer::{
4     infer::InferCtxt,
5     traits::{
6         query::NoSolution, FulfillmentError, FulfillmentErrorCode, PredicateObligation,
7         SelectionError, TraitEngine,
8     },
9 };
10
11 use super::{search_graph, Certainty, EvalCtxt};
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 search_graph = &mut search_graph::SearchGraph::new(infcx.tcx);
70                 let mut ecx = EvalCtxt::new_outside_solver(infcx, search_graph);
71                 let (changed, certainty) = match ecx.evaluate_goal(goal) {
72                     Ok(result) => result,
73                     Err(NoSolution) => {
74                         errors.push(FulfillmentError {
75                             obligation: obligation.clone(),
76                             code: FulfillmentErrorCode::CodeSelectionError(
77                                 SelectionError::Unimplemented,
78                             ),
79                             root_obligation: obligation,
80                         });
81                         continue;
82                     }
83                 };
84
85                 has_changed |= changed;
86                 match certainty {
87                     Certainty::Yes => {}
88                     Certainty::Maybe(_) => self.obligations.push(obligation),
89                 }
90             }
91
92             if !has_changed {
93                 break;
94             }
95         }
96
97         errors
98     }
99
100     fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
101         self.obligations.clone()
102     }
103 }