Skip to content

Commit 66500fe

Browse files
committed
Move infer methods to trait
1 parent 61c418a commit 66500fe

File tree

2 files changed

+194
-63
lines changed

2 files changed

+194
-63
lines changed

chalk-solve/src/recursive.rs

Lines changed: 107 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,25 @@ mod fulfill;
22
mod search_graph;
33
mod stack;
44

5-
use self::fulfill::Fulfill;
5+
use self::fulfill::{Fulfill, RecursiveInferenceTable};
66
use self::search_graph::{DepthFirstNumber, SearchGraph};
77
use self::stack::{Stack, StackDepth};
88
use crate::clauses::program_clauses_for_goal;
9+
use crate::infer::{InferenceTable, ParameterEnaVariable};
10+
use crate::solve::truncate;
911
use crate::{Guidance, RustIrDatabase, Solution};
10-
use chalk_ir::interner::Interner;
12+
use chalk_ir::fold::Fold;
13+
use chalk_ir::interner::{HasInterner, Interner};
14+
use chalk_ir::visit::Visit;
15+
use chalk_ir::zip::Zip;
1116
use chalk_ir::{debug, debug_heading, info, info_heading};
1217
use chalk_ir::{
13-
Binders, Canonical, ClausePriority, ConstrainedSubst, DomainGoal, Environment, Fallible,
14-
Floundered, GenericArg, Goal, GoalData, InEnvironment, NoSolution, ProgramClause,
15-
ProgramClauseData, ProgramClauseImplication, UCanonical, VariableKinds,
18+
Binders, Canonical, ClausePriority, ConstrainedSubst, Constraint, DomainGoal, Environment,
19+
Fallible, Floundered, GenericArg, Goal, GoalData, InEnvironment, NoSolution, ProgramClause,
20+
ProgramClauseData, ProgramClauseImplication, UCanonical, UniverseMap, VariableKinds,
1621
};
1722
use rustc_hash::FxHashMap;
23+
use std::fmt::Debug;
1824

1925
type UCanonicalGoal<I> = UCanonical<InEnvironment<Goal<I>>>;
2026

@@ -26,14 +32,97 @@ pub(crate) struct RecursiveContext<I: Interner> {
2632
caching_enabled: bool,
2733
}
2834

29-
trait Context<I: Interner> {
30-
fn instantiate_binders_universally(&mut self, interner: &I, arg: &Binders<Goal<I>>) -> Goal<I>;
35+
pub(crate) struct RecursiveInferenceTableImpl<I: Interner> {
36+
pub(crate) infer: InferenceTable<I>,
37+
}
38+
39+
impl<I: Interner> RecursiveInferenceTable<I> for RecursiveInferenceTableImpl<I> {
40+
fn instantiate_binders_universally<'a, T>(
41+
&mut self,
42+
interner: &'a I,
43+
arg: &'a Binders<T>,
44+
) -> T::Result
45+
where
46+
T: Fold<I> + HasInterner<Interner = I>,
47+
{
48+
self.infer.instantiate_binders_universally(interner, arg)
49+
}
50+
51+
fn instantiate_binders_existentially<'a, T>(
52+
&mut self,
53+
interner: &'a I,
54+
arg: &'a Binders<T>,
55+
) -> T::Result
56+
where
57+
T: Fold<I> + HasInterner<Interner = I>,
58+
{
59+
self.infer.instantiate_binders_existentially(interner, arg)
60+
}
3161

