Skip to content

Commit 93c844d

Browse files
authored
Merge pull request #487 from jackh726/recursive_refactor
Refactor the recursive solver a bit
2 parents 5eb7b26 + 1c651e3 commit 93c844d

File tree

12 files changed

+777
-506
lines changed

12 files changed

+777
-506
lines changed

chalk-engine/src/context.rs

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,6 @@ use std::fmt::Debug;
3434
/// FIXME: Clone and Debug bounds are just for easy derive, they are
3535
/// not actually necessary. But dang are they convenient.
3636
pub trait Context<I: Interner>: Clone + Debug {
37-
/// A final solution that is passed back to the user. This is
38-
/// completely opaque to the SLG solver; it is produced by
39-
/// `make_solution`.
40-
type Solution;
41-
4237
/// Represents an inference table.
4338
type InferenceTable: InferenceTable<I, Self> + Clone;
4439

@@ -47,9 +42,7 @@ pub trait Context<I: Interner>: Clone + Debug {
4742
fn next_subgoal_index(ex_clause: &ExClause<I>) -> usize;
4843
}
4944

50-
pub trait ContextOps<I: Interner, C: Context<I>>:
51-
Sized + Clone + Debug + AggregateOps<I, C>
52-
{
45+
pub trait ContextOps<I: Interner, C: Context<I>>: Sized + Clone + Debug {
5346
/// True if this is a coinductive goal -- e.g., proving an auto trait.
5447
fn is_coinductive(&self, goal: &UCanonical<InEnvironment<Goal<I>>>) -> bool;
5548

@@ -147,16 +140,6 @@ pub trait ContextOps<I: Interner, C: Context<I>>:
147140
) -> bool;
148141
}
149142

150-
/// Methods for combining solutions to yield an aggregate solution.
151-
pub trait AggregateOps<I: Interner, C: Context<I>> {
152-
fn make_solution(
153-
&self,
154-
root_goal: &UCanonical<InEnvironment<Goal<I>>>,
155-
answers: impl AnswerStream<I>,
156-
should_continue: impl Fn() -> bool,
157-
) -> Option<C::Solution>;
158-
}
159-
160143
/// An "inference table" contains the state to support unification and
161144
/// other operations on terms.
162145
pub trait InferenceTable<I: Interner, C: Context<I>>:

chalk-engine/src/forest.rs

Lines changed: 2 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@ use crate::logic::RootSearchFail;
33
use crate::table::AnswerIndex;
44
use crate::tables::Tables;
55
use crate::{TableIndex, TimeStamp};
6-
use std::fmt::Display;
76

87
use chalk_ir::debug;
98
use chalk_ir::interner::Interner;
10-
use chalk_ir::{Canonical, ConstrainedSubst, Goal, InEnvironment, Substitution, UCanonical};
9+
use chalk_ir::{Goal, InEnvironment, Substitution, UCanonical};
1110

1211
pub struct Forest<I: Interner, C: Context<I>> {
1312
pub(crate) tables: Tables<I>,
@@ -39,7 +38,7 @@ impl<I: Interner, C: Context<I>> Forest<I, C> {
3938
/// iterator. Each time you invoke `next`, it will do the work to
4039
/// extract one more answer. These answers are cached in between
4140
/// invocations. Invoking `next` fewer times is preferable =)
42-
fn iter_answers<'f>(
41+
pub fn iter_answers<'f>(
4342
&'f mut self,
4443
context: &'f impl ContextOps<I, C>,
4544
goal: &UCanonical<InEnvironment<Goal<I>>>,
@@ -54,89 +53,6 @@ impl<I: Interner, C: Context<I>> Forest<I, C> {
5453
_context: std::marker::PhantomData::<C>,
5554
}
5655
}
57-
58-
/// Solves a given goal, producing the solution. This will do only
59-
/// as much work towards `goal` as it has to (and that works is
60-
/// cached for future attempts).
61-
pub fn solve(
62-
&mut self,
63-
context: &impl ContextOps<I, C>,
64-
goal: &UCanonical<InEnvironment<Goal<I>>>,
65-
should_continue: impl Fn() -> bool,
66-
) -> Option<C::Solution> {
67-
context.make_solution(&goal, self.iter_answers(context, goal), should_continue)
68-
}
69-
70-
/// Solves a given goal, producing the solution. This will do only
71-
/// as much work towards `goal` as it has to (and that works is
72-
/// cached for future attempts). Calls provided function `f` to
73-
/// iterate over multiple solutions until the function return `false`.
74-
pub fn solve_multiple(
75-
&mut self,
76-
context: &impl ContextOps<I, C>,
77-
goal: &UCanonical<InEnvironment<Goal<I>>>,
78-
mut f: impl FnMut(SubstitutionResult<Canonical<ConstrainedSubst<I>>>, bool) -> bool,
79-
) -> bool {
80-
let mut answers = self.iter_answers(context, goal);
81-
loop {
82-
let subst = match answers.next_answer(|| true) {
83-
AnswerResult::Answer(answer) => {
84-
if !answer.ambiguous {
85-
SubstitutionResult::Definite(answer.subst)
86-
} else {
87-
if context.is_trivial_constrained_substitution(&answer.subst) {
88-
SubstitutionResult::Floundered
89-
} else {
90-
SubstitutionResult::Ambiguous(answer.subst)
91-
}
92-
}
93-
}
94-
AnswerResult::Floundered => SubstitutionResult::Floundered,
95-
AnswerResult::NoMoreSolutions => {
96-
return true;
97-
}
98-
AnswerResult::QuantumExceeded => continue,
99-
};
100-
101-
if !f(subst, !answers.peek_answer(|| true).is_no_more_solutions()) {
102-
return false;
103-
}
104-
}
105-
}
106-
}
107-
108-
#[derive(Debug)]
109-
pub enum SubstitutionResult<S> {
110-
Definite(S),
111-
Ambiguous(S),
112-
Floundered,
113-
}
114-
115-
impl<S> SubstitutionResult<S> {
116-
pub fn as_ref(&self) -> SubstitutionResult<&S> {
117-
match self {
118-
SubstitutionResult::Definite(subst) => SubstitutionResult::Definite(subst),
119-
SubstitutionResult::Ambiguous(subst) => SubstitutionResult::Ambiguous(subst),
120-
SubstitutionResult::Floundered => SubstitutionResult::Floundered,
121-
}
122-
}
123-
pub fn map<U, F: FnOnce(S) -> U>(self, f: F) -> SubstitutionResult<U> {
124-
match self {
125-
SubstitutionResult::Definite(subst) => SubstitutionResult::Definite(f(subst)),
126-
SubstitutionResult::Ambiguous(subst) => SubstitutionResult::Ambiguous(f(subst)),
127-
SubstitutionResult::Floundered => SubstitutionResult::Floundered,
128-
}
129-
}
130-
}
131-
132-
impl<S: Display> Display for SubstitutionResult<S> {
133-
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
134-
match self {
135-
SubstitutionResult::Definite(subst) => write!(fmt, "{}", subst),
136-
SubstitutionResult::Ambiguous(subst) => write!(fmt, "Ambiguous({})", subst),
137-
SubstitutionResult::Floundered => write!(fmt, "Floundered"),
138-
}
139-
}
14056
}
14157

