]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_trait_selection/src/solve/fulfill.rs
Rollup merge of #107239 - tmiasko:tests, r=Mark-Simulacrum
[rust.git] / compiler / rustc_trait_selection / src / solve / fulfill.rs
1 use std::mem;
2
3 use super::{Certainty, InferCtxtEvalExt};
4 use rustc_infer::{
5     infer::InferCtxt,
6     traits::{
7         query::NoSolution, FulfillmentError, FulfillmentErrorCode, PredicateObligation,
8         SelectionError, TraitEngine,
9     },
10 };
11
12 /// A trait engine using the new trait solver.
13 ///
14 /// This is mostly identical to how `evaluate_all` works inside of the
15 /// solver, except that the requirements are slightly different.
16 ///
17 /// Unlike `evaluate_all` it is possible to add new obligations later on
18 /// and we also have to track diagnostics information by using `Obligation`
19 /// instead of `Goal`.
20 ///
21 /// It is also likely that we want to use slightly different datastructures
22 /// here as this will have to deal with far more root goals than `evaluate_all`.
23 pub struct FulfillmentCtxt<'tcx> {
24     obligations: Vec<PredicateObligation<'tcx>>,
25 }
26
27 impl<'tcx> FulfillmentCtxt<'tcx> {
28     pub fn new() -> FulfillmentCtxt<'tcx> {
29         FulfillmentCtxt { obligations: Vec::new() }
30     }
31 }
32
33 impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
34     fn register_predicate_obligation(
35         &mut self,
36         _infcx: &InferCtxt<'tcx>,
37         obligation: PredicateObligation<'tcx>,
38     ) {
39         self.obligations.push(obligation);
40     }
41
42     fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
43         let errors = self.select_where_possible(infcx);
44         if !errors.is_empty() {
45             return errors;
46         }
47
48         self.obligations
49             .drain(..)
50             .map(|obligation| FulfillmentError {
51                 obligation: obligation.clone(),
52                 code: FulfillmentErrorCode::CodeAmbiguity,
53                 root_obligation: obligation,
54             })
55             .collect()
56     }
57
58     fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
59         let mut errors = Vec::new();
60         for i in 0.. {
61             if !infcx.tcx.recursion_limit().value_within_limit(i) {
62                 unimplemented!("overflowed on pending obligations: {:?}", self.obligations);
63             }
64
65             let mut has_changed = false;
66             for obligation in mem::take(&mut self.obligations) {
67                 let goal = obligation.clone().into();
68                 let (changed, certainty) = match infcx.evaluate_root_goal(goal) {
69                     Ok(result) => result,
70                     Err(NoSolution) => {
71                         errors.push(FulfillmentError {
72                             obligation: obligation.clone(),
73                             code: FulfillmentErrorCode::CodeSelectionError(
74                                 SelectionError::Unimplemented,
75                             ),
76                             root_obligation: obligation,
77                         });
78                         continue;
79                     }
80                 };
81
82                 has_changed |= changed;
83                 match certainty {
84                     Certainty::Yes => {}
85                     Certainty::Maybe(_) => self.obligations.push(obligation),
86                 }
87             }
88
89             if !has_changed {
90                 break;
91             }
92         }
93
94         errors
95     }
96
97     fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
98         self.obligations.clone()
99     }
100 }