1use crate::infer::InferenceTable;
2use chalk_ir::fold::TypeFoldable;
3use chalk_ir::interner::{HasInterner, Interner};
4use chalk_ir::*;
5
6pub trait CanonicalExt<T: HasInterner, I: Interner> {
7 fn map<OP, U>(self, interner: I, op: OP) -> Canonical<U>
8 where
9 OP: FnOnce(T) -> U,
10 T: TypeFoldable<I>,
11 U: TypeFoldable<I>,
12 U: HasInterner<Interner = I>;
13}
14
15impl<T, I> CanonicalExt<T, I> for Canonical<T>
16where
17 T: HasInterner<Interner = I>,
18 I: Interner,
19{
20 fn map<OP, U>(self, interner: I, op: OP) -> Canonical<U>
28 where
29 OP: FnOnce(T) -> U,
30 T: TypeFoldable<I>,
31 U: TypeFoldable<I>,
32 U: HasInterner<Interner = I>,
33 {
34 let mut infer = InferenceTable::new();
44 let snapshot = infer.snapshot();
45 let instantiated_value = infer.instantiate_canonical(interner, self);
46 let mapped_value = op(instantiated_value);
47 let result = infer.canonicalize(interner, mapped_value);
48 infer.rollback_to(snapshot);
49 result.quantified
50 }
51}
52
53pub trait GoalExt<I: Interner> {
54 fn into_peeled_goal(self, interner: I) -> UCanonical<InEnvironment<Goal<I>>>;
55 fn into_closed_goal(self, interner: I) -> UCanonical<InEnvironment<Goal<I>>>;
56}
57
58impl<I: Interner> GoalExt<I> for Goal<I> {
59 fn into_peeled_goal(self, interner: I) -> UCanonical<InEnvironment<Goal<I>>> {
66 let mut infer = InferenceTable::new();
67 let peeled_goal = {
68 let mut env_goal = InEnvironment::new(&Environment::new(interner), self);
69 loop {
70 let InEnvironment { environment, goal } = env_goal;
71 match goal.data(interner) {
72 GoalData::Quantified(QuantifierKind::ForAll, subgoal) => {
73 let subgoal =
74 infer.instantiate_binders_universally(interner, subgoal.clone());
75 env_goal = InEnvironment::new(&environment, subgoal);
76 }
77
78 GoalData::Quantified(QuantifierKind::Exists, subgoal) => {
79 let subgoal =
80 infer.instantiate_binders_existentially(interner, subgoal.clone());
81 env_goal = InEnvironment::new(&environment, subgoal);
82 }
83
84 GoalData::Implies(wc, subgoal) => {
85 let new_environment =
86 environment.add_clauses(interner, wc.iter(interner).cloned());
87 env_goal = InEnvironment::new(&new_environment, Goal::clone(subgoal));
88 }
89
90 _ => break InEnvironment::new(&environment, goal),
91 }
92 }
93 };
94 let canonical = infer.canonicalize(interner, peeled_goal).quantified;
95 InferenceTable::u_canonicalize(interner, &canonical).quantified
96 }
97
98 fn into_closed_goal(self, interner: I) -> UCanonical<InEnvironment<Goal<I>>> {
108 let mut infer = InferenceTable::new();
109 let env_goal = InEnvironment::new(&Environment::new(interner), self);
110 let canonical_goal = infer.canonicalize(interner, env_goal).quantified;
111 InferenceTable::u_canonicalize(interner, &canonical_goal).quantified
112 }
113}