Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/next_solver/obligation_ctxt.rs')
| -rw-r--r-- | crates/hir-ty/src/next_solver/obligation_ctxt.rs | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/crates/hir-ty/src/next_solver/obligation_ctxt.rs b/crates/hir-ty/src/next_solver/obligation_ctxt.rs new file mode 100644 index 0000000000..8e2dc0dec4 --- /dev/null +++ b/crates/hir-ty/src/next_solver/obligation_ctxt.rs @@ -0,0 +1,203 @@ +use hir_def::TraitId; +use rustc_type_ir::relate::Relate; +use rustc_type_ir::{TypeFoldable, Upcast, Variance}; + +use crate::next_solver::fulfill::{FulfillmentCtxt, NextSolverError}; +use crate::next_solver::infer::at::ToTrace; +use crate::next_solver::infer::traits::{ + Obligation, ObligationCause, PredicateObligation, PredicateObligations, +}; +use crate::next_solver::infer::{DefineOpaqueTypes, InferCtxt, InferOk, TypeTrace}; +use crate::next_solver::{Const, DbInterner, ParamEnv, Term, TraitRef, Ty, TypeError}; + +/// Used if you want to have pleasant experience when dealing +/// with obligations outside of hir or mir typeck. +pub struct ObligationCtxt<'a, 'db> { + pub infcx: &'a InferCtxt<'db>, + engine: FulfillmentCtxt<'db>, +} + +impl<'a, 'db> ObligationCtxt<'a, 'db> { + pub fn new(infcx: &'a InferCtxt<'db>) -> Self { + Self { infcx, engine: FulfillmentCtxt::new(infcx) } + } +} + +impl<'a, 'db> ObligationCtxt<'a, 'db> { + pub fn register_obligation(&mut self, obligation: PredicateObligation<'db>) { + self.engine.register_predicate_obligation(self.infcx, obligation); + } + + pub fn register_obligations( + &mut self, + obligations: impl IntoIterator<Item = PredicateObligation<'db>>, + ) { + self.engine.register_predicate_obligations(self.infcx, obligations); + } + + pub fn register_infer_ok_obligations<T>(&mut self, infer_ok: InferOk<'db, T>) -> T { + let InferOk { value, obligations } = infer_ok; + self.register_obligations(obligations); + value + } + + /// Requires that `ty` must implement the trait with `def_id` in + /// the given environment. This trait must not have any type + /// parameters (except for `Self`). + pub fn register_bound( + &mut self, + cause: ObligationCause, + param_env: ParamEnv<'db>, + ty: Ty<'db>, + def_id: TraitId, + ) { + let trait_ref = TraitRef::new(self.infcx.interner, def_id.into(), [ty]); + self.register_obligation(Obligation { + cause, + recursion_depth: 0, + param_env, + predicate: trait_ref.upcast(self.infcx.interner), + }); + } + + pub fn eq<T: ToTrace<'db>>( + &mut self, + cause: &ObligationCause, + param_env: ParamEnv<'db>, + expected: T, + actual: T, + ) -> Result<(), TypeError<'db>> { + self.infcx + .at(cause, param_env) + .eq(DefineOpaqueTypes::Yes, expected, actual) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + } + + pub fn eq_trace<T: Relate<DbInterner<'db>>>( + &mut self, + cause: &ObligationCause, + param_env: ParamEnv<'db>, + trace: TypeTrace<'db>, + expected: T, + actual: T, + ) -> Result<(), TypeError<'db>> { + self.infcx + .at(cause, param_env) + .eq_trace(DefineOpaqueTypes::Yes, trace, expected, actual) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + } + + /// Checks whether `expected` is a subtype of `actual`: `expected <: actual`. + pub fn sub<T: ToTrace<'db>>( + &mut self, + cause: &ObligationCause, + param_env: ParamEnv<'db>, + expected: T, + actual: T, + ) -> Result<(), TypeError<'db>> { + self.infcx + .at(cause, param_env) + .sub(DefineOpaqueTypes::Yes, expected, actual) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + } + + pub fn relate<T: ToTrace<'db>>( + &mut self, + cause: &ObligationCause, + param_env: ParamEnv<'db>, + variance: Variance, + expected: T, + actual: T, + ) -> Result<(), TypeError<'db>> { + self.infcx + .at(cause, param_env) + .relate(DefineOpaqueTypes::Yes, expected, variance, actual) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + } + + /// Checks whether `expected` is a supertype of `actual`: `expected :> actual`. + pub fn sup<T: ToTrace<'db>>( + &mut self, + cause: &ObligationCause, + param_env: ParamEnv<'db>, + expected: T, + actual: T, + ) -> Result<(), TypeError<'db>> { + self.infcx + .at(cause, param_env) + .sup(DefineOpaqueTypes::Yes, expected, actual) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + } + + /// Computes the least-upper-bound, or mutual supertype, of two values. + pub fn lub<T: ToTrace<'db>>( + &mut self, + cause: &ObligationCause, + param_env: ParamEnv<'db>, + expected: T, + actual: T, + ) -> Result<T, TypeError<'db>> { + self.infcx + .at(cause, param_env) + .lub(expected, actual) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + } + + #[must_use] + pub fn select_where_possible(&mut self) -> Vec<NextSolverError<'db>> { + self.engine.select_where_possible(self.infcx) + } + + #[must_use] + pub fn select_all_or_error(&mut self) -> Vec<NextSolverError<'db>> { + self.engine.select_all_or_error(self.infcx) + } + + /// Returns the not-yet-processed and stalled obligations from the + /// `ObligationCtxt`. + /// + /// Takes ownership of the context as doing operations such as + /// [`ObligationCtxt::eq`] afterwards will result in other obligations + /// getting ignored. You can make a new `ObligationCtxt` if this + /// needs to be done in a loop, for example. + #[must_use] + pub fn into_pending_obligations(self) -> PredicateObligations<'db> { + self.engine.pending_obligations() + } + + pub fn deeply_normalize<T: TypeFoldable<DbInterner<'db>>>( + &self, + cause: &ObligationCause, + param_env: ParamEnv<'db>, + value: T, + ) -> Result<T, Vec<NextSolverError<'db>>> { + self.infcx.at(cause, param_env).deeply_normalize(value) + } + + pub fn structurally_normalize_ty( + &mut self, + cause: &ObligationCause, + param_env: ParamEnv<'db>, + value: Ty<'db>, + ) -> Result<Ty<'db>, Vec<NextSolverError<'db>>> { + self.infcx.at(cause, param_env).structurally_normalize_ty(value, &mut self.engine) + } + + pub fn structurally_normalize_const( + &mut self, + cause: &ObligationCause, + param_env: ParamEnv<'db>, + value: Const<'db>, + ) -> Result<Const<'db>, Vec<NextSolverError<'db>>> { + self.infcx.at(cause, param_env).structurally_normalize_const(value, &mut self.engine) + } + + pub fn structurally_normalize_term( + &mut self, + cause: &ObligationCause, + param_env: ParamEnv<'db>, + value: Term<'db>, + ) -> Result<Term<'db>, Vec<NextSolverError<'db>>> { + self.infcx.at(cause, param_env).structurally_normalize_term(value, &mut self.engine) + } +} |