@@ -58,28 +58,68 @@ impl<'i, I: Interner> Folder<'i, I> for SynEqFolder<'i, I> {
58
58
}
59
59
}
60
60
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
+ /// ```
61
81
fn fold_program_clause (
62
82
& mut self ,
63
83
clause : & ProgramClause < I > ,
64
84
outer_binder : DebruijnIndex ,
65
85
) -> Fallible < ProgramClause < I > > {
66
86
let interner = self . interner ;
87
+ assert ! ( self . new_params. is_empty( ) ) ;
88
+ assert ! ( self . new_goals. is_empty( ) ) ;
67
89
68
90
let ProgramClauseData ( binders) = clause. data ( interner) ;
69
91
70
92
let implication = binders. skip_binders ( ) ;
71
93
let mut binders: Vec < _ > = binders. binders . as_slice ( interner) . into ( ) ;
72
94
95
+ // Adjust the outer binder to account for the binder in the program clause
73
96
let outer_binder = outer_binder. shifted_in ( ) ;
74
97
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.
75
109
self . binders_len = binders. len ( ) ;
110
+
76
111
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.
81
117
82
118
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
+
83
123
let constraints = implication. constraints . fold_with ( self , outer_binder) ?;
84
124
85
125
binders. extend ( new_params. into_iter ( ) ) ;
@@ -102,7 +142,8 @@ impl<'i, I: Interner> Folder<'i, I> for SynEqFolder<'i, I> {
102
142
}
103
143
104
144
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( ) ) ;
106
147
107
148
let interner = self . interner ;
108
149
match goal. data ( interner) {
0 commit comments