From 698f8c2f01ea549d77d7dc3338a12e04c11057b9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:02:58 +0200 Subject: Adding upstream version 1.64.0+dfsg1. Signed-off-by: Daniel Baumann --- vendor/chalk-engine/src/slg.rs | 378 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 378 insertions(+) create mode 100644 vendor/chalk-engine/src/slg.rs (limited to 'vendor/chalk-engine/src/slg.rs') diff --git a/vendor/chalk-engine/src/slg.rs b/vendor/chalk-engine/src/slg.rs new file mode 100644 index 000000000..f3522e777 --- /dev/null +++ b/vendor/chalk-engine/src/slg.rs @@ -0,0 +1,378 @@ +use crate::ExClause; + +use chalk_derive::HasInterner; +use chalk_ir::interner::Interner; +use chalk_ir::*; +use chalk_solve::infer::InferenceTable; +use chalk_solve::RustIrDatabase; + +use std::fmt::Debug; +use std::marker::PhantomData; + +pub(crate) mod aggregate; +mod resolvent; + +#[derive(Clone, Debug, HasInterner)] +pub(crate) struct SlgContext { + phantom: PhantomData, +} + +impl SlgContext { + pub(crate) fn next_subgoal_index(ex_clause: &ExClause) -> usize { + // For now, we always pick the last subgoal in the + // list. + // + // FIXME(rust-lang-nursery/chalk#80) -- we should be more + // selective. For example, we don't want to pick a + // negative literal that will flounder, and we don't want + // to pick things like `?T: Sized` if we can help it. + ex_clause.subgoals.len() - 1 + } +} +#[derive(Clone, Debug)] +pub(crate) struct SlgContextOps<'me, I: Interner> { + program: &'me dyn RustIrDatabase, + max_size: usize, + expected_answers: Option, +} + +impl SlgContextOps<'_, I> { + pub(crate) fn new( + program: &dyn RustIrDatabase, + max_size: usize, + expected_answers: Option, + ) -> SlgContextOps<'_, I> { + SlgContextOps { + program, + max_size, + expected_answers, + } + } + + fn identity_constrained_subst( + &self, + goal: &UCanonical>>, + ) -> Canonical> { + let (mut infer, subst, _) = InferenceTable::from_canonical( + self.program.interner(), + goal.universes, + goal.canonical.clone(), + ); + infer + .canonicalize( + self.program.interner(), + ConstrainedSubst { + subst, + constraints: Constraints::empty(self.program.interner()), + }, + ) + .quantified + } + + pub(crate) fn program(&self) -> &dyn RustIrDatabase { + self.program + } + + pub(crate) fn max_size(&self) -> usize { + self.max_size + } + + pub(crate) fn unification_database(&self) -> &dyn UnificationDatabase { + self.program.unification_database() + } +} + +pub trait ResolventOps { + /// Combines the `goal` (instantiated within `infer`) with the + /// given program clause to yield the start of a new strand (a + /// canonical ex-clause). + /// + /// The bindings in `infer` are unaffected by this operation. + fn resolvent_clause( + &mut self, + ops: &dyn UnificationDatabase, + interner: I, + environment: &Environment, + goal: &DomainGoal, + subst: &Substitution, + clause: &ProgramClause, + ) -> Fallible>; + + fn apply_answer_subst( + &mut self, + interner: I, + unification_database: &dyn UnificationDatabase, + ex_clause: &mut ExClause, + selected_goal: &InEnvironment>, + answer_table_goal: &Canonical>>, + canonical_answer_subst: Canonical>, + ) -> Fallible<()>; +} + +trait SubstitutionExt { + fn may_invalidate(&self, interner: I, subst: &Canonical>) -> bool; +} + +impl SubstitutionExt for Substitution { + fn may_invalidate(&self, interner: I, subst: &Canonical>) -> bool { + self.iter(interner) + .zip(subst.value.iter(interner)) + .any(|(new, current)| MayInvalidate { interner }.aggregate_generic_args(new, current)) + } +} + +// This is a struct in case we need to add state at any point like in AntiUnifier +struct MayInvalidate { + interner: I, +} + +impl MayInvalidate { + fn aggregate_generic_args(&mut self, new: &GenericArg, current: &GenericArg) -> bool { + let interner = self.interner; + match (new.data(interner), current.data(interner)) { + (GenericArgData::Ty(ty1), GenericArgData::Ty(ty2)) => self.aggregate_tys(ty1, ty2), + (GenericArgData::Lifetime(l1), GenericArgData::Lifetime(l2)) => { + self.aggregate_lifetimes(l1, l2) + } + (GenericArgData::Const(c1), GenericArgData::Const(c2)) => self.aggregate_consts(c1, c2), + (GenericArgData::Ty(_), _) + | (GenericArgData::Lifetime(_), _) + | (GenericArgData::Const(_), _) => panic!( + "mismatched parameter kinds: new={:?} current={:?}", + new, current + ), + } + } + + /// Returns true if the two types could be unequal. + fn aggregate_tys(&mut self, new: &Ty, current: &Ty) -> bool { + let interner = self.interner; + match (new.kind(interner), current.kind(interner)) { + (_, TyKind::BoundVar(_)) => { + // If the aggregate solution already has an inference + // variable here, then no matter what type we produce, + // the aggregate cannot get 'more generalized' than it + // already is. So return false, we cannot invalidate. + // + // (Note that "inference variables" show up as *bound + // variables* here, because we are looking at the + // canonical form.) + false + } + + (TyKind::BoundVar(_), _) => { + // If we see a type variable in the potential future + // solution, we have to be conservative. We don't know + // what type variable will wind up being! Remember + // that the future solution could be any instantiation + // of `ty0` -- or it could leave this variable + // unbound, if the result is true for all types. + // + // (Note that "inference variables" show up as *bound + // variables* here, because we are looking at the + // canonical form.) + true + } + + (TyKind::InferenceVar(_, _), _) | (_, TyKind::InferenceVar(_, _)) => { + panic!( + "unexpected free inference variable in may-invalidate: {:?} vs {:?}", + new, current, + ); + } + + (TyKind::Placeholder(p1), TyKind::Placeholder(p2)) => { + self.aggregate_placeholders(p1, p2) + } + + ( + TyKind::Alias(AliasTy::Projection(proj1)), + TyKind::Alias(AliasTy::Projection(proj2)), + ) => self.aggregate_projection_tys(proj1, proj2), + + ( + TyKind::Alias(AliasTy::Opaque(opaque_ty1)), + TyKind::Alias(AliasTy::Opaque(opaque_ty2)), + ) => self.aggregate_opaque_ty_tys(opaque_ty1, opaque_ty2), + + (TyKind::Adt(id_a, substitution_a), TyKind::Adt(id_b, substitution_b)) => { + self.aggregate_name_and_substs(id_a, substitution_a, id_b, substitution_b) + } + ( + TyKind::AssociatedType(id_a, substitution_a), + TyKind::AssociatedType(id_b, substitution_b), + ) => self.aggregate_name_and_substs(id_a, substitution_a, id_b, substitution_b), + (TyKind::Scalar(scalar_a), TyKind::Scalar(scalar_b)) => scalar_a != scalar_b, + (TyKind::Str, TyKind::Str) => false, + (TyKind::Tuple(arity_a, substitution_a), TyKind::Tuple(arity_b, substitution_b)) => { + self.aggregate_name_and_substs(arity_a, substitution_a, arity_b, substitution_b) + } + ( + TyKind::OpaqueType(id_a, substitution_a), + TyKind::OpaqueType(id_b, substitution_b), + ) => self.aggregate_name_and_substs(id_a, substitution_a, id_b, substitution_b), + (TyKind::Slice(ty_a), TyKind::Slice(ty_b)) => self.aggregate_tys(ty_a, ty_b), + (TyKind::FnDef(id_a, substitution_a), TyKind::FnDef(id_b, substitution_b)) => { + self.aggregate_name_and_substs(id_a, substitution_a, id_b, substitution_b) + } + (TyKind::Ref(id_a, lifetime_a, ty_a), TyKind::Ref(id_b, lifetime_b, ty_b)) => { + id_a != id_b + || self.aggregate_lifetimes(lifetime_a, lifetime_b) + || self.aggregate_tys(ty_a, ty_b) + } + (TyKind::Raw(id_a, ty_a), TyKind::Raw(id_b, ty_b)) => { + id_a != id_b || self.aggregate_tys(ty_a, ty_b) + } + (TyKind::Never, TyKind::Never) => false, + (TyKind::Array(ty_a, const_a), TyKind::Array(ty_b, const_b)) => { + self.aggregate_tys(ty_a, ty_b) || self.aggregate_consts(const_a, const_b) + } + (TyKind::Closure(id_a, substitution_a), TyKind::Closure(id_b, substitution_b)) => { + self.aggregate_name_and_substs(id_a, substitution_a, id_b, substitution_b) + } + (TyKind::Generator(id_a, substitution_a), TyKind::Generator(id_b, substitution_b)) => { + self.aggregate_name_and_substs(id_a, substitution_a, id_b, substitution_b) + } + ( + TyKind::GeneratorWitness(id_a, substitution_a), + TyKind::GeneratorWitness(id_b, substitution_b), + ) => self.aggregate_name_and_substs(id_a, substitution_a, id_b, substitution_b), + (TyKind::Foreign(id_a), TyKind::Foreign(id_b)) => id_a != id_b, + (TyKind::Error, TyKind::Error) => false, + + (_, _) => true, + } + } + + /// Returns true if the two consts could be unequal. + fn aggregate_lifetimes(&mut self, _: &Lifetime, _: &Lifetime) -> bool { + true + } + + /// Returns true if the two consts could be unequal. + fn aggregate_consts(&mut self, new: &Const, current: &Const) -> bool { + let interner = self.interner; + let ConstData { + ty: new_ty, + value: new_value, + } = new.data(interner); + let ConstData { + ty: current_ty, + value: current_value, + } = current.data(interner); + + if self.aggregate_tys(new_ty, current_ty) { + return true; + } + + match (new_value, current_value) { + (_, ConstValue::BoundVar(_)) => { + // see comment in aggregate_tys + false + } + + (ConstValue::BoundVar(_), _) => { + // see comment in aggregate_tys + true + } + + (ConstValue::InferenceVar(_), _) | (_, ConstValue::InferenceVar(_)) => { + panic!( + "unexpected free inference variable in may-invalidate: {:?} vs {:?}", + new, current, + ); + } + + (ConstValue::Placeholder(p1), ConstValue::Placeholder(p2)) => { + self.aggregate_placeholders(p1, p2) + } + + (ConstValue::Concrete(c1), ConstValue::Concrete(c2)) => { + !c1.const_eq(new_ty, c2, interner) + } + + // Only variants left are placeholder = concrete, which always fails + (ConstValue::Placeholder(_), _) | (ConstValue::Concrete(_), _) => true, + } + } + + fn aggregate_placeholders( + &mut self, + new: &PlaceholderIndex, + current: &PlaceholderIndex, + ) -> bool { + new != current + } + + fn aggregate_projection_tys( + &mut self, + new: &ProjectionTy, + current: &ProjectionTy, + ) -> bool { + let ProjectionTy { + associated_ty_id: new_name, + substitution: new_substitution, + } = new; + let ProjectionTy { + associated_ty_id: current_name, + substitution: current_substitution, + } = current; + + self.aggregate_name_and_substs( + new_name, + new_substitution, + current_name, + current_substitution, + ) + } + + fn aggregate_opaque_ty_tys(&mut self, new: &OpaqueTy, current: &OpaqueTy) -> bool { + let OpaqueTy { + opaque_ty_id: new_name, + substitution: new_substitution, + } = new; + let OpaqueTy { + opaque_ty_id: current_name, + substitution: current_substitution, + } = current; + + self.aggregate_name_and_substs( + new_name, + new_substitution, + current_name, + current_substitution, + ) + } + + fn aggregate_name_and_substs( + &mut self, + new_name: N, + new_substitution: &Substitution, + current_name: N, + current_substitution: &Substitution, + ) -> bool + where + N: Copy + Eq + Debug, + { + let interner = self.interner; + if new_name != current_name { + return true; + } + + let name = new_name; + + assert_eq!( + new_substitution.len(interner), + current_substitution.len(interner), + "does {:?} take {} substitution or {}? can't both be right", + name, + new_substitution.len(interner), + current_substitution.len(interner) + ); + + new_substitution + .iter(interner) + .zip(current_substitution.iter(interner)) + .any(|(new, current)| self.aggregate_generic_args(new, current)) + } +} -- cgit v1.2.3