From 18c95168ee435e9fb9a8fa0b86667489a60f6e8e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 20 May 2018 06:25:39 -0400 Subject: [PATCH 1/6] merge to shared trait --- chalk-engine/src/context.rs | 66 +++++++++++++---------- chalk-engine/src/context/prelude.rs | 1 + chalk-engine/src/derived.rs | 18 +++---- chalk-engine/src/lib.rs | 20 +++---- chalk-engine/src/logic.rs | 18 ++++--- chalk-engine/src/simplify.rs | 2 +- chalk-engine/src/strand.rs | 2 +- chalk-engine/src/table.rs | 6 +-- src/solve/slg/implementation.rs | 44 +++++++++------ src/solve/slg/implementation/resolvent.rs | 12 ++--- 10 files changed, 107 insertions(+), 82 deletions(-) diff --git a/chalk-engine/src/context.rs b/chalk-engine/src/context.rs index a9107d9faca..fdabe8fb65b 100644 --- a/chalk-engine/src/context.rs +++ b/chalk-engine/src/context.rs @@ -1,15 +1,34 @@ use crate::fallible::Fallible; use crate::hh::HhGoal; -use crate::{ExClause, SimplifiedAnswer}; +use crate::{DelayedLiteral, ExClause, SimplifiedAnswer}; use std::fmt::Debug; use std::hash::Hash; crate mod prelude; +pub trait ExClauseContext: Sized + Debug { + /// Part of an answer: represents a canonicalized substitution, + /// combined with region constraints. See [the rustc-guide] for more information. + /// + /// [the rustc-guide]: https://rust-lang-nursery.github.io/rustc-guide/traits-canonicalization.html#canonicalizing-the-query-result + type CanonicalConstrainedSubst: Clone + Debug + Eq + Hash; + + /// Represents a substitution from the "canonical variables" found + /// in a canonical goal to specific values. + type Substitution: Debug; + + /// Represents a region constraint that will be propagated back + /// (but not verified). + type RegionConstraint: Debug; + + /// Represents a goal along with an environment. + type GoalInEnvironment: Debug + Clone + Eq + Hash; +} + /// The "context" in which the SLG solver operates. // FIXME(leodasvacas): Clone and Debug bounds are just for easy derive, // they are not actually necessary. -pub trait Context: Clone + Debug { +pub trait Context: Clone + Debug + ExClauseContext { type CanonicalExClause: Debug; /// A map between universes. These are produced when @@ -17,12 +36,6 @@ pub trait Context: Clone + Debug { /// the universes from the original. type UniverseMap: Clone + Debug; - /// Part of an answer: represents a canonicalized substitution, - /// combined with region constraints. See [the rustc-guide] for more information. - /// - /// [the rustc-guide]: https://rust-lang-nursery.github.io/rustc-guide/traits-canonicalization.html#canonicalizing-the-query-result - type CanonicalConstrainedSubst: Clone + Debug + Eq + Hash; - /// Extracted from a canonicalized substitution or canonicalized ex clause, this is the type of /// substitution that is fully normalized with respect to inference variables. type InferenceNormalizedSubst: Debug; @@ -45,23 +58,10 @@ pub trait Context: Clone + Debug { type Solution; } -pub trait ExClauseContext: Sized + Debug { - /// Represents a substitution from the "canonical variables" found - /// in a canonical goal to specific values. - type Substitution: Debug; - - /// Represents a region constraint that will be propagated back - /// (but not verified). - type RegionConstraint: Debug; - - /// Represents a goal along with an environment. - type GoalInEnvironment: Debug + Clone + Eq + Hash; -} - /// The set of types belonging to an "inference context"; in rustc, /// these types are tied to the lifetime of the arena within which an /// inference context operates. -pub trait InferenceContext: ExClauseContext { +pub trait InferenceContext: ExClauseContext { /// Represents a set of hypotheses that are assumed to be true. type Environment: Debug + Clone; @@ -118,7 +118,7 @@ pub trait InferenceContext: ExClauseContext { /// Add the residual subgoals as new subgoals of the ex-clause. /// Also add region constraints. - fn into_ex_clause(result: Self::UnificationResult, ex_clause: &mut ExClause); + fn into_ex_clause(result: Self::UnificationResult, ex_clause: &mut ExClause); // Used by: simplify fn add_clauses( @@ -222,7 +222,7 @@ pub trait WithInstantiatedExClause { fn with>( self, infer: &mut dyn InferenceTable, - ex_clause: ExClause, + ex_clause: ExClause, ) -> Self::Output; } @@ -259,13 +259,13 @@ pub trait UnificationOps> { fn instantiate_binders_existentially(&mut self, arg: &I::BindersGoal) -> I::Goal; // Used by: logic (but for debugging only) - fn debug_ex_clause(&mut self, value: &'v ExClause) -> Box; + fn debug_ex_clause(&mut self, value: &'v ExClause) -> Box; // Used by: logic fn canonicalize_goal(&mut self, value: &I::GoalInEnvironment) -> C::CanonicalGoalInEnvironment; // Used by: logic - fn canonicalize_ex_clause(&mut self, value: &ExClause) -> C::CanonicalExClause; + fn canonicalize_ex_clause(&mut self, value: &ExClause) -> C::CanonicalExClause; // Used by: logic fn canonicalize_constrained_subst( @@ -280,6 +280,16 @@ pub trait UnificationOps> { value: &C::CanonicalGoalInEnvironment, ) -> (C::UCanonicalGoalInEnvironment, C::UniverseMap); + fn sink_answer_subset( + &self, + value: &C::CanonicalConstrainedSubst, + ) -> I::CanonicalConstrainedSubst; + + fn lift_delayed_literal( + &self, + value: DelayedLiteral, + ) -> DelayedLiteral; + // Used by: logic fn invert_goal(&mut self, value: &I::GoalInEnvironment) -> Option; @@ -330,11 +340,11 @@ pub trait ResolventOps> { fn apply_answer_subst( &mut self, - ex_clause: ExClause, + ex_clause: ExClause, selected_goal: &I::GoalInEnvironment, answer_table_goal: &C::CanonicalGoalInEnvironment, canonical_answer_subst: &C::CanonicalConstrainedSubst, - ) -> Fallible>; + ) -> Fallible>; } pub trait AnswerStream { diff --git a/chalk-engine/src/context/prelude.rs b/chalk-engine/src/context/prelude.rs index 39cf99b0904..a084b09424e 100644 --- a/chalk-engine/src/context/prelude.rs +++ b/chalk-engine/src/context/prelude.rs @@ -1,5 +1,6 @@ #![allow(unused_imports)] // rustc bug +crate use super::ExClauseContext; crate use super::Context; crate use super::ContextOps; crate use super::AggregateOps; diff --git a/chalk-engine/src/derived.rs b/chalk-engine/src/derived.rs index 9855ab5ee74..42e3f72cb00 100644 --- a/chalk-engine/src/derived.rs +++ b/chalk-engine/src/derived.rs @@ -7,7 +7,7 @@ use std::hash::{Hash, Hasher}; use std::mem; use super::*; -impl PartialEq for DelayedLiteralSet { +impl PartialEq for DelayedLiteralSet { fn eq(&self, other: &Self) -> bool { let DelayedLiteralSet { delayed_literals: a1 } = self; let DelayedLiteralSet { delayed_literals: a2 } = other; @@ -15,12 +15,12 @@ impl PartialEq for DelayedLiteralSet { } } -impl Eq for DelayedLiteralSet { +impl Eq for DelayedLiteralSet { } /////////////////////////////////////////////////////////////////////////// -impl PartialEq for DelayedLiteral { +impl PartialEq for DelayedLiteral { fn eq(&self, other: &Self) -> bool { if mem::discriminant(self) != mem::discriminant(other) { return false; @@ -41,10 +41,10 @@ impl PartialEq for DelayedLiteral { } } -impl Eq for DelayedLiteral { +impl Eq for DelayedLiteral { } -impl Hash for DelayedLiteral { +impl Hash for DelayedLiteral { fn hash(&self, hasher: &mut H) { mem::discriminant(self).hash(hasher); @@ -65,8 +65,8 @@ impl Hash for DelayedLiteral { /////////////////////////////////////////////////////////////////////////// -impl> PartialEq for Literal { - fn eq(&self, other: &Literal) -> bool { +impl PartialEq for Literal { + fn eq(&self, other: &Literal) -> bool { match (self, other) { (Literal::Positive(goal1), Literal::Positive(goal2)) | (Literal::Negative(goal1), Literal::Negative(goal2)) => goal1 == goal2, @@ -76,10 +76,10 @@ impl> PartialEq for Literal { } } -impl> Eq for Literal { +impl Eq for Literal { } -impl> Hash for Literal { +impl Hash for Literal { fn hash(&self, state: &mut H) { mem::discriminant(self).hash(state); match self { diff --git a/chalk-engine/src/lib.rs b/chalk-engine/src/lib.rs index a8650b81e43..bc88f4458ec 100644 --- a/chalk-engine/src/lib.rs +++ b/chalk-engine/src/lib.rs @@ -111,20 +111,20 @@ struct DepthFirstNumber { /// The paper describes these as `A :- D | G`. #[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct ExClause> { +pub struct ExClause { /// The substitution which, applied to the goal of our table, /// would yield A. pub subst: E::Substitution, /// Delayed literals: things that we depend on negatively, /// but which have not yet been fully evaluated. - pub delayed_literals: Vec>, + pub delayed_literals: Vec>, /// Region constraints we have accumulated. pub constraints: Vec, /// Subgoals: literals that must be proven - pub subgoals: Vec>, + pub subgoals: Vec>, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] @@ -170,12 +170,12 @@ enum InnerDelayedLiteralSets { /// delayed literal, which in turn forces its subgoal to be delayed, /// and so forth. Therefore, we store canonicalized goals.) #[derive(Clone, Debug, Default)] -struct DelayedLiteralSet { - delayed_literals: FxHashSet>, +struct DelayedLiteralSet { + delayed_literals: FxHashSet>, } #[derive(Clone, Debug)] -pub enum DelayedLiteral { +pub enum DelayedLiteral { /// Something which can never be proven nor disproven. Inserted /// when truncation triggers; doesn't arise normally. CannotProve(()), @@ -189,12 +189,12 @@ pub enum DelayedLiteral { /// **conditional** answer (the `CanonicalConstrainedSubst`) within the /// given table, but we have to come back later and see whether /// that answer turns out to be true. - Positive(TableIndex, C::CanonicalConstrainedSubst), + Positive(TableIndex, E::CanonicalConstrainedSubst), } /// Either `A` or `~A`, where `A` is a `Env |- Goal`. #[derive(Clone, Debug)] -pub enum Literal> { // FIXME: pub b/c fold +pub enum Literal { // FIXME: pub b/c fold Positive(E::GoalInEnvironment), Negative(E::GoalInEnvironment), } @@ -272,12 +272,12 @@ impl DelayedLiteralSets { } } -impl DelayedLiteralSet { +impl DelayedLiteralSet { fn is_empty(&self) -> bool { self.delayed_literals.is_empty() } - fn is_subset(&self, other: &DelayedLiteralSet) -> bool { + fn is_subset(&self, other: &DelayedLiteralSet) -> bool { self.delayed_literals .iter() .all(|elem| other.delayed_literals.contains(elem)) diff --git a/chalk-engine/src/logic.rs b/chalk-engine/src/logic.rs index d58ae1c1fec..5842e2f2b87 100644 --- a/chalk-engine/src/logic.rs +++ b/chalk-engine/src/logic.rs @@ -296,7 +296,7 @@ impl> Forest { fn with>( self, infer: &mut dyn InferenceTable, - ex_clause: ExClause, + ex_clause: ExClause, ) -> OP::Output { self.op.with(Strand { infer, @@ -318,7 +318,7 @@ impl> Forest { fn canonicalize_strand_from>( infer: &mut dyn InferenceTable, - ex_clause: &ExClause, + ex_clause: &ExClause, selected_subgoal: Option>, ) -> CanonicalStrand { let canonical_ex_clause = infer.canonicalize_ex_clause(&ex_clause); @@ -561,7 +561,9 @@ impl> Forest { debug!("answer: table={:?}, answer_subst={:?}", table, answer_subst); let delayed_literals = { - let mut delayed_literals: FxHashSet<_> = delayed_literals.into_iter().collect(); + let mut delayed_literals: FxHashSet<_> = delayed_literals.into_iter() + .map(|dl| infer.lift_delayed_literal(dl)) + .collect(); DelayedLiteralSet { delayed_literals } }; debug!("answer: delayed_literals={:?}", delayed_literals); @@ -663,7 +665,7 @@ impl> Forest { fn get_or_create_table_for_subgoal>( &mut self, infer: &mut dyn InferenceTable, - subgoal: &Literal, + subgoal: &Literal, ) -> Option<(TableIndex, C::UniverseMap)> { debug_heading!("get_or_create_table_for_subgoal(subgoal={:?})", subgoal); @@ -1064,7 +1066,7 @@ impl> Forest { if !answer.delayed_literals.is_empty() { ex_clause.delayed_literals.push(DelayedLiteral::Positive( subgoal_table, - answer.subst.clone(), + infer.sink_answer_subset(&answer.subst), )); } } @@ -1097,9 +1099,9 @@ impl> Forest { /// the resolvent (or factor) if it has grown too large. fn truncate_returned>( &self, - ex_clause: ExClause, + ex_clause: ExClause, infer: &mut dyn InferenceTable, - ) -> ExClause { + ) -> ExClause { // DIVERGENCE // // In the original RR paper, truncation is only applied @@ -1208,7 +1210,7 @@ impl> Forest { // literal (in which case the negative literal *may* be true). // Before exiting the match, then, we set `delayed_literal` to // either `Some` or `None` depending. - let delayed_literal: Option>; + let delayed_literal: Option>; match self.ensure_answer_recursively(subgoal_table, answer_index) { Ok(EnsureSuccess::AnswerAvailable) => { if self.answer(subgoal_table, answer_index).is_unconditional() { diff --git a/chalk-engine/src/simplify.rs b/chalk-engine/src/simplify.rs index 098031a29a2..76d6c3f26ec 100644 --- a/chalk-engine/src/simplify.rs +++ b/chalk-engine/src/simplify.rs @@ -13,7 +13,7 @@ impl> Forest { subst: I::Substitution, initial_environment: &I::Environment, initial_hh_goal: HhGoal, - ) -> Fallible> { + ) -> Fallible> { let mut ex_clause = ExClause { subst, delayed_literals: vec![], diff --git a/chalk-engine/src/strand.rs b/chalk-engine/src/strand.rs index b5a9331c8df..2353908c63f 100644 --- a/chalk-engine/src/strand.rs +++ b/chalk-engine/src/strand.rs @@ -14,7 +14,7 @@ crate struct CanonicalStrand { crate struct Strand<'table, C: Context + 'table, I: InferenceContext + 'table> { crate infer: &'table mut dyn InferenceTable, - pub(super) ex_clause: ExClause, + pub(super) ex_clause: ExClause, /// Index into `ex_clause.subgoals`. crate selected_subgoal: Option>, diff --git a/chalk-engine/src/table.rs b/chalk-engine/src/table.rs index ca83bc9dfef..209864ec8f6 100644 --- a/chalk-engine/src/table.rs +++ b/chalk-engine/src/table.rs @@ -42,9 +42,9 @@ index_struct! { /// goal for a particular table (modulo delayed literals). It contains /// a substitution #[derive(Clone, Debug)] -pub struct Answer { - crate subst: C::CanonicalConstrainedSubst, - crate delayed_literals: DelayedLiteralSet, +pub struct Answer { + crate subst: E::CanonicalConstrainedSubst, + crate delayed_literals: DelayedLiteralSet, } impl Table { diff --git a/src/solve/slg/implementation.rs b/src/solve/slg/implementation.rs index 3d81a24169c..1ec625b757b 100644 --- a/src/solve/slg/implementation.rs +++ b/src/solve/slg/implementation.rs @@ -49,12 +49,18 @@ impl SlgContext { } } +impl context::ExClauseContext for SlgContext { + type CanonicalConstrainedSubst = Canonical; + type GoalInEnvironment = InEnvironment; + type Substitution = Substitution; + type RegionConstraint = InEnvironment; +} + impl context::Context for SlgContext { type CanonicalGoalInEnvironment = Canonical>; - type CanonicalExClause = Canonical>; + type CanonicalExClause = Canonical>; type UCanonicalGoalInEnvironment = UCanonical>; type UniverseMap = UniverseMap; - type CanonicalConstrainedSubst = Canonical; type InferenceNormalizedSubst = Substitution; type Solution = Solution; } @@ -78,7 +84,7 @@ impl context::ContextOps for SlgContext { fn instantiate_ex_clause( &self, num_universes: usize, - canonical_ex_clause: &Canonical>, + canonical_ex_clause: &Canonical>, op: impl context::WithInstantiatedExClause, ) -> R { let (infer, _subst, ex_cluse) = @@ -88,7 +94,7 @@ impl context::ContextOps for SlgContext { } fn inference_normalized_subst_from_ex_clause( - canon_ex_clause: &Canonical>, + canon_ex_clause: &Canonical>, ) -> &Substitution { &canon_ex_clause.value.subst } @@ -163,12 +169,6 @@ impl context::TruncateOps for TruncatingInferenceTable { impl context::InferenceTable for TruncatingInferenceTable {} -impl context::ExClauseContext for SlgContext { - type GoalInEnvironment = InEnvironment; - type Substitution = Substitution; - type RegionConstraint = InEnvironment; -} - impl context::InferenceContext for SlgContext { type Environment = Arc; type DomainGoal = DomainGoal; @@ -205,7 +205,7 @@ impl context::InferenceContext for SlgContext { fn into_ex_clause( result: Self::UnificationResult, - ex_clause: &mut ExClause, + ex_clause: &mut ExClause, ) { ex_clause .subgoals @@ -253,7 +253,7 @@ impl context::UnificationOps for TruncatingInferenceTabl fn debug_ex_clause( &mut self, - value: &'v ExClause, + value: &'v ExClause, ) -> Box { Box::new(self.infer.normalize_deep(value)) } @@ -264,8 +264,8 @@ impl context::UnificationOps for TruncatingInferenceTabl fn canonicalize_ex_clause( &mut self, - value: &ExClause, - ) -> Canonical> { + value: &ExClause, + ) -> Canonical> { self.infer.canonicalize(value).quantified } @@ -305,6 +305,18 @@ impl context::UnificationOps for TruncatingInferenceTabl ) -> Fallible { self.infer.unify(environment, a, b) } + + /// Since we do not have distinct types for the inference context and the slg-context, + /// these conversion operations are just no-ops.q + fn sink_answer_subset(&self, c: &Canonical) -> Canonical { + c.clone() + } + + /// Since we do not have distinct types for the inference context and the slg-context, + /// these conversion operations are just no-ops.q + fn lift_delayed_literal(&self, c: DelayedLiteral) -> DelayedLiteral { + c + } } impl Substitution { @@ -453,7 +465,7 @@ impl MayInvalidate { } } -type ExClauseSlgContext = ExClause; +type ExClauseSlgContext = ExClause; struct_fold!(ExClauseSlgContext { subst, delayed_literals, @@ -461,7 +473,7 @@ struct_fold!(ExClauseSlgContext { subgoals, }); -type LiteralSlgContext = Literal; +type LiteralSlgContext = Literal; enum_fold!(LiteralSlgContext { Literal :: { Positive(a), Negative(a) diff --git a/src/solve/slg/implementation/resolvent.rs b/src/solve/slg/implementation/resolvent.rs index 3d7023b2d8a..2191af9ce18 100644 --- a/src/solve/slg/implementation/resolvent.rs +++ b/src/solve/slg/implementation/resolvent.rs @@ -61,7 +61,7 @@ impl context::ResolventOps for TruncatingInferenceTable goal: &DomainGoal, subst: &Substitution, clause: &ProgramClause, - ) -> Fallible>> { + ) -> Fallible>> { // Relating the above description to our situation: // // - `goal` G, except with binders for any existential variables. @@ -202,11 +202,11 @@ impl context::ResolventOps for TruncatingInferenceTable fn apply_answer_subst( &mut self, - ex_clause: ExClause, + ex_clause: ExClause, selected_goal: &InEnvironment, answer_table_goal: &Canonical>, canonical_answer_subst: &Canonical, - ) -> Fallible> { + ) -> Fallible> { debug_heading!("apply_answer_subst()"); debug!("ex_clause={:?}", ex_clause); debug!( @@ -247,7 +247,7 @@ struct AnswerSubstitutor<'t> { answer_subst: &'t Substitution, answer_binders: usize, pending_binders: usize, - ex_clause: ExClause, + ex_clause: ExClause, } impl<'t> AnswerSubstitutor<'t> { @@ -255,10 +255,10 @@ impl<'t> AnswerSubstitutor<'t> { table: &mut InferenceTable, environment: &Arc, answer_subst: &Substitution, - ex_clause: ExClause, + ex_clause: ExClause, answer: &T, pending: &T, - ) -> Fallible> { + ) -> Fallible> { let mut this = AnswerSubstitutor { table, environment, From ab299640501144a7043789049bd0bf84b58f01a0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 21 May 2018 04:46:28 -0400 Subject: [PATCH 2/6] pull all the types into `Context` --- chalk-engine/src/context.rs | 50 ++++++++++++++--------------- chalk-engine/src/context/prelude.rs | 1 - chalk-engine/src/derived.rs | 18 +++++------ chalk-engine/src/hh.rs | 18 +++++------ chalk-engine/src/lib.rs | 30 ++++++++--------- chalk-engine/src/simplify.rs | 2 +- chalk-engine/src/table.rs | 6 ++-- src/solve/slg/implementation.rs | 28 +++++++--------- 8 files changed, 73 insertions(+), 80 deletions(-) diff --git a/chalk-engine/src/context.rs b/chalk-engine/src/context.rs index fdabe8fb65b..460b3b19aaf 100644 --- a/chalk-engine/src/context.rs +++ b/chalk-engine/src/context.rs @@ -6,29 +6,10 @@ use std::hash::Hash; crate mod prelude; -pub trait ExClauseContext: Sized + Debug { - /// Part of an answer: represents a canonicalized substitution, - /// combined with region constraints. See [the rustc-guide] for more information. - /// - /// [the rustc-guide]: https://rust-lang-nursery.github.io/rustc-guide/traits-canonicalization.html#canonicalizing-the-query-result - type CanonicalConstrainedSubst: Clone + Debug + Eq + Hash; - - /// Represents a substitution from the "canonical variables" found - /// in a canonical goal to specific values. - type Substitution: Debug; - - /// Represents a region constraint that will be propagated back - /// (but not verified). - type RegionConstraint: Debug; - - /// Represents a goal along with an environment. - type GoalInEnvironment: Debug + Clone + Eq + Hash; -} - /// The "context" in which the SLG solver operates. // FIXME(leodasvacas): Clone and Debug bounds are just for easy derive, // they are not actually necessary. -pub trait Context: Clone + Debug + ExClauseContext { +pub trait Context: Clone + Debug { type CanonicalExClause: Debug; /// A map between universes. These are produced when @@ -56,12 +37,24 @@ pub trait Context: Clone + Debug + ExClauseContext { /// completely opaque to the SLG solver; it is produced by /// `make_solution`. type Solution; -} -/// The set of types belonging to an "inference context"; in rustc, -/// these types are tied to the lifetime of the arena within which an -/// inference context operates. -pub trait InferenceContext: ExClauseContext { + /// Part of an answer: represents a canonicalized substitution, + /// combined with region constraints. See [the rustc-guide] for more information. + /// + /// [the rustc-guide]: https://rust-lang-nursery.github.io/rustc-guide/traits-canonicalization.html#canonicalizing-the-query-result + type CanonicalConstrainedSubst: Clone + Debug + Eq + Hash; + + /// Represents a substitution from the "canonical variables" found + /// in a canonical goal to specific values. + type Substitution: Debug; + + /// Represents a region constraint that will be propagated back + /// (but not verified). + type RegionConstraint: Debug; + + /// Represents a goal along with an environment. + type GoalInEnvironment: Debug + Clone + Eq + Hash; + /// Represents a set of hypotheses that are assumed to be true. type Environment: Debug + Clone; @@ -94,7 +87,12 @@ pub trait InferenceContext: ExClauseContext { /// The successful result from unification: contains new subgoals /// and things that can be attached to an ex-clause. type UnificationResult; +} +/// The set of types belonging to an "inference context"; in rustc, +/// these types are tied to the lifetime of the arena within which an +/// inference context operates. +pub trait InferenceContext: Context { fn goal_in_environment( environment: &Self::Environment, goal: Self::Goal, @@ -114,7 +112,7 @@ pub trait InferenceContext: ExClauseContext { /// conversion -- that is, we convert the outermost goal into an /// `HhGoal`, but the goals contained within are left as context /// goals. - fn into_hh_goal(goal: Self::Goal) -> HhGoal; + fn into_hh_goal(goal: Self::Goal) -> HhGoal; /// Add the residual subgoals as new subgoals of the ex-clause. /// Also add region constraints. diff --git a/chalk-engine/src/context/prelude.rs b/chalk-engine/src/context/prelude.rs index a084b09424e..39cf99b0904 100644 --- a/chalk-engine/src/context/prelude.rs +++ b/chalk-engine/src/context/prelude.rs @@ -1,6 +1,5 @@ #![allow(unused_imports)] // rustc bug -crate use super::ExClauseContext; crate use super::Context; crate use super::ContextOps; crate use super::AggregateOps; diff --git a/chalk-engine/src/derived.rs b/chalk-engine/src/derived.rs index 42e3f72cb00..37b95ad1909 100644 --- a/chalk-engine/src/derived.rs +++ b/chalk-engine/src/derived.rs @@ -7,7 +7,7 @@ use std::hash::{Hash, Hasher}; use std::mem; use super::*; -impl PartialEq for DelayedLiteralSet { +impl PartialEq for DelayedLiteralSet { fn eq(&self, other: &Self) -> bool { let DelayedLiteralSet { delayed_literals: a1 } = self; let DelayedLiteralSet { delayed_literals: a2 } = other; @@ -15,12 +15,12 @@ impl PartialEq for DelayedLiteralSet { } } -impl Eq for DelayedLiteralSet { +impl Eq for DelayedLiteralSet { } /////////////////////////////////////////////////////////////////////////// -impl PartialEq for DelayedLiteral { +impl PartialEq for DelayedLiteral { fn eq(&self, other: &Self) -> bool { if mem::discriminant(self) != mem::discriminant(other) { return false; @@ -41,10 +41,10 @@ impl PartialEq for DelayedLiteral { } } -impl Eq for DelayedLiteral { +impl Eq for DelayedLiteral { } -impl Hash for DelayedLiteral { +impl Hash for DelayedLiteral { fn hash(&self, hasher: &mut H) { mem::discriminant(self).hash(hasher); @@ -65,8 +65,8 @@ impl Hash for DelayedLiteral { /////////////////////////////////////////////////////////////////////////// -impl PartialEq for Literal { - fn eq(&self, other: &Literal) -> bool { +impl PartialEq for Literal { + fn eq(&self, other: &Literal) -> bool { match (self, other) { (Literal::Positive(goal1), Literal::Positive(goal2)) | (Literal::Negative(goal1), Literal::Negative(goal2)) => goal1 == goal2, @@ -76,10 +76,10 @@ impl PartialEq for Literal { } } -impl Eq for Literal { +impl Eq for Literal { } -impl Hash for Literal { +impl Hash for Literal { fn hash(&self, state: &mut H) { mem::discriminant(self).hash(state); match self { diff --git a/chalk-engine/src/hh.rs b/chalk-engine/src/hh.rs index 29494acc01c..fa4b0f7f2db 100644 --- a/chalk-engine/src/hh.rs +++ b/chalk-engine/src/hh.rs @@ -1,17 +1,17 @@ -use crate::context::{Context, InferenceContext}; +use crate::context::Context; #[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] /// A general goal; this is the full range of questions you can pose to Chalk. -pub enum HhGoal> { +pub enum HhGoal { /// Introduces a binding at depth 0, shifting other bindings up /// (deBruijn index). - ForAll(I::BindersGoal), - Exists(I::BindersGoal), - Implies(Vec, I::Goal), - And(I::Goal, I::Goal), - Not(I::Goal), - Unify(I::Parameter, I::Parameter), - DomainGoal(I::DomainGoal), + ForAll(C::BindersGoal), + Exists(C::BindersGoal), + Implies(Vec, C::Goal), + And(C::Goal, C::Goal), + Not(C::Goal), + Unify(C::Parameter, C::Parameter), + DomainGoal(C::DomainGoal), /// Indicates something that cannot be proven to be true or false /// definitively. This can occur with overflow but also with diff --git a/chalk-engine/src/lib.rs b/chalk-engine/src/lib.rs index bc88f4458ec..805bdacc2e7 100644 --- a/chalk-engine/src/lib.rs +++ b/chalk-engine/src/lib.rs @@ -66,7 +66,7 @@ extern crate stacker; extern crate fxhash; -use crate::context::{Context, ExClauseContext}; +use crate::context::Context; use fxhash::FxHashSet; use std::cmp::min; use std::usize; @@ -111,20 +111,20 @@ struct DepthFirstNumber { /// The paper describes these as `A :- D | G`. #[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct ExClause { +pub struct ExClause { /// The substitution which, applied to the goal of our table, /// would yield A. - pub subst: E::Substitution, + pub subst: C::Substitution, /// Delayed literals: things that we depend on negatively, /// but which have not yet been fully evaluated. - pub delayed_literals: Vec>, + pub delayed_literals: Vec>, /// Region constraints we have accumulated. - pub constraints: Vec, + pub constraints: Vec, /// Subgoals: literals that must be proven - pub subgoals: Vec>, + pub subgoals: Vec>, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] @@ -170,12 +170,12 @@ enum InnerDelayedLiteralSets { /// delayed literal, which in turn forces its subgoal to be delayed, /// and so forth. Therefore, we store canonicalized goals.) #[derive(Clone, Debug, Default)] -struct DelayedLiteralSet { - delayed_literals: FxHashSet>, +struct DelayedLiteralSet { + delayed_literals: FxHashSet>, } #[derive(Clone, Debug)] -pub enum DelayedLiteral { +pub enum DelayedLiteral { /// Something which can never be proven nor disproven. Inserted /// when truncation triggers; doesn't arise normally. CannotProve(()), @@ -189,14 +189,14 @@ pub enum DelayedLiteral { /// **conditional** answer (the `CanonicalConstrainedSubst`) within the /// given table, but we have to come back later and see whether /// that answer turns out to be true. - Positive(TableIndex, E::CanonicalConstrainedSubst), + Positive(TableIndex, C::CanonicalConstrainedSubst), } /// Either `A` or `~A`, where `A` is a `Env |- Goal`. #[derive(Clone, Debug)] -pub enum Literal { // FIXME: pub b/c fold - Positive(E::GoalInEnvironment), - Negative(E::GoalInEnvironment), +pub enum Literal { // FIXME: pub b/c fold + Positive(C::GoalInEnvironment), + Negative(C::GoalInEnvironment), } /// The `Minimums` structure is used to track the dependencies between @@ -272,12 +272,12 @@ impl DelayedLiteralSets { } } -impl DelayedLiteralSet { +impl DelayedLiteralSet { fn is_empty(&self) -> bool { self.delayed_literals.is_empty() } - fn is_subset(&self, other: &DelayedLiteralSet) -> bool { + fn is_subset(&self, other: &DelayedLiteralSet) -> bool { self.delayed_literals .iter() .all(|elem| other.delayed_literals.contains(elem)) diff --git a/chalk-engine/src/simplify.rs b/chalk-engine/src/simplify.rs index 76d6c3f26ec..9120f4b574b 100644 --- a/chalk-engine/src/simplify.rs +++ b/chalk-engine/src/simplify.rs @@ -12,7 +12,7 @@ impl> Forest { infer: &mut dyn InferenceTable, subst: I::Substitution, initial_environment: &I::Environment, - initial_hh_goal: HhGoal, + initial_hh_goal: HhGoal, ) -> Fallible> { let mut ex_clause = ExClause { subst, diff --git a/chalk-engine/src/table.rs b/chalk-engine/src/table.rs index 209864ec8f6..ca83bc9dfef 100644 --- a/chalk-engine/src/table.rs +++ b/chalk-engine/src/table.rs @@ -42,9 +42,9 @@ index_struct! { /// goal for a particular table (modulo delayed literals). It contains /// a substitution #[derive(Clone, Debug)] -pub struct Answer { - crate subst: E::CanonicalConstrainedSubst, - crate delayed_literals: DelayedLiteralSet, +pub struct Answer { + crate subst: C::CanonicalConstrainedSubst, + crate delayed_literals: DelayedLiteralSet, } impl Table { diff --git a/src/solve/slg/implementation.rs b/src/solve/slg/implementation.rs index 1ec625b757b..f72d39b052f 100644 --- a/src/solve/slg/implementation.rs +++ b/src/solve/slg/implementation.rs @@ -49,13 +49,6 @@ impl SlgContext { } } -impl context::ExClauseContext for SlgContext { - type CanonicalConstrainedSubst = Canonical; - type GoalInEnvironment = InEnvironment; - type Substitution = Substitution; - type RegionConstraint = InEnvironment; -} - impl context::Context for SlgContext { type CanonicalGoalInEnvironment = Canonical>; type CanonicalExClause = Canonical>; @@ -63,6 +56,17 @@ impl context::Context for SlgContext { type UniverseMap = UniverseMap; type InferenceNormalizedSubst = Substitution; type Solution = Solution; + type Environment = Arc; + type DomainGoal = DomainGoal; + type Goal = Goal; + type BindersGoal = Binders>; + type Parameter = Parameter; + type ProgramClause = ProgramClause; + type UnificationResult = UnificationResult; + type CanonicalConstrainedSubst = Canonical; + type GoalInEnvironment = InEnvironment; + type Substitution = Substitution; + type RegionConstraint = InEnvironment; } impl context::ContextOps for SlgContext { @@ -170,14 +174,6 @@ impl context::TruncateOps for TruncatingInferenceTable { impl context::InferenceTable for TruncatingInferenceTable {} impl context::InferenceContext for SlgContext { - type Environment = Arc; - type DomainGoal = DomainGoal; - type Goal = Goal; - type BindersGoal = Binders>; - type Parameter = Parameter; - type ProgramClause = ProgramClause; - type UnificationResult = UnificationResult; - fn goal_in_environment(environment: &Arc, goal: Goal) -> InEnvironment { InEnvironment::new(environment, goal) } @@ -190,7 +186,7 @@ impl context::InferenceContext for SlgContext { Goal::CannotProve(()) } - fn into_hh_goal(goal: Self::Goal) -> HhGoal { + fn into_hh_goal(goal: Self::Goal) -> HhGoal { match goal { Goal::Quantified(QuantifierKind::ForAll, binders_goal) => HhGoal::ForAll(binders_goal), Goal::Quantified(QuantifierKind::Exists, binders_goal) => HhGoal::Exists(binders_goal), From b402078310ee9db9b6011a6796ca50c115bb7b8f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 21 May 2018 04:54:28 -0400 Subject: [PATCH 3/6] remove InferenceContext and merge into Context --- chalk-engine/src/context.rs | 48 ++++++----- chalk-engine/src/context/prelude.rs | 1 - chalk-engine/src/logic.rs | 38 ++++----- chalk-engine/src/simplify.rs | 6 +- chalk-engine/src/strand.rs | 6 +- src/lib.rs | 1 + src/solve/slg/implementation.rs | 97 ++++++++++++----------- src/solve/slg/implementation/resolvent.rs | 8 +- 8 files changed, 112 insertions(+), 93 deletions(-) diff --git a/chalk-engine/src/context.rs b/chalk-engine/src/context.rs index 460b3b19aaf..7e5a31243ae 100644 --- a/chalk-engine/src/context.rs +++ b/chalk-engine/src/context.rs @@ -6,9 +6,25 @@ use std::hash::Hash; crate mod prelude; -/// The "context" in which the SLG solver operates. -// FIXME(leodasvacas): Clone and Debug bounds are just for easy derive, -// they are not actually necessary. +/// The "context" in which the SLG solver operates. It defines all the +/// types that the SLG solver may need to refer to, as well as a few +/// very simple interconversion methods. +/// +/// At any given time, the SLG solver may have more than one context +/// active. First, there is always the *global* context, but when we +/// are in the midst of pursuing some particular strange, we will +/// instantiate a second context just for that work, via the +/// `instantiate_ucanonical_goal` and `instantiate_ex_clause` methods. +/// +/// In the chalk implementation, these two contexts are mapped to the +/// same type. But in the rustc implementation, this second context +/// corresponds to a fresh arena, and data allocated in that second +/// context will be freed once the work is done. (The "canonicalizing" +/// steps offer a way to convert data from the inference context back +/// into the global context.) +/// +/// FIXME: Clone and Debug bounds are just for easy derive, they are +/// not actually necessary. But dang are they convenient. pub trait Context: Clone + Debug { type CanonicalExClause: Debug; @@ -87,12 +103,8 @@ pub trait Context: Clone + Debug { /// The successful result from unification: contains new subgoals /// and things that can be attached to an ex-clause. type UnificationResult; -} -/// The set of types belonging to an "inference context"; in rustc, -/// these types are tied to the lifetime of the arena within which an -/// inference context operates. -pub trait InferenceContext: Context { + /// Given an environment and a goal, glue them together to create a `GoalInEnvironment`. fn goal_in_environment( environment: &Self::Environment, goal: Self::Goal, @@ -114,10 +126,6 @@ pub trait InferenceContext: Context { /// goals. fn into_hh_goal(goal: Self::Goal) -> HhGoal; - /// Add the residual subgoals as new subgoals of the ex-clause. - /// Also add region constraints. - fn into_ex_clause(result: Self::UnificationResult, ex_clause: &mut ExClause); - // Used by: simplify fn add_clauses( env: &Self::Environment, @@ -199,7 +207,7 @@ pub trait ContextOps: Sized + Clone + Debug + AggregateOps { pub trait WithInstantiatedUCanonicalGoal { type Output; - fn with>( + fn with( self, infer: &mut dyn InferenceTable, subst: I::Substitution, @@ -217,7 +225,7 @@ pub trait WithInstantiatedUCanonicalGoal { pub trait WithInstantiatedExClause { type Output; - fn with>( + fn with( self, infer: &mut dyn InferenceTable, ex_clause: ExClause, @@ -235,13 +243,13 @@ pub trait AggregateOps { /// An "inference table" contains the state to support unification and /// other operations on terms. -pub trait InferenceTable>: +pub trait InferenceTable: ResolventOps + TruncateOps + UnificationOps { } /// Methods for unifying and manipulating terms and binders. -pub trait UnificationOps> { +pub trait UnificationOps { /// Returns the set of program clauses that might apply to /// `goal`. (This set can be over-approximated, naturally.) fn program_clauses( @@ -298,6 +306,10 @@ pub trait UnificationOps> { a: &I::Parameter, b: &I::Parameter, ) -> Fallible; + + /// Add the residual subgoals as new subgoals of the ex-clause. + /// Also add region constraints. + fn into_ex_clause(&mut self, result: I::UnificationResult, ex_clause: &mut ExClause); } /// "Truncation" (called "abstraction" in the papers referenced below) @@ -312,7 +324,7 @@ pub trait UnificationOps> { /// - Riguzzi and Swift; ACM Transactions on Computational Logic 2013 /// - Radial Restraint /// - Grosof and Swift; 2013 -pub trait TruncateOps> { +pub trait TruncateOps { /// If `subgoal` is too large, return a truncated variant (else /// return `None`). fn truncate_goal(&mut self, subgoal: &I::GoalInEnvironment) -> Option; @@ -322,7 +334,7 @@ pub trait TruncateOps> { fn truncate_answer(&mut self, subst: &I::Substitution) -> Option; } -pub trait ResolventOps> { +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). diff --git a/chalk-engine/src/context/prelude.rs b/chalk-engine/src/context/prelude.rs index 39cf99b0904..978d14f5ae2 100644 --- a/chalk-engine/src/context/prelude.rs +++ b/chalk-engine/src/context/prelude.rs @@ -6,4 +6,3 @@ crate use super::AggregateOps; crate use super::ResolventOps; crate use super::TruncateOps; crate use super::InferenceTable; -crate use super::InferenceContext; diff --git a/chalk-engine/src/logic.rs b/chalk-engine/src/logic.rs index 5842e2f2b87..93548ced28d 100644 --- a/chalk-engine/src/logic.rs +++ b/chalk-engine/src/logic.rs @@ -293,7 +293,7 @@ impl> Forest { WithInstantiatedExClause for With { type Output = OP::Output; - fn with>( + fn with( self, infer: &mut dyn InferenceTable, ex_clause: ExClause, @@ -307,7 +307,7 @@ impl> Forest { } } - fn canonicalize_strand(strand: Strand<'_, C, impl InferenceContext>) -> CanonicalStrand { + fn canonicalize_strand(strand: Strand<'_, C, impl Context>) -> CanonicalStrand { let Strand { infer, ex_clause, @@ -316,7 +316,7 @@ impl> Forest { Self::canonicalize_strand_from(&mut *infer, &ex_clause, selected_subgoal) } - fn canonicalize_strand_from>( + fn canonicalize_strand_from( infer: &mut dyn InferenceTable, ex_clause: &ExClause, selected_subgoal: Option>, @@ -431,7 +431,7 @@ impl> Forest { fn delay_strand_after_cycle( table: TableIndex, - mut strand: Strand<'_, C, impl InferenceContext>, + mut strand: Strand<'_, C, impl Context>, ) -> (CanonicalStrand, TableIndex) { let (subgoal_index, subgoal_table) = match &strand.selected_subgoal { Some(selected_subgoal) => ( @@ -467,7 +467,7 @@ impl> Forest { fn pursue_strand( &mut self, depth: StackIndex, - mut strand: Strand<'_, C, impl InferenceContext>, + mut strand: Strand<'_, C, impl Context>, ) -> StrandResult { info_heading!( "pursue_strand(table={:?}, depth={:?}, ex_clause={:#?}, selected_subgoal={:?})", @@ -541,7 +541,7 @@ impl> Forest { fn pursue_answer( &mut self, depth: StackIndex, - strand: Strand<'_, C, impl InferenceContext>, + strand: Strand<'_, C, impl Context>, ) -> StrandResult { let table = self.stack[depth].table; let Strand { @@ -662,7 +662,7 @@ impl> Forest { /// In terms of the NFTD paper, creating a new table corresponds /// to the *New Subgoal* step as well as the *Program Clause /// Resolution* steps. - fn get_or_create_table_for_subgoal>( + fn get_or_create_table_for_subgoal( &mut self, infer: &mut dyn InferenceTable, subgoal: &Literal, @@ -741,7 +741,7 @@ impl> Forest { for PushInitialStrandsInstantiated<'a, C, CO> { type Output = (); - fn with>( + fn with( self, infer: &mut dyn InferenceTable, subst: I::Substitution, @@ -754,7 +754,7 @@ impl> Forest { } } - fn push_initial_strands_instantiated>( + fn push_initial_strands_instantiated( &mut self, table: TableIndex, infer: &mut dyn InferenceTable, @@ -814,7 +814,7 @@ impl> Forest { /// truncate the goal to ensure termination. /// /// This technique is described in the SA paper. - fn abstract_positive_literal>( + fn abstract_positive_literal( &mut self, infer: &mut dyn InferenceTable, subgoal: &I::GoalInEnvironment, @@ -858,7 +858,7 @@ impl> Forest { /// fail to yield a useful result, for example if free existential /// variables appear in `subgoal` (in which case the execution is /// said to "flounder"). - fn abstract_negative_literal>( + fn abstract_negative_literal( &mut self, infer: &mut dyn InferenceTable, subgoal: &I::GoalInEnvironment, @@ -973,7 +973,7 @@ impl> Forest { fn pursue_positive_subgoal( &mut self, depth: StackIndex, - mut strand: Strand<'_, C, impl InferenceContext>, + mut strand: Strand<'_, C, impl Context>, selected_subgoal: &SelectedSubgoal, ) -> StrandResult { let table = self.stack[depth].table; @@ -1097,7 +1097,7 @@ impl> Forest { /// Used whenever we process an answer (whether new or cached) on /// a positive edge (the SLG POSITIVE RETURN operation). Truncates /// the resolvent (or factor) if it has grown too large. - fn truncate_returned>( + fn truncate_returned( &self, ex_clause: ExClause, infer: &mut dyn InferenceTable, @@ -1164,7 +1164,7 @@ impl> Forest { fn pursue_strand_recursively( &mut self, depth: StackIndex, - strand: Strand<'_, C, impl InferenceContext>, + strand: Strand<'_, C, impl Context>, ) -> StrandResult { ::crate::maybe_grow_stack(|| self.pursue_strand(depth, strand)) } @@ -1175,7 +1175,7 @@ impl> Forest { fn push_strand_pursuing_next_answer( &mut self, depth: StackIndex, - strand: &mut Strand<'_, C, impl InferenceContext>, + strand: &mut Strand<'_, C, impl Context>, selected_subgoal: &SelectedSubgoal, ) { let table = self.stack[depth].table; @@ -1191,7 +1191,7 @@ impl> Forest { fn pursue_negative_subgoal( &mut self, depth: StackIndex, - strand: Strand<'_, C, impl InferenceContext>, + strand: Strand<'_, C, impl Context>, selected_subgoal: &SelectedSubgoal, ) -> StrandResult { let table = self.stack[depth].table; @@ -1311,7 +1311,7 @@ impl> Forest { trait WithInstantiatedStrand> { type Output; - fn with(self, strand: Strand<'_, C, impl InferenceContext>) -> Self::Output; + fn with(self, strand: Strand<'_, C, impl Context>) -> Self::Output; } struct PursueStrand<'a, C: Context + 'a, CO: ContextOps + 'a> { @@ -1322,7 +1322,7 @@ struct PursueStrand<'a, C: Context + 'a, CO: ContextOps + 'a> { impl> WithInstantiatedStrand for PursueStrand<'a, C, CO> { type Output = StrandResult; - fn with(self, strand: Strand<'_, C, impl InferenceContext>) -> Self::Output { + fn with(self, strand: Strand<'_, C, impl Context>) -> Self::Output { self.forest.pursue_strand(self.depth, strand) } } @@ -1334,7 +1334,7 @@ struct DelayStrandAfterCycle { impl> WithInstantiatedStrand for DelayStrandAfterCycle { type Output = (CanonicalStrand, TableIndex); - fn with(self, strand: Strand<'_, C, impl InferenceContext>) -> Self::Output { + fn with(self, strand: Strand<'_, C, impl Context>) -> Self::Output { >::delay_strand_after_cycle(self.table, strand) } } diff --git a/chalk-engine/src/simplify.rs b/chalk-engine/src/simplify.rs index 9120f4b574b..9c038e16f5a 100644 --- a/chalk-engine/src/simplify.rs +++ b/chalk-engine/src/simplify.rs @@ -8,7 +8,7 @@ impl> Forest { /// Simplifies an HH goal into a series of positive domain goals /// and negative HH goals. This operation may fail if the HH goal /// includes unifications that cannot be completed. - pub(super) fn simplify_hh_goal>( + pub(super) fn simplify_hh_goal( infer: &mut dyn InferenceTable, subst: I::Substitution, initial_environment: &I::Environment, @@ -48,8 +48,8 @@ impl> Forest { .push(Literal::Negative(I::goal_in_environment(&environment, subgoal))); } HhGoal::Unify(a, b) => { - I::into_ex_clause(infer.unify_parameters(&environment, &a, &b)?, - &mut ex_clause) + let result = infer.unify_parameters(&environment, &a, &b)?; + infer.into_ex_clause(result, &mut ex_clause) } HhGoal::DomainGoal(domain_goal) => { ex_clause diff --git a/chalk-engine/src/strand.rs b/chalk-engine/src/strand.rs index 2353908c63f..1e8ea35ca81 100644 --- a/chalk-engine/src/strand.rs +++ b/chalk-engine/src/strand.rs @@ -1,6 +1,6 @@ use std::fmt::{Debug, Error, Formatter}; use crate::{ExClause, TableIndex}; -use crate::context::{Context, InferenceContext, InferenceTable}; +use crate::context::{Context, InferenceTable}; use crate::table::AnswerIndex; #[derive(Debug)] @@ -11,7 +11,7 @@ crate struct CanonicalStrand { crate selected_subgoal: Option>, } -crate struct Strand<'table, C: Context + 'table, I: InferenceContext + 'table> { +crate struct Strand<'table, C: Context + 'table, I: Context + 'table> { crate infer: &'table mut dyn InferenceTable, pub(super) ex_clause: ExClause, @@ -36,7 +36,7 @@ crate struct SelectedSubgoal { crate universe_map: C::UniverseMap, } -impl<'table, C: Context, I: InferenceContext> Debug for Strand<'table, C, I> { +impl<'table, C: Context, I: Context> Debug for Strand<'table, C, I> { fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { fmt.debug_struct("Strand") .field("ex_clause", &self.ex_clause) diff --git a/src/lib.rs b/src/lib.rs index 9a87e92b99c..b88e90a91be 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,7 @@ #![feature(specialization)] #![feature(step_trait)] #![feature(non_modrs_mods)] +#![feature(underscore_imports)] extern crate chalk_parse; #[macro_use] diff --git a/src/solve/slg/implementation.rs b/src/solve/slg/implementation.rs index f72d39b052f..9fe7d1991b2 100644 --- a/src/solve/slg/implementation.rs +++ b/src/solve/slg/implementation.rs @@ -67,6 +67,39 @@ impl context::Context for SlgContext { type GoalInEnvironment = InEnvironment; type Substitution = Substitution; type RegionConstraint = InEnvironment; + + fn goal_in_environment(environment: &Arc, goal: Goal) -> InEnvironment { + InEnvironment::new(environment, goal) + } + + fn into_goal(domain_goal: Self::DomainGoal) -> Self::Goal { + domain_goal.cast() + } + + fn cannot_prove() -> Self::Goal { + Goal::CannotProve(()) + } + + fn into_hh_goal(goal: Self::Goal) -> HhGoal { + match goal { + Goal::Quantified(QuantifierKind::ForAll, binders_goal) => HhGoal::ForAll(binders_goal), + Goal::Quantified(QuantifierKind::Exists, binders_goal) => HhGoal::Exists(binders_goal), + Goal::Implies(dg, subgoal) => HhGoal::Implies(dg, *subgoal), + Goal::And(g1, g2) => HhGoal::And(*g1, *g2), + Goal::Not(g1) => HhGoal::Not(*g1), + Goal::Leaf(LeafGoal::EqGoal(EqGoal { a, b })) => HhGoal::Unify(a, b), + Goal::Leaf(LeafGoal::DomainGoal(domain_goal)) => HhGoal::DomainGoal(domain_goal), + Goal::CannotProve(()) => HhGoal::CannotProve, + } + } + + // Used by: simplify + fn add_clauses( + env: &Self::Environment, + clauses: impl IntoIterator, + ) -> Self::Environment { + Environment::add_clauses(env, clauses) + } } impl context::ContextOps for SlgContext { @@ -173,51 +206,6 @@ impl context::TruncateOps for TruncatingInferenceTable { impl context::InferenceTable for TruncatingInferenceTable {} -impl context::InferenceContext for SlgContext { - fn goal_in_environment(environment: &Arc, goal: Goal) -> InEnvironment { - InEnvironment::new(environment, goal) - } - - fn into_goal(domain_goal: Self::DomainGoal) -> Self::Goal { - domain_goal.cast() - } - - fn cannot_prove() -> Self::Goal { - Goal::CannotProve(()) - } - - fn into_hh_goal(goal: Self::Goal) -> HhGoal { - match goal { - Goal::Quantified(QuantifierKind::ForAll, binders_goal) => HhGoal::ForAll(binders_goal), - Goal::Quantified(QuantifierKind::Exists, binders_goal) => HhGoal::Exists(binders_goal), - Goal::Implies(dg, subgoal) => HhGoal::Implies(dg, *subgoal), - Goal::And(g1, g2) => HhGoal::And(*g1, *g2), - Goal::Not(g1) => HhGoal::Not(*g1), - Goal::Leaf(LeafGoal::EqGoal(EqGoal { a, b })) => HhGoal::Unify(a, b), - Goal::Leaf(LeafGoal::DomainGoal(domain_goal)) => HhGoal::DomainGoal(domain_goal), - Goal::CannotProve(()) => HhGoal::CannotProve, - } - } - - fn into_ex_clause( - result: Self::UnificationResult, - ex_clause: &mut ExClause, - ) { - ex_clause - .subgoals - .extend(result.goals.into_iter().casted().map(Literal::Positive)); - ex_clause.constraints.extend(result.constraints); - } - - // Used by: simplify - fn add_clauses( - env: &Self::Environment, - clauses: impl IntoIterator, - ) -> Self::Environment { - Environment::add_clauses(env, clauses) - } -} - impl context::UnificationOps for TruncatingInferenceTable { fn program_clauses( &self, @@ -313,6 +301,25 @@ impl context::UnificationOps for TruncatingInferenceTabl fn lift_delayed_literal(&self, c: DelayedLiteral) -> DelayedLiteral { c } + + fn into_ex_clause( + &mut self, + result: UnificationResult, + ex_clause: &mut ExClause, + ) { + into_ex_clause(result, ex_clause) + } +} + +/// Helper function +fn into_ex_clause( + result: UnificationResult, + ex_clause: &mut ExClause, +) { + ex_clause + .subgoals + .extend(result.goals.into_iter().casted().map(Literal::Positive)); + ex_clause.constraints.extend(result.constraints); } impl Substitution { diff --git a/src/solve/slg/implementation/resolvent.rs b/src/solve/slg/implementation/resolvent.rs index 2191af9ce18..65cf83ee767 100644 --- a/src/solve/slg/implementation/resolvent.rs +++ b/src/solve/slg/implementation/resolvent.rs @@ -3,10 +3,10 @@ use crate::fold::shift::Shift; use crate::fold::Fold; use crate::ir::*; use crate::solve::infer::InferenceTable; -use crate::solve::slg::implementation::{SlgContext, TruncatingInferenceTable}; +use crate::solve::slg::implementation::{self, SlgContext, TruncatingInferenceTable}; use crate::zip::{Zip, Zipper}; -use chalk_engine::context::{self, InferenceContext}; +use chalk_engine::context; use chalk_engine::{ExClause, Literal}; use std::sync::Arc; @@ -105,7 +105,7 @@ impl context::ResolventOps for TruncatingInferenceTable }; // Add the subgoals/region-constraints that unification gave us. - SlgContext::into_ex_clause(unification_result, &mut ex_clause); + implementation::into_ex_clause(unification_result, &mut ex_clause); // Add the `conditions` from the program clause into the result too. ex_clause @@ -293,7 +293,7 @@ impl<'t> AnswerSubstitutor<'t> { ) }); - SlgContext::into_ex_clause( + implementation::into_ex_clause( self.table .unify(&self.environment, answer_param, pending_shifted)?, &mut self.ex_clause, From 125e0a8b3744c0521eba98a0acb5d8b7051066a8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 21 May 2018 05:51:30 -0400 Subject: [PATCH 4/6] move some more methods to InferenceTable I predict that these may need access to the interners etc in rustc --- chalk-engine/src/context.rs | 35 ++++++++++++------------- chalk-engine/src/logic.rs | 2 +- chalk-engine/src/simplify.rs | 12 ++++----- src/solve/slg/implementation.rs | 45 +++++++++++++++++---------------- 4 files changed, 48 insertions(+), 46 deletions(-) diff --git a/chalk-engine/src/context.rs b/chalk-engine/src/context.rs index 7e5a31243ae..41ad5c36c94 100644 --- a/chalk-engine/src/context.rs +++ b/chalk-engine/src/context.rs @@ -104,7 +104,8 @@ pub trait Context: Clone + Debug { /// and things that can be attached to an ex-clause. type UnificationResult; - /// Given an environment and a goal, glue them together to create a `GoalInEnvironment`. + /// Given an environment and a goal, glue them together to create + /// a `GoalInEnvironment`. fn goal_in_environment( environment: &Self::Environment, goal: Self::Goal, @@ -115,22 +116,6 @@ pub trait Context: Clone + Debug { /// Create a "cannot prove" goal (see `HhGoal::CannotProve`). fn cannot_prove() -> Self::Goal; - - /// Convert the context's goal type into the `HhGoal` type that - /// the SLG solver understands. The expectation is that the - /// context's goal type has the same set of variants, but with - /// different names and a different setup. If you inspect - /// `HhGoal`, you will see that this is a "shallow" or "lazy" - /// conversion -- that is, we convert the outermost goal into an - /// `HhGoal`, but the goals contained within are left as context - /// goals. - fn into_hh_goal(goal: Self::Goal) -> HhGoal; - - // Used by: simplify - fn add_clauses( - env: &Self::Environment, - clauses: impl IntoIterator, - ) -> Self::Environment; } pub trait ContextOps: Sized + Clone + Debug + AggregateOps { @@ -246,6 +231,22 @@ pub trait AggregateOps { pub trait InferenceTable: ResolventOps + TruncateOps + UnificationOps { + /// Convert the context's goal type into the `HhGoal` type that + /// the SLG solver understands. The expectation is that the + /// context's goal type has the same set of variants, but with + /// different names and a different setup. If you inspect + /// `HhGoal`, you will see that this is a "shallow" or "lazy" + /// conversion -- that is, we convert the outermost goal into an + /// `HhGoal`, but the goals contained within are left as context + /// goals. + fn into_hh_goal(&mut self, goal: I::Goal) -> HhGoal; + + // Used by: simplify + fn add_clauses( + &mut self, + env: &I::Environment, + clauses: Vec, + ) -> I::Environment; } /// Methods for unifying and manipulating terms and binders. diff --git a/chalk-engine/src/logic.rs b/chalk-engine/src/logic.rs index 93548ced28d..ee2d27b6999 100644 --- a/chalk-engine/src/logic.rs +++ b/chalk-engine/src/logic.rs @@ -763,7 +763,7 @@ impl> Forest { goal: I::Goal, ) { let table_ref = &mut self.tables[table]; - match I::into_hh_goal(goal) { + match infer.into_hh_goal(goal) { HhGoal::DomainGoal(domain_goal) => { let clauses = infer.program_clauses(&environment, &domain_goal); for clause in clauses { diff --git a/chalk-engine/src/simplify.rs b/chalk-engine/src/simplify.rs index 9c038e16f5a..b98efa7569e 100644 --- a/chalk-engine/src/simplify.rs +++ b/chalk-engine/src/simplify.rs @@ -28,19 +28,19 @@ impl> Forest { match hh_goal { HhGoal::ForAll(subgoal) => { let subgoal = infer.instantiate_binders_universally(&subgoal); - pending_goals.push((environment, I::into_hh_goal(subgoal))); + pending_goals.push((environment, infer.into_hh_goal(subgoal))); } HhGoal::Exists(subgoal) => { let subgoal = infer.instantiate_binders_existentially(&subgoal); - pending_goals.push((environment, I::into_hh_goal(subgoal))) + pending_goals.push((environment, infer.into_hh_goal(subgoal))) } HhGoal::Implies(wc, subgoal) => { - let new_environment = I::add_clauses(&environment, wc); - pending_goals.push((new_environment, I::into_hh_goal(subgoal))); + let new_environment = infer.add_clauses(&environment, wc); + pending_goals.push((new_environment, infer.into_hh_goal(subgoal))); } HhGoal::And(subgoal1, subgoal2) => { - pending_goals.push((environment.clone(), I::into_hh_goal(subgoal1))); - pending_goals.push((environment, I::into_hh_goal(subgoal2))); + pending_goals.push((environment.clone(), infer.into_hh_goal(subgoal1))); + pending_goals.push((environment, infer.into_hh_goal(subgoal2))); } HhGoal::Not(subgoal) => { ex_clause diff --git a/src/solve/slg/implementation.rs b/src/solve/slg/implementation.rs index 9fe7d1991b2..edbd3b3f692 100644 --- a/src/solve/slg/implementation.rs +++ b/src/solve/slg/implementation.rs @@ -79,27 +79,6 @@ impl context::Context for SlgContext { fn cannot_prove() -> Self::Goal { Goal::CannotProve(()) } - - fn into_hh_goal(goal: Self::Goal) -> HhGoal { - match goal { - Goal::Quantified(QuantifierKind::ForAll, binders_goal) => HhGoal::ForAll(binders_goal), - Goal::Quantified(QuantifierKind::Exists, binders_goal) => HhGoal::Exists(binders_goal), - Goal::Implies(dg, subgoal) => HhGoal::Implies(dg, *subgoal), - Goal::And(g1, g2) => HhGoal::And(*g1, *g2), - Goal::Not(g1) => HhGoal::Not(*g1), - Goal::Leaf(LeafGoal::EqGoal(EqGoal { a, b })) => HhGoal::Unify(a, b), - Goal::Leaf(LeafGoal::DomainGoal(domain_goal)) => HhGoal::DomainGoal(domain_goal), - Goal::CannotProve(()) => HhGoal::CannotProve, - } - } - - // Used by: simplify - fn add_clauses( - env: &Self::Environment, - clauses: impl IntoIterator, - ) -> Self::Environment { - Environment::add_clauses(env, clauses) - } } impl context::ContextOps for SlgContext { @@ -204,7 +183,29 @@ impl context::TruncateOps for TruncatingInferenceTable { } } -impl context::InferenceTable for TruncatingInferenceTable {} +impl context::InferenceTable for TruncatingInferenceTable { + fn into_hh_goal(&mut self, goal: Goal) -> HhGoal { + match goal { + Goal::Quantified(QuantifierKind::ForAll, binders_goal) => HhGoal::ForAll(binders_goal), + Goal::Quantified(QuantifierKind::Exists, binders_goal) => HhGoal::Exists(binders_goal), + Goal::Implies(dg, subgoal) => HhGoal::Implies(dg, *subgoal), + Goal::And(g1, g2) => HhGoal::And(*g1, *g2), + Goal::Not(g1) => HhGoal::Not(*g1), + Goal::Leaf(LeafGoal::EqGoal(EqGoal { a, b })) => HhGoal::Unify(a, b), + Goal::Leaf(LeafGoal::DomainGoal(domain_goal)) => HhGoal::DomainGoal(domain_goal), + Goal::CannotProve(()) => HhGoal::CannotProve, + } + } + + // Used by: simplify + fn add_clauses( + &mut self, + env: &Arc, + clauses: Vec, + ) -> Arc { + Environment::add_clauses(env, clauses) + } +} impl context::UnificationOps for TruncatingInferenceTable { fn program_clauses( From 1f179eb4490bd6a5e347922074b300438741955e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 21 May 2018 05:53:49 -0400 Subject: [PATCH 5/6] don't hard-code the use of `Vec` --- chalk-engine/src/context.rs | 5 ++++- chalk-engine/src/hh.rs | 2 +- src/solve/slg/implementation.rs | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/chalk-engine/src/context.rs b/chalk-engine/src/context.rs index 41ad5c36c94..0b5cf70bfc7 100644 --- a/chalk-engine/src/context.rs +++ b/chalk-engine/src/context.rs @@ -100,6 +100,9 @@ pub trait Context: Clone + Debug { /// goal we are trying to solve to produce an ex-clause. type ProgramClause: Debug; + /// A vector of program clauses. + type ProgramClauses: Debug; + /// The successful result from unification: contains new subgoals /// and things that can be attached to an ex-clause. type UnificationResult; @@ -245,7 +248,7 @@ pub trait InferenceTable: fn add_clauses( &mut self, env: &I::Environment, - clauses: Vec, + clauses: I::ProgramClauses, ) -> I::Environment; } diff --git a/chalk-engine/src/hh.rs b/chalk-engine/src/hh.rs index fa4b0f7f2db..39af0ec6caf 100644 --- a/chalk-engine/src/hh.rs +++ b/chalk-engine/src/hh.rs @@ -7,7 +7,7 @@ pub enum HhGoal { /// (deBruijn index). ForAll(C::BindersGoal), Exists(C::BindersGoal), - Implies(Vec, C::Goal), + Implies(C::ProgramClauses, C::Goal), And(C::Goal, C::Goal), Not(C::Goal), Unify(C::Parameter, C::Parameter), diff --git a/src/solve/slg/implementation.rs b/src/solve/slg/implementation.rs index edbd3b3f692..9bedec2f9b8 100644 --- a/src/solve/slg/implementation.rs +++ b/src/solve/slg/implementation.rs @@ -62,6 +62,7 @@ impl context::Context for SlgContext { type BindersGoal = Binders>; type Parameter = Parameter; type ProgramClause = ProgramClause; + type ProgramClauses = Vec; type UnificationResult = UnificationResult; type CanonicalConstrainedSubst = Canonical; type GoalInEnvironment = InEnvironment; From b657ec1c4cfb1517a7f204b521b16c3e227956cc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 21 May 2018 10:48:36 -0400 Subject: [PATCH 6/6] fix typo --- chalk-engine/src/context.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chalk-engine/src/context.rs b/chalk-engine/src/context.rs index 0b5cf70bfc7..19cb0d0a00b 100644 --- a/chalk-engine/src/context.rs +++ b/chalk-engine/src/context.rs @@ -12,7 +12,7 @@ crate mod prelude; /// /// At any given time, the SLG solver may have more than one context /// active. First, there is always the *global* context, but when we -/// are in the midst of pursuing some particular strange, we will +/// are in the midst of pursuing some particular strand, we will /// instantiate a second context just for that work, via the /// `instantiate_ucanonical_goal` and `instantiate_ex_clause` methods. ///