32-
fn instantiate_binders_existentially(
62+
fn canonicalize<T>(
3363
&mut self,
3464
interner: &I,
35-
arg: &Binders<Goal<I>>,
36-
) -> Goal<I>;
65+
value: &T,
66+
) -> (Canonical<T::Result>, Vec<ParameterEnaVariable<I>>)
67+
where
68+
T: Fold<I>,
69+
T::Result: HasInterner<Interner = I>,
70+
{
71+
let res = self.infer.canonicalize(interner, value);
72+
(res.quantified, res.free_vars)
73+
}
74+
75+
fn u_canonicalize<T>(
76+
&mut self,
77+
interner: &I,
78+
value0: &Canonical<T>,
79+
) -> (UCanonical<T::Result>, UniverseMap)
80+
where
81+
T: HasInterner<Interner = I> + Fold<I> + Visit<I>,
82+
T::Result: HasInterner<Interner = I>,
83+
{
84+
let res = self.infer.u_canonicalize(interner, value0);
85+
(res.quantified, res.universes)
86+
}
87+
88+
fn unify<T>(
89+
&mut self,
90+
interner: &I,
91+
environment: &Environment<I>,
92+
a: &T,
93+
b: &T,
94+
) -> Fallible<(
95+
Vec<InEnvironment<DomainGoal<I>>>,
96+
Vec<InEnvironment<Constraint<I>>>,
97+
)>
98+
where
99+
T: ?Sized + Zip<I>,
100+
{
101+
let res = self.infer.unify(interner, environment, a, b)?;
102+
Ok((res.goals, res.constraints))
103+
}
104+
105+
fn instantiate_canonical<T>(&mut self, interner: &I, bound: &Canonical<T>) -> T::Result
106+
where
107+
T: HasInterner<Interner = I> + Fold<I> + Debug,
108+
{
109+
self.infer.instantiate_canonical(interner, bound)
110+
}
111+
112+
fn invert_then_canonicalize<T>(
113+
&mut self,
114+
interner: &I,
115+
value: &T,
116+
) -> Option<Canonical<T::Result>>
117+
where
118+
T: Fold<I, Result = T> + HasInterner<Interner = I>,
119+
{
120+
self.infer.invert_then_canonicalize(interner, value)
121+
}
122+
123+
fn needs_truncation(&mut self, interner: &I, max_size: usize, value: impl Visit<I>) -> bool {
124+
truncate::needs_truncation(interner, &mut self.infer, max_size, value)
125+
}
37126
}
38127

39128
/// A Solver is the basic context in which you can propose goals for a given
@@ -351,11 +440,10 @@ impl<'me, I: Interner> Solver<'me, I> {
351440
minimums: &mut Minimums,
352441
) -> (Fallible<Solution<I>>, ClausePriority) {
353442
debug_heading!("solve_via_simplification({:?})", canonical_goal);
354-
let fulfill = match Fulfill::new_with_simplification(self, canonical_goal) {
355-
Ok(r) => r,
356-
Err(e) => return (Err(e), ClausePriority::High),
357-
};
358-
(fulfill.solve(minimums), ClausePriority::High)
443+
match Fulfill::new_with_simplification(self, canonical_goal) {
444+
Ok(fulfill) => (fulfill.solve(minimums), ClausePriority::High),
445+
Err(e) => (Err(e), ClausePriority::High),
446+
}
359447
}
360448

361449
/// See whether we can solve a goal by implication on any of the given
@@ -426,12 +514,11 @@ impl<'me, I: Interner> Solver<'me, I> {
426514
canonical_goal,
427515
clause
428516
);
429-
let fulfill = match Fulfill::new_with_clause(self, canonical_goal, clause) {
430-
Ok(r) => r,
431-
Err(e) => return (Err(e), ClausePriority::High),
432-
};
433517

434-
(fulfill.solve(minimums), clause.skip_binders().priority)
518+
match Fulfill::new_with_clause(self, canonical_goal, clause) {
519+
Ok(fulfill) => (fulfill.solve(minimums), clause.skip_binders().priority),
520+
Err(e) => (Err(e), ClausePriority::High),
521+
}
435522
}
436523

