2022-12-04 03:19:10 +00:00
|
|
|
use std::mem;
|
|
|
|
|
|
|
|
|
|
use rustc_infer::{
|
2023-01-17 11:47:47 +01:00
|
|
|
infer::InferCtxt,
|
2023-01-11 03:54:46 +00:00
|
|
|
traits::{
|
|
|
|
|
query::NoSolution, FulfillmentError, FulfillmentErrorCode, PredicateObligation,
|
|
|
|
|
SelectionError, TraitEngine,
|
|
|
|
|
},
|
2022-12-04 03:19:10 +00:00
|
|
|
};
|
|
|
|
|
|
2023-01-17 11:47:47 +01:00
|
|
|
use super::{search_graph, Certainty, EvalCtxt};
|
2022-12-04 03:19:10 +00:00
|
|
|
|
|
|
|
|
/// A trait engine using the new trait solver.
|
|
|
|
|
///
|
|
|
|
|
/// This is mostly identical to how `evaluate_all` works inside of the
|
|
|
|
|
/// solver, except that the requirements are slightly different.
|
|
|
|
|
///
|
|
|
|
|
/// Unlike `evaluate_all` it is possible to add new obligations later on
|
|
|
|
|
/// and we also have to track diagnostics information by using `Obligation`
|
|
|
|
|
/// instead of `Goal`.
|
|
|
|
|
///
|
|
|
|
|
/// It is also likely that we want to use slightly different datastructures
|
|
|
|
|
/// here as this will have to deal with far more root goals than `evaluate_all`.
|
|
|
|
|
pub struct FulfillmentCtxt<'tcx> {
|
|
|
|
|
obligations: Vec<PredicateObligation<'tcx>>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'tcx> FulfillmentCtxt<'tcx> {
|
|
|
|
|
pub fn new() -> FulfillmentCtxt<'tcx> {
|
|
|
|
|
FulfillmentCtxt { obligations: Vec::new() }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
|
|
|
|
|
fn register_predicate_obligation(
|
|
|
|
|
&mut self,
|
|
|
|
|
_infcx: &InferCtxt<'tcx>,
|
|
|
|
|
obligation: PredicateObligation<'tcx>,
|
|
|
|
|
) {
|
|
|
|
|
self.obligations.push(obligation);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
|
|
|
|
|
let errors = self.select_where_possible(infcx);
|
|
|
|
|
if !errors.is_empty() {
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-11 03:54:46 +00:00
|
|
|
self.obligations
|
|
|
|
|
.drain(..)
|
|
|
|
|
.map(|obligation| FulfillmentError {
|
|
|
|
|
obligation: obligation.clone(),
|
2023-01-19 04:50:14 +00:00
|
|
|
code: FulfillmentErrorCode::CodeAmbiguity,
|
2023-01-11 03:54:46 +00:00
|
|
|
root_obligation: obligation,
|
|
|
|
|
})
|
|
|
|
|
.collect()
|
2022-12-04 03:19:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
|
2023-01-11 03:54:46 +00:00
|
|
|
let mut errors = Vec::new();
|
2022-12-04 03:19:10 +00:00
|
|
|
for i in 0.. {
|
|
|
|
|
if !infcx.tcx.recursion_limit().value_within_limit(i) {
|
2023-01-10 20:24:10 +00:00
|
|
|
unimplemented!("overflowed on pending obligations: {:?}", self.obligations);
|
2022-12-04 03:19:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut has_changed = false;
|
2023-01-11 03:54:46 +00:00
|
|
|
for obligation in mem::take(&mut self.obligations) {
|
2023-01-17 10:21:30 +01:00
|
|
|
let goal = obligation.clone().into();
|
2023-01-17 11:47:47 +01:00
|
|
|
let search_graph = &mut search_graph::SearchGraph::new(infcx.tcx);
|
|
|
|
|
let mut ecx = EvalCtxt::new_outside_solver(infcx, search_graph);
|
|
|
|
|
let (changed, certainty) = match ecx.evaluate_goal(goal) {
|
|
|
|
|
Ok(result) => result,
|
2023-01-11 03:54:46 +00:00
|
|
|
Err(NoSolution) => {
|
|
|
|
|
errors.push(FulfillmentError {
|
|
|
|
|
obligation: obligation.clone(),
|
2023-01-19 04:50:14 +00:00
|
|
|
code: FulfillmentErrorCode::CodeSelectionError(
|
|
|
|
|
SelectionError::Unimplemented,
|
|
|
|
|
),
|
2023-01-11 03:54:46 +00:00
|
|
|
root_obligation: obligation,
|
|
|
|
|
});
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2022-12-04 03:19:10 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
has_changed |= changed;
|
|
|
|
|
match certainty {
|
|
|
|
|
Certainty::Yes => {}
|
2023-01-11 03:54:46 +00:00
|
|
|
Certainty::Maybe(_) => self.obligations.push(obligation),
|
2022-12-04 03:19:10 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !has_changed {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
errors
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
|
|
|
|
|
self.obligations.clone()
|
|
|
|
|
}
|
|
|
|
|
}
|