From 64d98f8ee037282c35007b64c2649055c56af1db Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:19:03 +0200 Subject: Merging upstream version 1.68.2+dfsg1. Signed-off-by: Daniel Baumann --- vendor/chalk-solve-0.87.0/src/clauses/builder.rs | 207 +++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 vendor/chalk-solve-0.87.0/src/clauses/builder.rs (limited to 'vendor/chalk-solve-0.87.0/src/clauses/builder.rs') diff --git a/vendor/chalk-solve-0.87.0/src/clauses/builder.rs b/vendor/chalk-solve-0.87.0/src/clauses/builder.rs new file mode 100644 index 000000000..bbe7c2fd2 --- /dev/null +++ b/vendor/chalk-solve-0.87.0/src/clauses/builder.rs @@ -0,0 +1,207 @@ +use std::marker::PhantomData; + +use crate::cast::{Cast, CastTo}; +use crate::RustIrDatabase; +use chalk_ir::fold::{Shift, TypeFoldable}; +use chalk_ir::interner::{HasInterner, Interner}; +use chalk_ir::*; +use tracing::{debug, instrument}; + +/// The "clause builder" is a useful tool for building up sets of +/// program clauses. It takes ownership of the output vector while it +/// lasts, and offers methods like `push_clause` and so forth to +/// append to it. +pub struct ClauseBuilder<'me, I: Interner> { + pub db: &'me dyn RustIrDatabase, + clauses: &'me mut Vec>, + binders: Vec>, + parameters: Vec>, +} + +impl<'me, I: Interner> ClauseBuilder<'me, I> { + pub fn new(db: &'me dyn RustIrDatabase, clauses: &'me mut Vec>) -> Self { + Self { + db, + clauses, + binders: vec![], + parameters: vec![], + } + } + + /// Pushes a "fact" `forall<..> { consequence }` into the set of + /// program clauses, meaning something that we can assume to be + /// true unconditionally. The `forall<..>` binders will be + /// whichever binders have been pushed (see `push_binders`). + pub fn push_fact(&mut self, consequence: impl CastTo>) { + self.push_clause(consequence, None::>); + } + + /// Pushes a "fact" `forall<..> { consequence }` into the set of + /// program clauses, meaning something that we can assume to be + /// true unconditionally. The `forall<..>` binders will be + /// whichever binders have been pushed (see `push_binders`). + pub fn push_fact_with_priority( + &mut self, + consequence: impl CastTo>, + constraints: impl IntoIterator>>, + priority: ClausePriority, + ) { + self.push_clause_with_priority(consequence, None::>, constraints, priority); + } + + /// Pushes a clause `forall<..> { consequence :- conditions }` + /// into the set of program clauses, meaning that `consequence` + /// can be proven if `conditions` are all true. The `forall<..>` + /// binders will be whichever binders have been pushed (see `push_binders`). + pub fn push_clause( + &mut self, + consequence: impl CastTo>, + conditions: impl IntoIterator>>, + ) { + self.push_clause_with_priority(consequence, conditions, None, ClausePriority::High) + } + + pub fn push_fact_with_constraints( + &mut self, + consequence: impl CastTo>, + constraints: impl IntoIterator>>, + ) { + self.push_fact_with_priority(consequence, constraints, ClausePriority::High) + } + + /// Pushes a clause `forall<..> { consequence :- conditions ; constraints }` + /// into the set of program clauses, meaning that `consequence` + /// can be proven if `conditions` are all true and `constraints` + /// are proven to hold. The `forall<..>` binders will be whichever binders + /// have been pushed (see `push_binders`). + pub fn push_clause_with_priority( + &mut self, + consequence: impl CastTo>, + conditions: impl IntoIterator>>, + constraints: impl IntoIterator>>, + priority: ClausePriority, + ) { + let interner = self.db.interner(); + let clause = ProgramClauseImplication { + consequence: consequence.cast(interner), + conditions: Goals::from_iter(interner, conditions), + constraints: Constraints::from_iter(interner, constraints), + priority, + }; + + let clause = if self.binders.is_empty() { + // Compensate for the added empty binder + clause.shifted_in(interner) + } else { + clause + }; + + self.clauses.push( + ProgramClauseData(Binders::new( + VariableKinds::from_iter(interner, self.binders.clone()), + clause, + )) + .intern(interner), + ); + + debug!("pushed clause {:?}", self.clauses.last()); + } + + /// Accesses the placeholders for the current list of parameters in scope. + pub fn placeholders_in_scope(&self) -> &[GenericArg] { + &self.parameters + } + + /// Accesses the placeholders for the current list of parameters in scope, + /// in the form of a `Substitution`. + pub fn substitution_in_scope(&self) -> Substitution { + Substitution::from_iter( + self.db.interner(), + self.placeholders_in_scope().iter().cloned(), + ) + } + + /// Executes `op` with the `binders` in-scope; `op` is invoked + /// with the bound value `v` as a parameter. After `op` finishes, + /// the binders are popped from scope. + /// + /// The new binders are always pushed onto the end of the internal + /// list of binders; this means that any extant values where were + /// created referencing the *old* list of binders are still valid. + #[instrument(level = "debug", skip(self, op))] + pub fn push_binders( + &mut self, + binders: Binders, + op: impl FnOnce(&mut Self, V) -> R, + ) -> R + where + V: TypeFoldable + HasInterner, + V: std::fmt::Debug, + { + let old_len = self.binders.len(); + let interner = self.interner(); + self.binders.extend(binders.binders.iter(interner).cloned()); + self.parameters.extend( + binders + .binders + .iter(interner) + .zip(old_len..) + .map(|(pk, i)| (i, pk).to_generic_arg(interner)), + ); + let value = binders.substitute(self.interner(), &self.parameters[old_len..]); + debug!(?value); + let res = op(self, value); + + self.binders.truncate(old_len); + self.parameters.truncate(old_len); + res + } + + /// Push a single binder, for a type, at the end of the binder + /// list. The indices of previously bound variables are + /// unaffected and hence the context remains usable. Invokes `op`, + /// passing a type representing this new type variable in as an + /// argument. + pub fn push_bound_ty(&mut self, op: impl FnOnce(&mut Self, Ty)) { + let interner = self.interner(); + let binders = Binders::new( + VariableKinds::from1(interner, VariableKind::Ty(TyVariableKind::General)), + PhantomData::, + ); + self.push_binders(binders, |this, PhantomData| { + let ty = this + .placeholders_in_scope() + .last() + .unwrap() + .assert_ty_ref(interner) + .clone(); + op(this, ty) + }); + } + + /// Push a single binder, for a lifetime, at the end of the binder + /// list. The indices of previously bound variables are + /// unaffected and hence the context remains usable. Invokes `op`, + /// passing a lifetime representing this new lifetime variable in as an + /// argument. + pub fn push_bound_lifetime(&mut self, op: impl FnOnce(&mut Self, Lifetime)) { + let interner = self.interner(); + let binders = Binders::new( + VariableKinds::from1(interner, VariableKind::Lifetime), + PhantomData::, + ); + self.push_binders(binders, |this, PhantomData| { + let lifetime = this + .placeholders_in_scope() + .last() + .unwrap() + .assert_lifetime_ref(interner) + .clone(); + op(this, lifetime) + }); + } + + pub fn interner(&self) -> I { + self.db.interner() + } +} -- cgit v1.2.3