3 use rustc_data_structures::fx::FxHashMap;
5 infer::{canonical::OriginalQueryValues, InferCtxt},
7 query::NoSolution, FulfillmentError, FulfillmentErrorCode, PredicateObligation,
8 SelectionError, TraitEngine,
13 use super::{Certainty, EvalCtxt};
15 /// A trait engine using the new trait solver.
17 /// This is mostly identical to how `evaluate_all` works inside of the
18 /// solver, except that the requirements are slightly different.
20 /// Unlike `evaluate_all` it is possible to add new obligations later on
21 /// and we also have to track diagnostics information by using `Obligation`
22 /// instead of `Goal`.
24 /// It is also likely that we want to use slightly different datastructures
25 /// here as this will have to deal with far more root goals than `evaluate_all`.
26 pub struct FulfillmentCtxt<'tcx> {
27 obligations: Vec<PredicateObligation<'tcx>>,
30 impl<'tcx> FulfillmentCtxt<'tcx> {
31 pub fn new() -> FulfillmentCtxt<'tcx> {
32 FulfillmentCtxt { obligations: Vec::new() }
36 impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
37 fn register_predicate_obligation(
39 _infcx: &InferCtxt<'tcx>,
40 obligation: PredicateObligation<'tcx>,
42 self.obligations.push(obligation);
45 fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
46 let errors = self.select_where_possible(infcx);
47 if !errors.is_empty() {
53 .map(|obligation| FulfillmentError {
54 obligation: obligation.clone(),
55 code: FulfillmentErrorCode::CodeSelectionError(SelectionError::Unimplemented),
56 root_obligation: obligation,
61 fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
62 let mut errors = Vec::new();
64 if !infcx.tcx.recursion_limit().value_within_limit(i) {
65 unimplemented!("overflowed on pending obligations: {:?}", self.obligations);
68 let mut has_changed = false;
69 for obligation in mem::take(&mut self.obligations) {
70 let goal = obligation.clone().into();
72 // FIXME: Add a better API for that '^^
73 let mut orig_values = OriginalQueryValues::default();
74 let canonical_goal = infcx.canonicalize_query(goal, &mut orig_values);
75 let (changed, certainty) = match EvalCtxt::evaluate_canonical_goal(
77 &mut super::search_graph::SearchGraph::new(infcx.tcx),
80 Ok(canonical_response) => {
82 true, // FIXME: check whether `var_values` are an identity substitution.
83 super::instantiate_canonical_query_response(
91 errors.push(FulfillmentError {
92 obligation: obligation.clone(),
93 code: FulfillmentErrorCode::CodeAmbiguity,
94 root_obligation: obligation,
100 has_changed |= changed;
103 Certainty::Maybe(_) => self.obligations.push(obligation),
115 fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
116 self.obligations.clone()
119 fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships> {
120 unimplemented!("Should be moved out of `TraitEngine`")