Skip to content

Commit 511bb62

Browse files
authored
Merge pull request #131 from nikomatsakis/one-big-happy-family
One big happy family
2 parents 3c3caae + b657ec1 commit 511bb62

File tree

11 files changed

+218
-175
lines changed

11 files changed

+218
-175
lines changed

chalk-engine/src/context.rs

Lines changed: 72 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,30 @@
11
use crate::fallible::Fallible;
22
use crate::hh::HhGoal;
3-
use crate::{ExClause, SimplifiedAnswer};
3+
use crate::{DelayedLiteral, ExClause, SimplifiedAnswer};
44
use std::fmt::Debug;
55
use std::hash::Hash;
66

77
crate mod prelude;
88

9-
/// The "context" in which the SLG solver operates.
10-
// FIXME(leodasvacas): Clone and Debug bounds are just for easy derive,
11-
// they are not actually necessary.
9+
/// The "context" in which the SLG solver operates. It defines all the
10+
/// types that the SLG solver may need to refer to, as well as a few
11+
/// very simple interconversion methods.
12+
///
13+
/// At any given time, the SLG solver may have more than one context
14+
/// active. First, there is always the *global* context, but when we
15+
/// are in the midst of pursuing some particular strand, we will
16+
/// instantiate a second context just for that work, via the
17+
/// `instantiate_ucanonical_goal` and `instantiate_ex_clause` methods.
18+
///
19+
/// In the chalk implementation, these two contexts are mapped to the
20+
/// same type. But in the rustc implementation, this second context
21+
/// corresponds to a fresh arena, and data allocated in that second
22+
/// context will be freed once the work is done. (The "canonicalizing"
23+
/// steps offer a way to convert data from the inference context back
24+
/// into the global context.)
25+
///
26+
/// FIXME: Clone and Debug bounds are just for easy derive, they are
27+
/// not actually necessary. But dang are they convenient.
1228
pub trait Context: Clone + Debug {
1329
type CanonicalExClause: Debug;
1430

@@ -17,12 +33,6 @@ pub trait Context: Clone + Debug {
1733
/// the universes from the original.
1834
type UniverseMap: Clone + Debug;
1935

20-
/// Part of an answer: represents a canonicalized substitution,
21-
/// combined with region constraints. See [the rustc-guide] for more information.
22-
///
23-
/// [the rustc-guide]: https://rust-lang-nursery.github.io/rustc-guide/traits-canonicalization.html#canonicalizing-the-query-result
24-
type CanonicalConstrainedSubst: Clone + Debug + Eq + Hash;
25-
2636
/// Extracted from a canonicalized substitution or canonicalized ex clause, this is the type of
2737
/// substitution that is fully normalized with respect to inference variables.
2838
type InferenceNormalizedSubst: Debug;
@@ -43,9 +53,13 @@ pub trait Context: Clone + Debug {
4353
/// completely opaque to the SLG solver; it is produced by
4454
/// `make_solution`.
4555
type Solution;
46-
}
4756

48-
pub trait ExClauseContext<C: Context>: Sized + Debug {
57+
/// Part of an answer: represents a canonicalized substitution,
58+
/// combined with region constraints. See [the rustc-guide] for more information.
59+
///
60+
/// [the rustc-guide]: https://rust-lang-nursery.github.io/rustc-guide/traits-canonicalization.html#canonicalizing-the-query-result
61+
type CanonicalConstrainedSubst: Clone + Debug + Eq + Hash;
62+
4963
/// Represents a substitution from the "canonical variables" found
5064
/// in a canonical goal to specific values.
5165
type Substitution: Debug;
@@ -56,12 +70,7 @@ pub trait ExClauseContext<C: Context>: Sized + Debug {
5670

5771
/// Represents a goal along with an environment.
5872
type GoalInEnvironment: Debug + Clone + Eq + Hash;
59-
}
6073

61-
/// The set of types belonging to an "inference context"; in rustc,
62-
/// these types are tied to the lifetime of the arena within which an
63-
/// inference context operates.
64-
pub trait InferenceContext<C: Context>: ExClauseContext<C> {
6574
/// Represents a set of hypotheses that are assumed to be true.
6675
type Environment: Debug + Clone;
6776

@@ -91,10 +100,15 @@ pub trait InferenceContext<C: Context>: ExClauseContext<C> {
91100
/// goal we are trying to solve to produce an ex-clause.
92101
type ProgramClause: Debug;
93102

103+
/// A vector of program clauses.
104+
type ProgramClauses: Debug;
105+
94106
/// The successful result from unification: contains new subgoals
95107
/// and things that can be attached to an ex-clause.
96108
type UnificationResult;
97109

110+
/// Given an environment and a goal, glue them together to create
111+
/// a `GoalInEnvironment`.
98112
fn goal_in_environment(
99113
environment: &Self::Environment,
100114
goal: Self::Goal,
@@ -105,26 +119,6 @@ pub trait InferenceContext<C: Context>: ExClauseContext<C> {
105119

106120
/// Create a "cannot prove" goal (see `HhGoal::CannotProve`).
107121
fn cannot_prove() -> Self::Goal;
108-
109-
/// Convert the context's goal type into the `HhGoal` type that
110-
/// the SLG solver understands. The expectation is that the
111-
/// context's goal type has the same set of variants, but with
112-
/// different names and a different setup. If you inspect
113-
/// `HhGoal`, you will see that this is a "shallow" or "lazy"
114-
/// conversion -- that is, we convert the outermost goal into an
115-
/// `HhGoal`, but the goals contained within are left as context
116-
/// goals.
117-
fn into_hh_goal(goal: Self::Goal) -> HhGoal<C, Self>;
118-
119-
/// Add the residual subgoals as new subgoals of the ex-clause.
120-
/// Also add region constraints.
121-
fn into_ex_clause(result: Self::UnificationResult, ex_clause: &mut ExClause<C, Self>);
122-
123-
// Used by: simplify
124-
fn add_clauses(
125-
env: &Self::Environment,
126-
clauses: impl IntoIterator<Item = Self::ProgramClause>,
127-
) -> Self::Environment;
128122
}
129123

130124
pub trait ContextOps<C: Context>: Sized + Clone + Debug + AggregateOps<C> {
@@ -201,7 +195,7 @@ pub trait ContextOps<C: Context>: Sized + Clone + Debug + AggregateOps<C> {
201195
pub trait WithInstantiatedUCanonicalGoal<C: Context> {
202196
type Output;
203197

204-
fn with<I: InferenceContext<C>>(
198+
fn with<I: Context>(
205199
self,
206200
infer: &mut dyn InferenceTable<C, I>,
207201
subst: I::Substitution,
@@ -219,10 +213,10 @@ pub trait WithInstantiatedUCanonicalGoal<C: Context> {
219213
pub trait WithInstantiatedExClause<C: Context> {
220214
type Output;
221215

222-
fn with<I: InferenceContext<C>>(
216+
fn with<I: Context>(
223217
self,
224218
infer: &mut dyn InferenceTable<C, I>,
225-
ex_clause: ExClause<C, I>,
219+
ex_clause: ExClause<I>,
226220
) -> Self::Output;
227221
}
228222

@@ -237,13 +231,29 @@ pub trait AggregateOps<C: Context> {
237231

238232
/// An "inference table" contains the state to support unification and
239233
/// other operations on terms.
240-
pub trait InferenceTable<C: Context, I: InferenceContext<C>>:
234+
pub trait InferenceTable<C: Context, I: Context>:
241235
ResolventOps<C, I> + TruncateOps<C, I> + UnificationOps<C, I>
242236
{
237+
/// Convert the context's goal type into the `HhGoal` type that
238+
/// the SLG solver understands. The expectation is that the
239+
/// context's goal type has the same set of variants, but with
240+
/// different names and a different setup. If you inspect
241+
/// `HhGoal`, you will see that this is a "shallow" or "lazy"
242+
/// conversion -- that is, we convert the outermost goal into an
243+
/// `HhGoal`, but the goals contained within are left as context
244+
/// goals.
245+
fn into_hh_goal(&mut self, goal: I::Goal) -> HhGoal<I>;
246+
247+
// Used by: simplify
248+
fn add_clauses(
249+
&mut self,
250+
env: &I::Environment,
251+
clauses: I::ProgramClauses,
252+
) -> I::Environment;
243253
}
244254

245255
/// Methods for unifying and manipulating terms and binders.
246-
pub trait UnificationOps<C: Context, I: InferenceContext<C>> {
256+
pub trait UnificationOps<C: Context, I: Context> {
247257
/// Returns the set of program clauses that might apply to
248258
/// `goal`. (This set can be over-approximated, naturally.)
249259
fn program_clauses(
@@ -259,13 +269,13 @@ pub trait UnificationOps<C: Context, I: InferenceContext<C>> {
259269
fn instantiate_binders_existentially(&mut self, arg: &I::BindersGoal) -> I::Goal;
260270

261271
// Used by: logic (but for debugging only)
262-
fn debug_ex_clause(&mut self, value: &'v ExClause<C, I>) -> Box<dyn Debug + 'v>;
272+
fn debug_ex_clause(&mut self, value: &'v ExClause<I>) -> Box<dyn Debug + 'v>;
263273

264274
// Used by: logic
265275
fn canonicalize_goal(&mut self, value: &I::GoalInEnvironment) -> C::CanonicalGoalInEnvironment;
266276

267277
// Used by: logic
268-
fn canonicalize_ex_clause(&mut self, value: &ExClause<C, I>) -> C::CanonicalExClause;
278+
fn canonicalize_ex_clause(&mut self, value: &ExClause<I>) -> C::CanonicalExClause;
269279

270280
// Used by: logic
271281
fn canonicalize_constrained_subst(
@@ -280,6 +290,16 @@ pub trait UnificationOps<C: Context, I: InferenceContext<C>> {
280290
value: &C::CanonicalGoalInEnvironment,
281291
) -> (C::UCanonicalGoalInEnvironment, C::UniverseMap);
282292

293+
fn sink_answer_subset(
294+
&self,
295+
value: &C::CanonicalConstrainedSubst,
296+
) -> I::CanonicalConstrainedSubst;
297+
298+
fn lift_delayed_literal(
299+
&self,
300+
value: DelayedLiteral<I>,
301+
) -> DelayedLiteral<C>;
302+
283303
// Used by: logic
284304
fn invert_goal(&mut self, value: &I::GoalInEnvironment) -> Option<I::GoalInEnvironment>;
285305

@@ -290,6 +310,10 @@ pub trait UnificationOps<C: Context, I: InferenceContext<C>> {
290310
a: &I::Parameter,
291311
b: &I::Parameter,
292312
) -> Fallible<I::UnificationResult>;
313+
314+
/// Add the residual subgoals as new subgoals of the ex-clause.
315+
/// Also add region constraints.
316+
fn into_ex_clause(&mut self, result: I::UnificationResult, ex_clause: &mut ExClause<I>);
293317
}
294318

295319
/// "Truncation" (called "abstraction" in the papers referenced below)
@@ -304,7 +328,7 @@ pub trait UnificationOps<C: Context, I: InferenceContext<C>> {
304328
/// - Riguzzi and Swift; ACM Transactions on Computational Logic 2013
305329
/// - Radial Restraint
306330
/// - Grosof and Swift; 2013
307-
pub trait TruncateOps<C: Context, I: InferenceContext<C>> {
331+
pub trait TruncateOps<C: Context, I: Context> {
308332
/// If `subgoal` is too large, return a truncated variant (else
309333
/// return `None`).
310334
fn truncate_goal(&mut self, subgoal: &I::GoalInEnvironment) -> Option<I::GoalInEnvironment>;
@@ -314,7 +338,7 @@ pub trait TruncateOps<C: Context, I: InferenceContext<C>> {
314338
fn truncate_answer(&mut self, subst: &I::Substitution) -> Option<I::Substitution>;
315339
}
316340

317-
pub trait ResolventOps<C: Context, I: InferenceContext<C>> {
341+
pub trait ResolventOps<C: Context, I: Context> {
318342
/// Combines the `goal` (instantiated within `infer`) with the
319343
/// given program clause to yield the start of a new strand (a
320344
/// canonical ex-clause).
@@ -330,11 +354,11 @@ pub trait ResolventOps<C: Context, I: InferenceContext<C>> {
330354

331355
fn apply_answer_subst(
332356
&mut self,
333-
ex_clause: ExClause<C, I>,
357+
ex_clause: ExClause<I>,
334358
selected_goal: &I::GoalInEnvironment,
335359
answer_table_goal: &C::CanonicalGoalInEnvironment,
336360
canonical_answer_subst: &C::CanonicalConstrainedSubst,
337-
) -> Fallible<ExClause<C, I>>;
361+
) -> Fallible<ExClause<I>>;
338362
}
339363

340364
pub trait AnswerStream<C: Context> {

chalk-engine/src/context/prelude.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,3 @@ crate use super::AggregateOps;
66
crate use super::ResolventOps;
77
crate use super::TruncateOps;
88
crate use super::InferenceTable;
9-
crate use super::InferenceContext;

chalk-engine/src/derived.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ impl<C: Context> Hash for DelayedLiteral<C> {
6565

6666
///////////////////////////////////////////////////////////////////////////
6767

68-
impl<C: Context, I: ExClauseContext<C>> PartialEq for Literal<C, I> {
69-
fn eq(&self, other: &Literal<C, I>) -> bool {
68+
impl<C: Context> PartialEq for Literal<C> {
69+
fn eq(&self, other: &Literal<C>) -> bool {
7070
match (self, other) {
7171
(Literal::Positive(goal1), Literal::Positive(goal2))
7272
| (Literal::Negative(goal1), Literal::Negative(goal2)) => goal1 == goal2,
@@ -76,10 +76,10 @@ impl<C: Context, I: ExClauseContext<C>> PartialEq for Literal<C, I> {
7676
}
7777
}
7878

79-
impl<C: Context, I: ExClauseContext<C>> Eq for Literal<C, I> {
79+
impl<C: Context> Eq for Literal<C> {
8080
}
8181

82-
impl<C: Context, I: ExClauseContext<C>> Hash for Literal<C, I> {
82+
impl<C: Context> Hash for Literal<C> {
8383
fn hash<H: Hasher>(&self, state: &mut H) {
8484
mem::discriminant(self).hash(state);
8585
match self {

chalk-engine/src/hh.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
use crate::context::{Context, InferenceContext};
1+
use crate::context::Context;
22

33
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
44
/// A general goal; this is the full range of questions you can pose to Chalk.
5-
pub enum HhGoal<C: Context, I: InferenceContext<C>> {
5+
pub enum HhGoal<C: Context> {
66
/// Introduces a binding at depth 0, shifting other bindings up
77
/// (deBruijn index).
8-
ForAll(I::BindersGoal),
9-
Exists(I::BindersGoal),
10-
Implies(Vec<I::ProgramClause>, I::Goal),
11-
And(I::Goal, I::Goal),
12-
Not(I::Goal),
13-
Unify(I::Parameter, I::Parameter),
14-
DomainGoal(I::DomainGoal),
8+
ForAll(C::BindersGoal),
9+
Exists(C::BindersGoal),
10+
Implies(C::ProgramClauses, C::Goal),
11+
And(C::Goal, C::Goal),
12+
Not(C::Goal),
13+
Unify(C::Parameter, C::Parameter),
14+
DomainGoal(C::DomainGoal),
1515

1616
/// Indicates something that cannot be proven to be true or false
1717
/// definitively. This can occur with overflow but also with

chalk-engine/src/lib.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
extern crate stacker;
6767
extern crate fxhash;
6868

69-
use crate::context::{Context, ExClauseContext};
69+
use crate::context::Context;
7070
use fxhash::FxHashSet;
7171
use std::cmp::min;
7272
use std::usize;
@@ -111,20 +111,20 @@ struct DepthFirstNumber {
111111

112112
/// The paper describes these as `A :- D | G`.
113113
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
114-
pub struct ExClause<C: Context, E: ExClauseContext<C>> {
114+
pub struct ExClause<C: Context> {
115115
/// The substitution which, applied to the goal of our table,
116116
/// would yield A.
117-
pub subst: E::Substitution,
117+
pub subst: C::Substitution,
118118

119119
/// Delayed literals: things that we depend on negatively,
120120
/// but which have not yet been fully evaluated.
121121
pub delayed_literals: Vec<DelayedLiteral<C>>,
122122

123123
/// Region constraints we have accumulated.
124-
pub constraints: Vec<E::RegionConstraint>,
124+
pub constraints: Vec<C::RegionConstraint>,
125125

126126
/// Subgoals: literals that must be proven
127-
pub subgoals: Vec<Literal<C, E>>,
127+
pub subgoals: Vec<Literal<C>>,
128128
}
129129

130130
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
@@ -194,9 +194,9 @@ pub enum DelayedLiteral<C: Context> {
194194

195195
/// Either `A` or `~A`, where `A` is a `Env |- Goal`.
196196
#[derive(Clone, Debug)]
197-
pub enum Literal<C: Context, E: ExClauseContext<C>> { // FIXME: pub b/c fold
198-
Positive(E::GoalInEnvironment),
199-
Negative(E::GoalInEnvironment),
197+
pub enum Literal<C: Context> { // FIXME: pub b/c fold
198+
Positive(C::GoalInEnvironment),
199+
Negative(C::GoalInEnvironment),
200200
}
201201

202202
/// The `Minimums` structure is used to track the dependencies between

0 commit comments

Comments
 (0)