Skip to content

Commit d05412f

Browse files
committed
move Priority out from search graph and into the "value"
1 parent d968d96 commit d05412f

File tree

4 files changed

+66
-38
lines changed

4 files changed

+66
-38
lines changed

chalk-recursive/src/lib.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use crate::search_graph::DepthFirstNumber;
2-
use chalk_ir::{Goal, InEnvironment, UCanonical};
2+
use chalk_ir::{
3+
interner::Interner, ClausePriority, Fallible, Goal, InEnvironment, NoSolution, UCanonical,
4+
};
35

46
pub type UCanonicalGoal<I> = UCanonical<InEnvironment<Goal<I>>>;
57

@@ -12,8 +14,35 @@ pub mod solve;
1214
mod stack;
1315

1416
pub use cache::Cache;
17+
use chalk_solve::{Guidance, Solution};
1518
pub use recursive::RecursiveSolver;
19+
#[derive(Clone, PartialEq, Eq, Debug)]
20+
pub struct PrioritizedSolution<I: Interner> {
21+
priority: ClausePriority,
22+
solution: Fallible<Solution<I>>,
23+
}
24+
25+
impl<I: Interner> PrioritizedSolution<I> {
26+
/// Create a new prioritized solution.
27+
pub(crate) fn new(solution: Fallible<Solution<I>>, priority: ClausePriority) -> Self {
28+
Self { priority, solution }
29+
}
30+
31+
/// Create a high priority solution.
32+
pub(crate) fn high(solution: Fallible<Solution<I>>) -> Self {
33+
Self::new(solution, ClausePriority::High)
34+
}
1635

36+
/// Returns a high-priority solution that represents an error (no solution)
37+
pub(crate) fn error() -> Self {
38+
Self::high(Err(NoSolution))
39+
}
40+
41+
/// Returns a high-priority solution that represents ambiguity with no guidance.
42+
pub(crate) fn ambiguity() -> Self {
43+
Self::high(Ok(Solution::Ambig(Guidance::Unknown)))
44+
}
45+
}
1746
/// The `minimums` struct is used while solving to track whether we encountered
1847
/// any cycles in the process.
1948
#[derive(Copy, Clone, Debug)]

