2 use super::fulfill
::{Fulfill, RecursiveInferenceTable}
;
3 use crate::{Guidance, Minimums, Solution, UCanonicalGoal}
;
4 use chalk_ir
::fold
::Fold
;
5 use chalk_ir
::interner
::{HasInterner, Interner}
;
6 use chalk_ir
::visit
::Visit
;
7 use chalk_ir
::zip
::Zip
;
9 Binders
, Canonical
, ClausePriority
, DomainGoal
, Environment
, Fallible
, Floundered
, GenericArg
,
10 Goal
, GoalData
, InEnvironment
, NoSolution
, ProgramClause
, ProgramClauseData
,
11 ProgramClauseImplication
, Substitution
, UCanonical
, UniverseMap
,
13 use chalk_solve
::clauses
::program_clauses_for_goal
;
14 use chalk_solve
::debug_span
;
15 use chalk_solve
::infer
::{InferenceTable, ParameterEnaVariableExt}
;
16 use chalk_solve
::{solve::truncate, RustIrDatabase}
;
18 use tracing
::{debug, instrument}
;
20 pub(super) trait SolveDatabase
<I
: Interner
>: Sized
{
23 goal
: UCanonical
<InEnvironment
<Goal
<I
>>>,
24 minimums
: &mut Minimums
,
25 ) -> Fallible
<Solution
<I
>>;
27 fn interner(&self) -> &I
;
29 fn db(&self) -> &dyn RustIrDatabase
<I
>;
32 /// The `solve_iteration` method -- implemented for any type that implements
34 pub(super) trait SolveIteration
<I
: Interner
>: SolveDatabase
<I
> {
35 /// Executes one iteration of the recursive solver, computing the current
36 /// solution to the given canonical goal. This is used as part of a loop in
37 /// the case of cyclic goals.
38 #[instrument(level = "debug", skip(self))]
41 canonical_goal
: &UCanonicalGoal
<I
>,
42 minimums
: &mut Minimums
,
43 ) -> (Fallible
<Solution
<I
>>, ClausePriority
) {
49 value
: InEnvironment { environment, goal }
,
51 } = canonical_goal
.clone();
53 match goal
.data(self.interner()) {
54 GoalData
::DomainGoal(domain_goal
) => {
55 let canonical_goal
= UCanonical
{
57 canonical
: Canonical
{
59 value
: InEnvironment
{
61 goal
: domain_goal
.clone(),
66 // "Domain" goals (i.e., leaf goals that are Rust-specific) are
67 // always solved via some form of implication. We can either
68 // apply assumptions from our environment (i.e. where clauses),
69 // or from the lowered program, which includes fallback
70 // clauses. We try each approach in turn:
72 let (prog_solution
, prog_prio
) = {
73 debug_span
!("prog_clauses");
75 let prog_clauses
= self.program_clauses_for_goal(&canonical_goal
);
77 Ok(clauses
) => self.solve_from_clauses(&canonical_goal
, clauses
, minimums
),
79 (Ok(Solution
::Ambig(Guidance
::Unknown
)), ClausePriority
::High
)
83 debug
!(?prog_solution
);
85 (prog_solution
, prog_prio
)
89 let canonical_goal
= UCanonical
{
91 canonical
: Canonical
{
93 value
: InEnvironment { environment, goal }
,
97 self.solve_via_simplification(&canonical_goal
, minimums
)
103 impl<S
, I
> SolveIteration
<I
> for S
110 /// Helper methods for `solve_iteration`, private to this module.
111 trait SolveIterationHelpers
<I
: Interner
>: SolveDatabase
<I
> {
112 #[instrument(level = "debug", skip(self, minimums))]
113 fn solve_via_simplification(
115 canonical_goal
: &UCanonicalGoal
<I
>,
116 minimums
: &mut Minimums
,
117 ) -> (Fallible
<Solution
<I
>>, ClausePriority
) {
118 let (infer
, subst
, goal
) = self.new_inference_table(canonical_goal
);
119 match Fulfill
::new_with_simplification(self, infer
, subst
, goal
) {
120 Ok(fulfill
) => (fulfill
.solve(minimums
), ClausePriority
::High
),
121 Err(e
) => (Err(e
), ClausePriority
::High
),
125 /// See whether we can solve a goal by implication on any of the given
126 /// clauses. If multiple such solutions are possible, we attempt to combine
128 fn solve_from_clauses
<C
>(
130 canonical_goal
: &UCanonical
<InEnvironment
<DomainGoal
<I
>>>,
132 minimums
: &mut Minimums
,
133 ) -> (Fallible
<Solution
<I
>>, ClausePriority
)
135 C
: IntoIterator
<Item
= ProgramClause
<I
>>,
137 let mut cur_solution
= None
;
138 for program_clause
in clauses
{
139 debug_span
!("solve_from_clauses", clause
= ?program_clause
);
141 // If we have a completely ambiguous answer, it's not going to get better, so stop
142 if cur_solution
== Some((Solution
::Ambig(Guidance
::Unknown
), ClausePriority
::High
)) {
143 return (Ok(Solution
::Ambig(Guidance
::Unknown
)), ClausePriority
::High
);
146 let ProgramClauseData(implication
) = program_clause
.data(self.interner());
147 let res
= self.solve_via_implication(canonical_goal
, implication
, minimums
);
149 if let (Ok(solution
), priority
) = res
{
150 debug
!(?solution
, ?priority
, "Ok");
151 cur_solution
= Some(match cur_solution
{
152 None
=> (solution
, priority
),
153 Some((cur
, cur_priority
)) => combine
::with_priorities(
155 &canonical_goal
.canonical
.value
.goal
,
166 cur_solution
.map_or((Err(NoSolution
), ClausePriority
::High
), |(s
, p
)| (Ok(s
), p
))
169 /// Modus ponens! That is: try to apply an implication by proving its premises.
170 #[instrument(level = "info", skip(self, minimums))]
171 fn solve_via_implication(
173 canonical_goal
: &UCanonical
<InEnvironment
<DomainGoal
<I
>>>,
174 clause
: &Binders
<ProgramClauseImplication
<I
>>,
175 minimums
: &mut Minimums
,
176 ) -> (Fallible
<Solution
<I
>>, ClausePriority
) {
177 let (infer
, subst
, goal
) = self.new_inference_table(canonical_goal
);
178 match Fulfill
::new_with_clause(self, infer
, subst
, goal
, clause
) {
179 Ok(fulfill
) => (fulfill
.solve(minimums
), clause
.skip_binders().priority
),
180 Err(e
) => (Err(e
), ClausePriority
::High
),
184 fn new_inference_table
<T
: Fold
<I
, I
, Result
= T
> + HasInterner
<Interner
= I
> + Clone
>(
186 ucanonical_goal
: &UCanonical
<InEnvironment
<T
>>,
188 RecursiveInferenceTableImpl
<I
>,
190 InEnvironment
<T
::Result
>,
192 let (infer
, subst
, canonical_goal
) = InferenceTable
::from_canonical(
194 ucanonical_goal
.universes
,
195 &ucanonical_goal
.canonical
,
197 let infer
= RecursiveInferenceTableImpl { infer }
;
198 (infer
, subst
, canonical_goal
)
201 fn program_clauses_for_goal(
203 canonical_goal
: &UCanonical
<InEnvironment
<DomainGoal
<I
>>>,
204 ) -> Result
<Vec
<ProgramClause
<I
>>, Floundered
> {
205 program_clauses_for_goal(
207 &canonical_goal
.canonical
.value
.environment
,
208 &canonical_goal
.canonical
.value
.goal
,
209 &canonical_goal
.canonical
.binders
,
214 impl<S
, I
> SolveIterationHelpers
<I
> for S
221 struct RecursiveInferenceTableImpl
<I
: Interner
> {
222 infer
: InferenceTable
<I
>,
225 impl<I
: Interner
> RecursiveInferenceTable
<I
> for RecursiveInferenceTableImpl
<I
> {
226 fn instantiate_binders_universally
<'a
, T
>(
232 T
: Fold
<I
> + HasInterner
<Interner
= I
>,
234 self.infer
.instantiate_binders_universally(interner
, arg
)
237 fn instantiate_binders_existentially
<'a
, T
>(
243 T
: Fold
<I
> + HasInterner
<Interner
= I
>,
245 self.infer
.instantiate_binders_existentially(interner
, arg
)
252 ) -> (Canonical
<T
::Result
>, Vec
<GenericArg
<I
>>)
255 T
::Result
: HasInterner
<Interner
= I
>,
257 let res
= self.infer
.canonicalize(interner
, value
);
261 .map(|free_var
| free_var
.to_generic_arg(interner
))
263 (res
.quantified
, free_vars
)
266 fn u_canonicalize
<T
>(
269 value0
: &Canonical
<T
>,
270 ) -> (UCanonical
<T
::Result
>, UniverseMap
)
272 T
: HasInterner
<Interner
= I
> + Fold
<I
> + Visit
<I
>,
273 T
::Result
: HasInterner
<Interner
= I
>,
275 let res
= self.infer
.u_canonicalize(interner
, value0
);
276 (res
.quantified
, res
.universes
)
282 environment
: &Environment
<I
>,
285 ) -> Fallible
<Vec
<InEnvironment
<Goal
<I
>>>>
289 let res
= self.infer
.unify(interner
, environment
, a
, b
)?
;
293 fn instantiate_canonical
<T
>(&mut self, interner
: &I
, bound
: &Canonical
<T
>) -> T
::Result
295 T
: HasInterner
<Interner
= I
> + Fold
<I
> + Debug
,
297 self.infer
.instantiate_canonical(interner
, bound
)
300 fn invert_then_canonicalize
<T
>(
304 ) -> Option
<Canonical
<T
::Result
>>
306 T
: Fold
<I
, Result
= T
> + HasInterner
<Interner
= I
>,
308 self.infer
.invert_then_canonicalize(interner
, value
)
311 fn needs_truncation(&mut self, interner
: &I
, max_size
: usize, value
: impl Visit
<I
>) -> bool
{
312 truncate
::needs_truncation(interner
, &mut self.infer
, max_size
, value
)