437524
fn program_clauses_for_goal(

chalk-solve/src/recursive/fulfill.rs

Lines changed: 87 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
use crate::infer::{
2-
canonicalize::Canonicalized, ucanonicalize::UCanonicalized, unify::UnificationResult,
3-
InferenceTable, ParameterEnaVariable, ParameterEnaVariableExt,
4-
};
5-
use crate::recursive::{Minimums, Solver};
6-
use crate::solve::{truncate, Guidance, Solution};
1+
use crate::infer::{InferenceTable, ParameterEnaVariable, ParameterEnaVariableExt};
2+
use crate::recursive::{Minimums, RecursiveInferenceTableImpl, Solver};
3+
use crate::solve::{Guidance, Solution};
74
use chalk_ir::cast::Cast;
85
use chalk_ir::fold::Fold;
96
use chalk_ir::interner::{HasInterner, Interner};
7+
use chalk_ir::visit::Visit;
108
use chalk_ir::zip::Zip;
119
use chalk_ir::{debug, debug_heading};
1210
use chalk_ir::{
@@ -60,6 +58,69 @@ enum NegativeSolution {
6058
Ambiguous,
6159
}
6260

61+
pub(crate) trait RecursiveInferenceTable<I: Interner> {
62+
fn instantiate_binders_universally<'a, T>(
63+
&mut self,
64+
interner: &'a I,
65+
arg: &'a Binders<T>,
66+
) -> T::Result
67+
where
68+
T: Fold<I> + HasInterner<Interner = I>;
69+
70+
fn instantiate_binders_existentially<'a, T>(
71+
&mut self,
72+
interner: &'a I,
73+
arg: &'a Binders<T>,
74+
) -> T::Result
75+
where
76+
T: Fold<I> + HasInterner<Interner = I>;
77+
78+
fn canonicalize<T>(
79+
&mut self,
80+
interner: &I,
81+
value: &T,
82+
) -> (Canonical<T::Result>, Vec<ParameterEnaVariable<I>>)
83+
where
84+
T: Fold<I>,
85+
T::Result: HasInterner<Interner = I>;
86+
87+
fn u_canonicalize<T>(
88+
&mut self,
89+
interner: &I,
90+
value0: &Canonical<T>,
91+
) -> (UCanonical<T::Result>, UniverseMap)
92+
where
93+
T: HasInterner<Interner = I> + Fold<I> + Visit<I>,
94+
T::Result: HasInterner<Interner = I>;
95+
96+
fn unify<T>(
97+
&mut self,
98+
interner: &I,
99+
environment: &Environment<I>,
100+
a: &T,
101+
b: &T,
102+
) -> Fallible<(
103+
Vec<InEnvironment<DomainGoal<I>>>,
104+
Vec<InEnvironment<Constraint<I>>>,
105+
)>
106+
where
107+
T: ?Sized + Zip<I>;
108+
109+
fn instantiate_canonical<T>(&mut self, interner: &I, bound: &Canonical<T>) -> T::Result
110+
where
111+
T: HasInterner<Interner = I> + Fold<I> + Debug;
112+
113+
fn invert_then_canonicalize<T>(
114+
&mut self,
115+
interner: &I,
116+
value: &T,
117+
) -> Option<Canonical<T::Result>>
118+
where
119+
T: Fold<I, Result = T> + HasInterner<Interner = I>;
120+
121+
fn needs_truncation(&mut self, interner: &I, max_size: usize, value: impl Visit<I>) -> bool;
122+
}
123+
63124
/// A `Fulfill` is where we actually break down complex goals, instantiate
64125
/// variables, and perform inference. It's highly stateful. It's generally used
65126
/// in Chalk to try to solve a goal, and then package up what was learned in a
@@ -70,10 +131,10 @@ enum NegativeSolution {
70131
/// of type inference in general. But when solving trait constraints, *fresh*
71132
/// `Fulfill` instances will be created to solve canonicalized, free-standing
72133
/// goals, and transport what was learned back to the outer context.
73-
pub(crate) struct Fulfill<'s, 'db, I: Interner> {
134+
pub(crate) struct Fulfill<'s, 'db, I: Interner, Infer: RecursiveInferenceTable<I>> {
74135
solver: &'s mut Solver<'db, I>,
75136
subst: Substitution<I>,
76-
infer: InferenceTable<I>,
137+
infer: Infer,
77138

78139
/// The remaining goals to prove or refute
79140
obligations: Vec<Obligation<I>>,
@@ -88,7 +149,7 @@ pub(crate) struct Fulfill<'s, 'db, I: Interner> {
88149
cannot_prove: bool,
89150
}
90151

91-
impl<'s, 'db, I: Interner> Fulfill<'s, 'db, I> {
152+
impl<'s, 'db, I: Interner> Fulfill<'s, 'db, I, RecursiveInferenceTableImpl<I>> {
92153
fn new<T: Fold<I, I, Result = T> + HasInterner<Interner = I> + Clone>(
93154
solver: &'s mut Solver<'db, I>,
94155
ucanonical_goal: &UCanonical<InEnvironment<T>>,
@@ -98,6 +159,7 @@ impl<'s, 'db, I: Interner> Fulfill<'s, 'db, I> {
98159
ucanonical_goal.universes,
99160
&ucanonical_goal.canonical,
100161
);
162+
let infer = crate::recursive::RecursiveInferenceTableImpl { infer };
101163
let fulfill = Fulfill {
102164
solver,
103165
infer,
@@ -163,24 +225,20 @@ impl<'s, 'db, I: Interner> Fulfill<'s, 'db, I> {
163225
// truncate to avoid overflows
164226
match &obligation {
165227
Obligation::Prove(goal) => {
166-
if truncate::needs_truncation(
167-
self.solver.program.interner(),
168-
&mut self.infer,
169-
30,
170-
goal,
171-
) {
228+
if self
229+
.infer
230+
.needs_truncation(self.solver.program.interner(), 30, goal)
231+
{
172232
// the goal is too big. Record that we should return Ambiguous
173233
self.cannot_prove = true;
174234
return;
175235
}
176236
}
177237
Obligation::Refute(goal) => {
178-
if truncate::needs_truncation(
179-
self.solver.program.interner(),
180-
&mut self.infer,
181-
30,
182-
goal,
183-
) {
238+
if self
239+
.infer
240+
.needs_truncation(self.solver.program.interner(), 30, goal)
241+
{
184242
// the goal is too big. Record that we should return Ambiguous
185243
self.cannot_prove = true;
186244
return;
@@ -198,7 +256,7 @@ impl<'s, 'db, I: Interner> Fulfill<'s, 'db, I> {
198256
where
199257
T: ?Sized + Zip<I> + Debug,
200258
{
201-
let UnificationResult { goals, constraints } =
259+
let (goals, constraints) =
202260
self.infer
203261
.unify(self.solver.program.interner(), environment, a, b)?;
204262
debug!("unify({:?}, {:?}) succeeded", a, b);
@@ -276,15 +334,8 @@ impl<'s, 'db, I: Interner> Fulfill<'s, 'db, I> {
276334
minimums: &mut Minimums,
277335
) -> Fallible<PositiveSolution<I>> {
278336
let interner = self.solver.program.interner();
279-
let Canonicalized {
280-
quantified,
281-
free_vars,
282-
..
283-
} = self.infer.canonicalize(interner, &wc);
284-
let UCanonicalized {
285-
quantified,
286-
universes,
287-
} = self.infer.u_canonicalize(interner, &quantified);
337+
let (quantified, free_vars) = self.infer.canonicalize(interner, &wc);
338+
let (quantified, universes) = self.infer.u_canonicalize(interner, &quantified);
288339
let result = self.solver.solve_goal(quantified, minimums);
289340
Ok(PositiveSolution {
290341
free_vars,
@@ -307,10 +358,7 @@ impl<'s, 'db, I: Interner> Fulfill<'s, 'db, I> {
307358
};
308359

309360
// Negate the result
310-
let UCanonicalized {
311-
quantified,
312-
universes: _,
313-
} = self
361+
let (quantified, _) = self
314362
.infer
315363
.u_canonicalize(self.solver.program.interner(), &canonicalized);
316364
let mut minimums = Minimums::new(); // FIXME -- minimums here seems wrong
@@ -462,7 +510,7 @@ impl<'s, 'db, I: Interner> Fulfill<'s, 'db, I> {
462510
constraints,
463511
},
464512
);
465-
return Ok(Solution::Unique(constrained.quantified));
513+
return Ok(Solution::Unique(constrained.0));
466514
}
467515

468516
// Otherwise, we have (positive or negative) obligations remaining, but
@@ -473,7 +521,7 @@ impl<'s, 'db, I: Interner> Fulfill<'s, 'db, I> {
473521
let interner = self.solver.program.interner();
474522
let canonical_subst = self.infer.canonicalize(interner, &self.subst);
475523

476-
if canonical_subst.quantified.value.is_identity_subst(interner) {
524+
if canonical_subst.0.value.is_identity_subst(interner) {
477525
// In this case, we didn't learn *anything* definitively. So now, we
478526
// go one last time through the positive obligations, this time
479527
// applying even *tentative* inference suggestions, so that we can
@@ -490,9 +538,7 @@ impl<'s, 'db, I: Interner> Fulfill<'s, 'db, I> {
490538
} = self.prove(&goal, minimums).unwrap();
491539
if let Some(constrained_subst) = solution.constrained_subst() {
492540
self.apply_solution(free_vars, universes, constrained_subst);
493-
return Ok(Solution::Ambig(Guidance::Suggested(
494-
canonical_subst.quantified,
495-
)));
541+
return Ok(Solution::Ambig(Guidance::Suggested(canonical_subst.0)));
496542
}
497543
}
498544
}
@@ -519,9 +565,7 @@ impl<'s, 'db, I: Interner> Fulfill<'s, 'db, I> {
519565
// for sure what `T` must be (it could be either `Foo<Bar>` or
520566
// `Foo<Baz>`, but we *can* say for sure that it must be of the
521567
// form `Foo<?0>`.
522-
Ok(Solution::Ambig(Guidance::Definite(
523-
canonical_subst.quantified,
524-
)))
568+
Ok(Solution::Ambig(Guidance::Definite(canonical_subst.0)))
525569
}
526570
}
527571

0 commit comments

Comments
 (0)