1
- use std:: { iter, mem:: replace } ;
1
+ use std:: { iter, mem:: take } ;
2
2
3
3
use chalk_ir:: {
4
4
cast:: Cast ,
@@ -9,6 +9,9 @@ use chalk_ir::{
9
9
VariableKind , VariableKinds ,
10
10
} ;
11
11
12
+ /// Converts a set of clauses to require only syntactic equality.
13
+ /// This is done by introducing new parameters and subgoals in cases
14
+ /// where semantic equality may diverge, for instance in unnormalized projections.
12
15
pub fn syn_eq_lower < I : Interner , T : Fold < I > > ( interner : & I , clause : & T ) -> <T as Fold < I > >:: Result {
13
16
let mut folder = SynEqFolder {
14
17
interner,
@@ -24,8 +27,15 @@ pub fn syn_eq_lower<I: Interner, T: Fold<I>>(interner: &I, clause: &T) -> <T as
24
27
25
28
struct SynEqFolder < ' i , I : Interner > {
26
29
interner : & ' i I ,
30
+ /// Stores the kinds of new parameters introduced during folding.
31
+ /// The new parameters will either be added to an enclosing `exists` binder (when lowering a goal)
32
+ /// or to an enclosing `forall` binder (when lowering a program clause).
27
33
new_params : Vec < VariableKind < I > > ,
34
+ /// For each new parameter `X`, a new goal is introduced to define it, e.g. `AliasEq(<T as Iterator>::Item, X)
28
35
new_goals : Vec < Goal < I > > ,
36
+
37
+ /// Stores the current number of variables in the binder we are adding parameters to.
38
+ /// Incremented for each new variable added.
29
39
binders_len : usize ,
30
40
}
31
41
@@ -50,7 +60,6 @@ impl<'i, I: Interner> Folder<'i, I> for SynEqFolder<'i, I> {
50
60
. cast ( interner) ,
51
61
) ;
52
62
self . binders_len += 1 ;
53
- ty. super_fold_with ( self , outer_binder) ?;
54
63
Ok ( new_ty)
55
64
}
56
65
TyData :: Function ( _) => Ok ( ty. clone ( ) ) ,
@@ -95,6 +104,9 @@ impl<'i, I: Interner> Folder<'i, I> for SynEqFolder<'i, I> {
95
104
// Adjust the outer binder to account for the binder in the program clause
96
105
let outer_binder = outer_binder. shifted_in ( ) ;
97
106
107
+ // Set binders_len to binders.len() since new parameters will be added into the existing forall<...> binder on the program clause.
108
+ self . binders_len = binders. len ( ) ;
109
+
98
110
// First lower the "consequence" -- in our example that is
99
111
//
100
112
// ```
@@ -106,22 +118,23 @@ impl<'i, I: Interner> Folder<'i, I> for SynEqFolder<'i, I> {
106
118
//
107
119
// Note that these new parameters will have indices that come after the existing parameters,
108
120
// so any references to existing parameters like `X` in the "conditions" are still valid even if we insert new parameters.
109
- self . binders_len = binders. len ( ) ;
110
-
111
121
let consequence = implication. consequence . fold_with ( self , outer_binder) ?;
112
- let mut new_params = replace ( & mut self . new_params , vec ! [ ] ) ;
113
- let mut new_goals = replace ( & mut self . new_goals , vec ! [ ] ) ;
122
+
123
+ let mut new_params = take ( & mut self . new_params ) ;
124
+ let mut new_goals = take ( & mut self . new_goals ) ;
114
125
115
126
// Now fold the conditions (in our example, Implemented(X: Debug).
116
127
// The resulting list might be expanded to include new AliasEq goals.
117
-
118
128
let mut conditions = implication. conditions . fold_with ( self , outer_binder) ?;
119
129
120
- new_params. extend ( replace ( & mut self . new_params , vec ! [ ] ) ) ;
121
- new_goals. extend ( replace ( & mut self . new_goals , vec ! [ ] ) ) ;
130
+ new_params. extend ( take ( & mut self . new_params ) ) ;
131
+ new_goals. extend ( take ( & mut self . new_goals ) ) ;
122
132
123
133
let constraints = implication. constraints . fold_with ( self , outer_binder) ?;
124
134
135
+ new_params. extend ( take ( & mut self . new_params ) ) ;
136
+ new_goals. extend ( take ( & mut self . new_goals ) ) ;
137
+
125
138
binders. extend ( new_params. into_iter ( ) ) ;
126
139
127
140
conditions = Goals :: from_iter (
@@ -151,14 +164,16 @@ impl<'i, I: Interner> Folder<'i, I> for SynEqFolder<'i, I> {
151
164
_ => return goal. super_fold_with ( self , outer_binder) ,
152
165
} ;
153
166
167
+ // Set binders_len to zero as in the exists<..> binder we will create, there are no existing variables.
154
168
self . binders_len = 0 ;
169
+
155
170
// shifted in because we introduce a new binder
156
171
let outer_binder = outer_binder. shifted_in ( ) ;
157
172
let syn_goal = goal
158
173
. shifted_in ( interner)
159
174
. super_fold_with ( self , outer_binder) ?;
160
- let new_params = replace ( & mut self . new_params , vec ! [ ] ) ;
161
- let new_goals = replace ( & mut self . new_goals , vec ! [ ] ) ;
175
+ let new_params = take ( & mut self . new_params ) ;
176
+ let new_goals = take ( & mut self . new_goals ) ;
162
177
163
178
if new_params. is_empty ( ) {
164
179
return Ok ( goal. clone ( ) ) ;
0 commit comments