diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:57:31 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:57:31 +0000 |
commit | dc0db358abe19481e475e10c32149b53370f1a1c (patch) | |
tree | ab8ce99c4b255ce46f99ef402c27916055b899ee /vendor/chalk-solve-0.87.0/src/coherence | |
parent | Releasing progress-linux version 1.71.1+dfsg1-2~progress7.99u1. (diff) | |
download | rustc-dc0db358abe19481e475e10c32149b53370f1a1c.tar.xz rustc-dc0db358abe19481e475e10c32149b53370f1a1c.zip |
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/chalk-solve-0.87.0/src/coherence')
-rw-r--r-- | vendor/chalk-solve-0.87.0/src/coherence/orphan.rs | 44 | ||||
-rw-r--r-- | vendor/chalk-solve-0.87.0/src/coherence/solve.rs | 260 |
2 files changed, 0 insertions, 304 deletions
diff --git a/vendor/chalk-solve-0.87.0/src/coherence/orphan.rs b/vendor/chalk-solve-0.87.0/src/coherence/orphan.rs deleted file mode 100644 index f8e06b901..000000000 --- a/vendor/chalk-solve-0.87.0/src/coherence/orphan.rs +++ /dev/null @@ -1,44 +0,0 @@ -use crate::coherence::CoherenceError; -use crate::ext::GoalExt; -use crate::solve::Solver; -use crate::RustIrDatabase; -use chalk_ir::cast::*; -use chalk_ir::interner::Interner; -use chalk_ir::*; -use tracing::{debug, instrument}; - -// Test if a local impl violates the orphan rules. -// -// For `impl<T> Trait for MyType<T>` we generate: -// -// forall<T> { LocalImplAllowed(MyType<T>: Trait) } -// -// This must be provable in order to pass the orphan check. -#[instrument(level = "debug", skip(db, solver))] -pub fn perform_orphan_check<I: Interner>( - db: &dyn RustIrDatabase<I>, - solver: &mut dyn Solver<I>, - impl_id: ImplId<I>, -) -> Result<(), CoherenceError<I>> { - let impl_datum = db.impl_datum(impl_id); - debug!(?impl_datum); - - let impl_allowed: Goal<I> = impl_datum - .binders - .map_ref(|bound_impl| { - // Ignoring the polarization of the impl's polarized trait ref - DomainGoal::LocalImplAllowed(bound_impl.trait_ref.clone()) - }) - .cast(db.interner()); - - let canonical_goal = &impl_allowed.into_closed_goal(db.interner()); - let is_allowed = solver.solve(db, canonical_goal).is_some(); - debug!("overlaps = {:?}", is_allowed); - - if !is_allowed { - let trait_id = impl_datum.trait_id(); - return Err(CoherenceError::FailedOrphanCheck(trait_id)); - } - - Ok(()) -} diff --git a/vendor/chalk-solve-0.87.0/src/coherence/solve.rs b/vendor/chalk-solve-0.87.0/src/coherence/solve.rs deleted file mode 100644 index 57dd81061..000000000 --- a/vendor/chalk-solve-0.87.0/src/coherence/solve.rs +++ /dev/null @@ -1,260 +0,0 @@ -use crate::coherence::{CoherenceError, CoherenceSolver}; -use crate::debug_span; -use crate::ext::*; -use crate::rust_ir::*; -use crate::{goal_builder::GoalBuilder, Solution}; -use chalk_ir::cast::*; -use chalk_ir::fold::shift::Shift; -use chalk_ir::interner::Interner; -use chalk_ir::*; -use itertools::Itertools; -use tracing::{debug, instrument}; - -impl<I: Interner> CoherenceSolver<'_, I> { - pub(super) fn visit_specializations_of_trait( - &self, - mut record_specialization: impl FnMut(ImplId<I>, ImplId<I>), - ) -> Result<(), CoherenceError<I>> { - // Ignore impls for marker traits as they are allowed to overlap. - let trait_datum = self.db.trait_datum(self.trait_id); - if trait_datum.flags.marker { - return Ok(()); - } - - // Iterate over every pair of impls for the same trait. - let impls = self.db.local_impls_to_coherence_check(self.trait_id); - for (l_id, r_id) in impls.into_iter().tuple_combinations() { - let lhs = &self.db.impl_datum(l_id); - let rhs = &self.db.impl_datum(r_id); - - // Two negative impls never overlap. - if !lhs.is_positive() && !rhs.is_positive() { - continue; - } - - // Check if the impls overlap, then if they do, check if one specializes - // the other. Note that specialization can only run one way - if both - // specialization checks return *either* true or false, that's an error. - if !self.disjoint(lhs, rhs) { - match (self.specializes(l_id, r_id), self.specializes(r_id, l_id)) { - (true, false) => record_specialization(l_id, r_id), - (false, true) => record_specialization(r_id, l_id), - (_, _) => { - return Err(CoherenceError::OverlappingImpls(self.trait_id)); - } - } - } - } - - Ok(()) - } - - // Test if the set of types that these two impls apply to overlap. If the test succeeds, these - // two impls are disjoint. - // - // We combine the binders of the two impls & treat them as existential quantifiers. Then we - // attempt to unify the input types to the trait provided by each impl, as well as prove that - // the where clauses from both impls all hold. At the end, we apply the `compatible` modality - // and negate the query. Negating the query means that we are asking chalk to prove that no - // such overlapping impl exists. By applying `compatible { G }`, chalk attempts to prove that - // "there exists a compatible world where G is provable." When we negate compatible, it turns - // into the statement "for all compatible worlds, G is not provable." This is exactly what we - // want since we want to ensure that there is no overlap in *all* compatible worlds, not just - // that there is no overlap in *some* compatible world. - // - // Examples: - // - // Impls: - // impl<T> Foo for T { } // rhs - // impl Foo for i32 { } // lhs - // Generates: - // not { compatible { exists<T> { exists<> { T = i32 } } } } - // - // Impls: - // impl<T1, U> Foo<T1> for Vec<U> { } // rhs - // impl<T2> Foo<T2> for Vec<i32> { } // lhs - // Generates: - // not { compatible { exists<T1, U> { exists<T2> { Vec<U> = Vec<i32>, T1 = T2 } } } } - // - // Impls: - // impl<T> Foo for Vec<T> where T: Bar { } - // impl<U> Foo for Vec<U> where U: Baz { } - // Generates: - // not { compatible { exists<T> { exists<U> { Vec<T> = Vec<U>, T: Bar, U: Baz } } } } - // - #[instrument(level = "debug", skip(self))] - fn disjoint(&self, lhs: &ImplDatum<I>, rhs: &ImplDatum<I>) -> bool { - let interner = self.db.interner(); - - let (lhs_binders, lhs_bound) = lhs.binders.as_ref().into(); - let (rhs_binders, rhs_bound) = rhs.binders.as_ref().into(); - - // Upshift the rhs variables in params to account for the joined binders - let lhs_params = lhs_bound - .trait_ref - .substitution - .as_slice(interner) - .iter() - .cloned(); - let rhs_params = rhs_bound - .trait_ref - .substitution - .as_slice(interner) - .iter() - .map(|param| param.clone().shifted_in(interner)); - - // Create an equality goal for every input type the trait, attempting - // to unify the inputs to both impls with one another - let params_goals = lhs_params - .zip(rhs_params) - .map(|(a, b)| GoalData::EqGoal(EqGoal { a, b }).intern(interner)); - - // Upshift the rhs variables in where clauses - let lhs_where_clauses = lhs_bound.where_clauses.iter().cloned(); - let rhs_where_clauses = rhs_bound - .where_clauses - .iter() - .map(|wc| wc.clone().shifted_in(interner)); - - // Create a goal for each clause in both where clauses - let wc_goals = lhs_where_clauses - .chain(rhs_where_clauses) - .map(|wc| wc.cast(interner)); - - // Join all the goals we've created together with And, then quantify them - // over the joined binders. This is our query. - let goal = Box::new(Goal::all(interner, params_goals.chain(wc_goals))) - .quantify(interner, QuantifierKind::Exists, lhs_binders) - .quantify(interner, QuantifierKind::Exists, rhs_binders) - .compatible(interner) - .negate(interner); - - let canonical_goal = &goal.into_closed_goal(interner); - let mut fresh_solver = (self.solver_builder)(); - let solution = fresh_solver.solve(self.db, canonical_goal); - let result = match solution { - // Goal was proven with a unique solution, so no impl was found that causes these two - // to overlap - Some(Solution::Unique(_)) => true, - // Goal was ambiguous, so there *may* be overlap - Some(Solution::Ambig(_)) | - // Goal cannot be proven, so there is some impl that causes overlap - None => false, - }; - debug!("overlaps: result = {:?}", result); - result - } - - // Creates a goal which, if provable, means "more special" impl specializes the "less special" one. - // - // # General rule - // - // Given the more special impl: - // - // ```ignore - // impl<P0..Pn> SomeTrait<T1..Tm> for T0 where WC_more - // ``` - // - // and less special impl - // - // ```ignore - // impl<Q0..Qo> SomeTrait<U1..Um> for U0 where WC_less - // ``` - // - // create the goal: - // - // ```ignore - // forall<P0..Pn> { - // if (WC_more) {} - // exists<Q0..Qo> { - // T0 = U0, ..., Tm = Um, - // WC_less - // } - // } - // } - // ``` - // - // # Example - // - // Given: - // - // * more: `impl<T: Clone> Foo for Vec<T>` - // * less: `impl<U: Clone> Foo for U` - // - // Resulting goal: - // - // ```ignore - // forall<T> { - // if (T: Clone) { - // exists<U> { - // Vec<T> = U, U: Clone - // } - // } - // } - // ``` - #[instrument(level = "debug", skip(self))] - fn specializes(&self, less_special_id: ImplId<I>, more_special_id: ImplId<I>) -> bool { - let more_special = &self.db.impl_datum(more_special_id); - let less_special = &self.db.impl_datum(less_special_id); - debug_span!("specializes", ?less_special, ?more_special); - - let interner = self.db.interner(); - - let gb = &mut GoalBuilder::new(self.db); - - // forall<P0..Pn> { ... } - let goal = gb.forall( - &more_special.binders, - less_special_id, - |gb, _, more_special_impl, less_special_id| { - // if (WC_more) { ... } - gb.implies(more_special_impl.where_clauses.iter().cloned(), |gb| { - let less_special = &gb.db().impl_datum(less_special_id); - - // exists<Q0..Qn> { ... } - gb.exists( - &less_special.binders, - more_special_impl.trait_ref.clone(), - |gb, _, less_special_impl, more_special_trait_ref| { - let interner = gb.interner(); - - // T0 = U0, ..., Tm = Um - let params_goals = more_special_trait_ref - .substitution - .as_slice(interner) - .iter() - .cloned() - .zip( - less_special_impl - .trait_ref - .substitution - .as_slice(interner) - .iter() - .cloned(), - ) - .map(|(a, b)| GoalData::EqGoal(EqGoal { a, b }).intern(interner)); - - // <less_special_wc_goals> = where clauses from the less special impl - let less_special_wc_goals = less_special_impl - .where_clauses - .iter() - .cloned() - .casted(interner); - - // <equality_goals> && WC_less - gb.all(params_goals.chain(less_special_wc_goals)) - }, - ) - }) - }, - ); - - let canonical_goal = &goal.into_closed_goal(interner); - let mut fresh_solver = (self.solver_builder)(); - let result = fresh_solver.has_unique_solution(self.db, canonical_goal); - - debug!("specializes: result = {:?}", result); - - result - } -} |