14258
struct ForestSolver<'me, I: Interner, C: Context<I>, CO: ContextOps<I, C>> {

chalk-integration/src/db.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use crate::{
66
query::{Lowering, LoweringDatabase},
77
tls,
88
};
9-
use chalk_engine::forest::SubstitutionResult;
109
use chalk_ir::{
1110
AdtId, AssocTypeId, Canonical, ConstrainedSubst, Environment, FnDefId, GenericArg, Goal,
1211
ImplId, InEnvironment, OpaqueTyId, ProgramClause, ProgramClauses, TraitId, Ty, UCanonical,
@@ -15,7 +14,7 @@ use chalk_solve::rust_ir::{
1514
AdtDatum, AssociatedTyDatum, AssociatedTyValue, AssociatedTyValueId, FnDefDatum, ImplDatum,
1615
OpaqueTyDatum, TraitDatum, WellKnownTrait,
1716
};
18-
use chalk_solve::{RustIrDatabase, Solution, SolverChoice};
17+
use chalk_solve::{RustIrDatabase, Solution, SolverChoice, SubstitutionResult};
1918
use salsa::Database;
2019
use std::sync::Arc;
2120

@@ -58,6 +57,10 @@ impl ChalkDatabase {
5857
solution
5958
}
6059

60+
/// Solves a given goal, producing the solution. This will do only
61+
/// as much work towards `goal` as it has to (and that works is
62+
/// cached for future attempts). Calls provided function `f` to
63+
/// iterate over multiple solutions until the function return `false`.
6164
pub fn solve_multiple(
6265
&self,
6366
goal: &UCanonical<InEnvironment<Goal<ChalkIr>>>,

chalk-solve/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,4 @@ pub use solve::Guidance;
109109
pub use solve::Solution;
110110
pub use solve::Solver;
111111
pub use solve::SolverChoice;
112+
pub use solve::SubstitutionResult;

0 commit comments

Comments
 (0)