@@ -58,28 +58,68 @@ impl<'i, I: Interner> Folder<'i, I> for SynEqFolder<'i, I> {
5858 }
5959 }
6060
61+ /// Convert a program clause to rem
62+ ///
63+ /// Consider this (nonsense) example:
64+ ///
65+ /// ```notrust
66+ /// forall<X> {
67+ /// Implemented(<X as Iterator>::Item>: Debug) :-
68+ /// Implemented(X: Debug)
69+ /// }
70+ /// ```
71+ ///
72+ /// we would lower this into:
73+ ///
74+ /// ```notrust
75+ /// forall<X, Y> {
76+ /// Implemented(Y: Debug) :-
77+ /// AliasEq(<X as Iterator>::Item>, Y),
78+ /// Implemented(X: Debug)
79+ /// }
80+ /// ```
6181 fn fold_program_clause (
6282 & mut self ,
6383 clause : & ProgramClause < I > ,
6484 outer_binder : DebruijnIndex ,
6585 ) -> Fallible < ProgramClause < I > > {
6686 let interner = self . interner ;
87+ assert ! ( self . new_params. is_empty( ) ) ;
88+ assert ! ( self . new_goals. is_empty( ) ) ;
6789
6890 let ProgramClauseData ( binders) = clause. data ( interner) ;
6991
7092 let implication = binders. skip_binders ( ) ;
7193 let mut binders: Vec < _ > = binders. binders . as_slice ( interner) . into ( ) ;
7294
95+ // Adjust the outer binder to account for the binder in the program clause
7396 let outer_binder = outer_binder. shifted_in ( ) ;
7497
98+ // First lower the "consequence" -- in our example that is
99+ //
100+ // ```
101+ // Implemented(<X as Iterator>::Item: Debug)
102+ // ```
103+ //
104+ // then save out the `new_params` and `new_goals` vectors to store any new variables created as a result.
105+ // In this case, that would be the `Y` parameter and `AliasEq(<X as Iterator>::Item, Y)` goals.
106+ //
107+ // Note that these new parameters will have indices that come after the existing parameters,
108+ // so any references to existing parameters like `X` in the "conditions" are still valid even if we insert new parameters.
75109 self . binders_len = binders. len ( ) ;
110+
76111 let consequence = implication. consequence . fold_with ( self , outer_binder) ?;
77- // Immediately move `new_params` out of of the folder struct so it's safe
78- // to call `.fold_with` again
79- let new_params = replace ( & mut self . new_params , vec ! [ ] ) ;
80- let new_goals = replace ( & mut self . new_goals , vec ! [ ] ) ;
112+ let mut new_params = replace ( & mut self . new_params , vec ! [ ] ) ;
113+ let mut new_goals = replace ( & mut self . new_goals , vec ! [ ] ) ;
114+
115+ // Now fold the conditions (in our example, Implemented(X: Debug).
116+ // The resulting list might be expanded to include new AliasEq goals.
81117
82118 let mut conditions = implication. conditions . fold_with ( self , outer_binder) ?;
119+
120+ new_params. extend ( replace ( & mut self . new_params , vec ! [ ] ) ) ;
121+ new_goals. extend ( replace ( & mut self . new_goals , vec ! [ ] ) ) ;
122+
83123 let constraints = implication. constraints . fold_with ( self , outer_binder) ?;
84124
85125 binders. extend ( new_params. into_iter ( ) ) ;
@@ -102,7 +142,8 @@ impl<'i, I: Interner> Folder<'i, I> for SynEqFolder<'i, I> {
102142 }
103143
104144 fn fold_goal ( & mut self , goal : & Goal < I > , outer_binder : DebruijnIndex ) -> Fallible < Goal < I > > {
105- assert ! ( self . new_params. is_empty( ) , true ) ;
145+ assert ! ( self . new_params. is_empty( ) ) ;
146+ assert ! ( self . new_goals. is_empty( ) ) ;
106147
107148 let interner = self . interner ;
108149 match goal. data ( interner) {
0 commit comments