From 218caa410aa38c29984be31a5229b9fa717560ee Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:19:13 +0200 Subject: Merging upstream version 1.68.2+dfsg1. Signed-off-by: Daniel Baumann --- .../rustc_trait_selection/src/solve/fulfill.rs | 109 +++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 compiler/rustc_trait_selection/src/solve/fulfill.rs (limited to 'compiler/rustc_trait_selection/src/solve/fulfill.rs') diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs new file mode 100644 index 000000000..a6240666e --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -0,0 +1,109 @@ +use std::mem; + +use rustc_data_structures::fx::FxHashMap; +use rustc_infer::{ + infer::InferCtxt, + traits::{ + query::NoSolution, FulfillmentError, FulfillmentErrorCode, PredicateObligation, + SelectionError, TraitEngine, + }, +}; +use rustc_middle::ty; + +use super::{search_graph, Certainty, EvalCtxt}; + +/// 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>, +} + +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> { + let errors = self.select_where_possible(infcx); + if !errors.is_empty() { + return errors; + } + + self.obligations + .drain(..) + .map(|obligation| FulfillmentError { + obligation: obligation.clone(), + code: FulfillmentErrorCode::CodeAmbiguity, + root_obligation: obligation, + }) + .collect() + } + + fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec> { + let mut errors = Vec::new(); + for i in 0.. { + if !infcx.tcx.recursion_limit().value_within_limit(i) { + unimplemented!("overflowed on pending obligations: {:?}", self.obligations); + } + + let mut has_changed = false; + for obligation in mem::take(&mut self.obligations) { + let goal = obligation.clone().into(); + 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, + Err(NoSolution) => { + errors.push(FulfillmentError { + obligation: obligation.clone(), + code: FulfillmentErrorCode::CodeSelectionError( + SelectionError::Unimplemented, + ), + root_obligation: obligation, + }); + continue; + } + }; + + has_changed |= changed; + match certainty { + Certainty::Yes => {} + Certainty::Maybe(_) => self.obligations.push(obligation), + } + } + + if !has_changed { + break; + } + } + + errors + } + + fn pending_obligations(&self) -> Vec> { + self.obligations.clone() + } + + fn relationships(&mut self) -> &mut FxHashMap { + unimplemented!("Should be moved out of `TraitEngine`") + } +} -- cgit v1.2.3