1- use std:: { iter, mem:: replace } ;
1+ use std:: { iter, mem:: take } ;
22
33use chalk_ir:: {
44 cast:: Cast ,
@@ -9,6 +9,9 @@ use chalk_ir::{
99 VariableKind , VariableKinds ,
1010} ;
1111
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.
1215pub fn syn_eq_lower < I : Interner , T : Fold < I > > ( interner : & I , clause : & T ) -> <T as Fold < I > >:: Result {
1316 let mut folder = SynEqFolder {
1417 interner,
@@ -24,8 +27,15 @@ pub fn syn_eq_lower<I: Interner, T: Fold<I>>(interner: &I, clause: &T) -> <T as
2427
2528struct SynEqFolder < ' i , I : Interner > {
2629 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).
2733 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)
2835 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.
2939 binders_len : usize ,
3040}
3141
@@ -50,7 +60,6 @@ impl<'i, I: Interner> Folder<'i, I> for SynEqFolder<'i, I> {
5060 . cast ( interner) ,
5161 ) ;
5262 self . binders_len += 1 ;
53- ty. super_fold_with ( self , outer_binder) ?;
5463 Ok ( new_ty)
5564 }
5665 TyData :: Function ( _) => Ok ( ty. clone ( ) ) ,
@@ -95,6 +104,9 @@ impl<'i, I: Interner> Folder<'i, I> for SynEqFolder<'i, I> {
95104 // Adjust the outer binder to account for the binder in the program clause
96105 let outer_binder = outer_binder. shifted_in ( ) ;
97106
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+
98110 // First lower the "consequence" -- in our example that is
99111 //
100112 // ```
@@ -106,22 +118,23 @@ impl<'i, I: Interner> Folder<'i, I> for SynEqFolder<'i, I> {
106118 //
107119 // Note that these new parameters will have indices that come after the existing parameters,
108120 // 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-
111121 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 ) ;
114125
115126 // Now fold the conditions (in our example, Implemented(X: Debug).
116127 // The resulting list might be expanded to include new AliasEq goals.
117-
118128 let mut conditions = implication. conditions . fold_with ( self , outer_binder) ?;
119129
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 ) ) ;
122132
123133 let constraints = implication. constraints . fold_with ( self , outer_binder) ?;
124134
135+ new_params. extend ( take ( & mut self . new_params ) ) ;
136+ new_goals. extend ( take ( & mut self . new_goals ) ) ;
137+
125138 binders. extend ( new_params. into_iter ( ) ) ;
126139
127140 conditions = Goals :: from_iter (
@@ -151,14 +164,16 @@ impl<'i, I: Interner> Folder<'i, I> for SynEqFolder<'i, I> {
151164 _ => return goal. super_fold_with ( self , outer_binder) ,
152165 } ;
153166
167+ // Set binders_len to zero as in the exists<..> binder we will create, there are no existing variables.
154168 self . binders_len = 0 ;
169+
155170 // shifted in because we introduce a new binder
156171 let outer_binder = outer_binder. shifted_in ( ) ;
157172 let syn_goal = goal
158173 . shifted_in ( interner)
159174 . 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 ) ;
162177
163178 if new_params. is_empty ( ) {
164179 return Ok ( goal. clone ( ) ) ;
0 commit comments