chalk-recursive/src/recursive.rs

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
use crate::cache::Cache;
21
use crate::search_graph::DepthFirstNumber;
32
use crate::search_graph::SearchGraph;
43
use crate::solve::{SolveDatabase, SolveIteration};
54
use crate::stack::{Stack, StackDepth};
5+
use crate::{cache::Cache, PrioritizedSolution};
66
use crate::{Minimums, UCanonicalGoal};
77
use chalk_ir::{interner::Interner, NoSolution};
88
use chalk_ir::{Canonical, ConstrainedSubst, Goal, InEnvironment, UCanonical};
@@ -17,12 +17,12 @@ struct RecursiveContext<I: Interner> {
1717

1818
/// The "search graph" stores "in-progress results" that are still being
1919
/// solved.
20-
search_graph: SearchGraph<UCanonicalGoal<I>, Fallible<Solution<I>>>,
20+
search_graph: SearchGraph<UCanonicalGoal<I>, PrioritizedSolution<I>>,
2121

2222
/// The "cache" stores results for goals that we have completely solved.
2323
/// Things are added to the cache when we have completely processed their
2424
/// result.
25-
cache: Option<Cache<UCanonicalGoal<I>, Fallible<Solution<I>>>>,
25+
cache: Option<Cache<UCanonicalGoal<I>, PrioritizedSolution<I>>>,
2626

2727
/// The maximum size for goals.
2828
max_size: usize,
@@ -46,7 +46,7 @@ impl<I: Interner> RecursiveSolver<I> {
4646
pub fn new(
4747
overflow_depth: usize,
4848
max_size: usize,
49-
cache: Option<Cache<UCanonicalGoal<I>, Fallible<Solution<I>>>>,
49+
cache: Option<Cache<UCanonicalGoal<I>, PrioritizedSolution<I>>>,
5050
) -> Self {
5151
Self {
5252
ctx: Box::new(RecursiveContext::new(overflow_depth, max_size, cache)),
@@ -84,7 +84,7 @@ impl<I: Interner> RecursiveContext<I> {
8484
pub fn new(
8585
overflow_depth: usize,
8686
max_size: usize,
87-
cache: Option<Cache<UCanonicalGoal<I>, Fallible<Solution<I>>>>,
87+
cache: Option<Cache<UCanonicalGoal<I>, PrioritizedSolution<I>>>,
8888
) -> Self {
8989
RecursiveContext {
9090
stack: Stack::new(overflow_depth),
@@ -149,7 +149,7 @@ impl<'me, I: Interner> Solver<'me, I> {
149149
// so this function will eventually be constant and the loop terminates.
150150
loop {
151151
let minimums = &mut Minimums::new();
152-
let (current_answer, current_prio) = self.solve_iteration(&canonical_goal, minimums);
152+
let current_answer = self.solve_iteration(&canonical_goal, minimums);
153153

154154
debug!(
155155
"solve_new_subgoal: loop iteration result = {:?} with minimums {:?}",
@@ -160,24 +160,22 @@ impl<'me, I: Interner> Solver<'me, I> {
160160
// None of our subgoals depended on us directly.
161161
// We can return.
162162
self.context.search_graph[dfn].solution = current_answer;
163-
self.context.search_graph[dfn].solution_priority = current_prio;
164163
return *minimums;
165164
}
166165

167166
// Some of our subgoals depended on us. We need to re-run
168167
// with the current answer.
169-
if self.context.search_graph[dfn].solution == current_answer {
168+
if self.context.search_graph[dfn].solution.solution == current_answer.solution {
170169
// Reached a fixed point.
171170
return *minimums;
172171
}
173172

174-
let current_answer_is_ambig = match &current_answer {
173+
let current_answer_is_ambig = match &current_answer.solution {
175174
Ok(s) => s.is_ambig(),
176175
Err(_) => false,
177176
};
178177

179178
self.context.search_graph[dfn].solution = current_answer;
180-
self.context.search_graph[dfn].solution_priority = current_prio;
181179

182180
// Subtle: if our current answer is ambiguous, we can just stop, and
183181
// in fact we *must* -- otherwise, we sometimes fail to reach a
@@ -206,7 +204,7 @@ impl<'me, I: Interner> SolveDatabase<I> for Solver<'me, I> {
206204
if let Some(cache) = &self.context.cache {
207205
if let Some(value) = cache.get(&goal) {
208206
debug!("solve_reduced_goal: cache hit, value={:?}", value);
209-
return value.clone();
207+
return value.solution.clone();
210208
}
211209
}
212210

@@ -231,12 +229,11 @@ impl<'me, I: Interner> SolveDatabase<I> for Solver<'me, I> {
231229

232230
// Return the solution from the table.
233231
let previous_solution = self.context.search_graph[dfn].solution.clone();
234-
let previous_solution_priority = self.context.search_graph[dfn].solution_priority;
235232
info!(
236-
"solve_goal: cycle detected, previous solution {:?} with prio {:?}",
237-
previous_solution, previous_solution_priority
233+
"solve_goal: cycle detected, previous solution {:?}",
234+
previous_solution,
238235
);
239-
previous_solution
236+
previous_solution.solution
240237
} else {
241238
// Otherwise, push the goal onto the stack and create a table.
242239
// The initial result for this table depends on whether the goal is coinductive.
@@ -253,10 +250,11 @@ impl<'me, I: Interner> SolveDatabase<I> for Solver<'me, I> {
253250
} else {
254251
Err(NoSolution)
255252
};
256-
let dfn = self
257-
.context
258-
.search_graph
259-
.insert(&goal, depth, initial_solution);
253+
let dfn = self.context.search_graph.insert(
254+
&goal,
255+
depth,
256+
PrioritizedSolution::high(initial_solution),
257+
);
260258
let subgoal_minimums = self.solve_new_subgoal(goal, depth, dfn);
261259
self.context.search_graph[dfn].links = subgoal_minimums;
262260
self.context.search_graph[dfn].stack_depth = None;
@@ -265,7 +263,6 @@ impl<'me, I: Interner> SolveDatabase<I> for Solver<'me, I> {
265263

266264
// Read final result from table.
267265
let result = self.context.search_graph[dfn].solution.clone();
268-
let priority = self.context.search_graph[dfn].solution_priority;
269266

270267
// If processing this subgoal did not involve anything
271268
// outside of its subtree, then we can promote it to the
@@ -283,8 +280,8 @@ impl<'me, I: Interner> SolveDatabase<I> for Solver<'me, I> {
283280
}
284281
}
285282

286-
info!("solve_goal: solution = {:?} prio {:?}", result, priority);
287-
result
283+
info!("solve_goal: solution = {:#?}", result);
284+
result.solution
288285
}
289286
}
290287

chalk-recursive/src/search_graph.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use super::stack::StackDepth;
22
use crate::{Cache, Minimums};
3-
use chalk_ir::ClausePriority;
43
use rustc_hash::FxHashMap;
54
use std::fmt::Debug;
65
use std::hash::Hash;
@@ -30,7 +29,6 @@ pub(super) struct Node<K, V> {
3029
pub(crate) goal: K,
3130

3231
pub(crate) solution: V,
33-
pub(crate) solution_priority: ClausePriority,
3432

3533
/// This is `Some(X)` if we are actively exploring this node, or
3634
/// `None` otherwise.
@@ -78,7 +76,6 @@ where
7876
let node = Node {
7977
goal: goal.clone(),
8078
solution,
81-
solution_priority: ClausePriority::High,
8279
stack_depth: Some(stack_depth),
8380
links: Minimums { positive: dfn },
8481
};

chalk-recursive/src/solve.rs

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::combine;
22
use super::fulfill::Fulfill;
3-
use crate::{Minimums, UCanonicalGoal};
3+
use crate::{Minimums, PrioritizedSolution, UCanonicalGoal};
44
use chalk_ir::could_match::CouldMatch;
55
use chalk_ir::fold::Fold;
66
use chalk_ir::interner::{HasInterner, Interner};
@@ -39,7 +39,7 @@ pub(super) trait SolveIteration<I: Interner>: SolveDatabase<I> {
3939
&mut self,
4040
canonical_goal: &UCanonicalGoal<I>,
4141
minimums: &mut Minimums,
42-
) -> (Fallible<Solution<I>>, ClausePriority) {
42+
) -> PrioritizedSolution<I> {
4343
let UCanonical {
4444
universes,
4545
canonical:
@@ -68,14 +68,14 @@ pub(super) trait SolveIteration<I: Interner>: SolveDatabase<I> {
6868
// or from the lowered program, which includes fallback
6969
// clauses. We try each approach in turn:
7070

71-
let (prog_solution, prog_prio) = {
71+
let solution = {
7272
debug_span!("prog_clauses");
7373

7474
self.solve_from_clauses(&canonical_goal, minimums)
7575
};
76-
debug!(?prog_solution);
76+
debug!(?solution);
7777

78-
(prog_solution, prog_prio)
78+
solution
7979
}
8080

8181
_ => {
@@ -107,11 +107,11 @@ trait SolveIterationHelpers<I: Interner>: SolveDatabase<I> {
107107
&mut self,
108108
canonical_goal: &UCanonicalGoal<I>,
109109
minimums: &mut Minimums,
110-
) -> (Fallible<Solution<I>>, ClausePriority) {
110+
) -> PrioritizedSolution<I> {
111111
let (infer, subst, goal) = self.new_inference_table(canonical_goal);
112112
match Fulfill::new_with_simplification(self, infer, subst, goal) {
113-
Ok(fulfill) => (fulfill.solve(minimums), ClausePriority::High),
114-
Err(e) => (Err(e), ClausePriority::High),
113+
Ok(fulfill) => PrioritizedSolution::high(fulfill.solve(minimums)),
114+
Err(NoSolution) => PrioritizedSolution::error(),
115115
}
116116
}
117117

@@ -122,7 +122,7 @@ trait SolveIterationHelpers<I: Interner>: SolveDatabase<I> {
122122
&mut self,
123123
canonical_goal: &UCanonical<InEnvironment<DomainGoal<I>>>,
124124
minimums: &mut Minimums,
125-
) -> (Fallible<Solution<I>>, ClausePriority) {
125+
) -> PrioritizedSolution<I> {
126126
let mut clauses = vec![];
127127

128128
let db = self.db();
@@ -137,7 +137,7 @@ trait SolveIterationHelpers<I: Interner>: SolveDatabase<I> {
137137
match program_clauses_that_could_match(db, canonical_goal) {
138138
Ok(goal_clauses) => clauses.extend(goal_clauses.into_iter().filter(could_match)),
139139
Err(Floundered) => {
140-
return (Ok(Solution::Ambig(Guidance::Unknown)), ClausePriority::High);
140+
return PrioritizedSolution::ambiguity();
141141
}
142142
}
143143

@@ -155,7 +155,7 @@ trait SolveIterationHelpers<I: Interner>: SolveDatabase<I> {
155155

156156
// If we have a completely ambiguous answer, it's not going to get better, so stop
157157
if cur_solution == Some((Solution::Ambig(Guidance::Unknown), ClausePriority::High)) {
158-
return (Ok(Solution::Ambig(Guidance::Unknown)), ClausePriority::High);
158+
return PrioritizedSolution::ambiguity();
159159
}
160160

161161
let ProgramClauseData(implication) = program_clause.data(self.interner());
@@ -184,7 +184,12 @@ trait SolveIterationHelpers<I: Interner>: SolveDatabase<I> {
184184
debug!("Error");
185185
}
186186
}
187-
cur_solution.map_or((Err(NoSolution), ClausePriority::High), |(s, p)| (Ok(s), p))
187+
188+
if let Some((s, p)) = cur_solution {
189+
PrioritizedSolution::new(Ok(s), p)
190+
} else {
191+
PrioritizedSolution::error()
192+
}
188193
}
189194

190195
fn new_inference_table<T: Fold<I, Result = T> + HasInterner<Interner = I> + Clone>(

0 commit comments

Comments
 (0)