@@ -5,6 +5,7 @@ use cast::CastTo;
5
5
use chalk_ir:: cast:: Cast ;
6
6
use chalk_ir:: cast:: Caster ;
7
7
use chalk_ir:: * ;
8
+ use chalk_rust_ir:: ToParameter ;
8
9
use fold:: shift:: Shift ;
9
10
use fold:: Fold ;
10
11
use interner:: { HasInterner , Interner } ;
@@ -18,14 +19,18 @@ impl<'i, I: Interner> GoalBuilder<'i, I> {
18
19
GoalBuilder { db }
19
20
}
20
21
22
+ /// Returns the database within the goal builder.
21
23
pub ( crate ) fn db ( & self ) -> & ' i dyn RustIrDatabase < I > {
22
24
self . db
23
25
}
24
26
27
+ /// Returns the interner within the goal builder.
25
28
pub ( crate ) fn interner ( & self ) -> & ' i I {
26
29
self . db . interner ( )
27
30
}
28
31
32
+ /// Creates a goal that ensures all of the goals from the `goals`
33
+ /// iterator are met (e.g., `goals[0] && ... && goals[N]`).
29
34
pub ( crate ) fn all < GS , G > ( & mut self , goals : GS ) -> Goal < I >
30
35
where
31
36
GS : IntoIterator < Item = G > ,
@@ -34,6 +39,8 @@ impl<'i, I: Interner> GoalBuilder<'i, I> {
34
39
Goal :: all ( self . interner ( ) , goals. into_iter ( ) . casted ( self . interner ( ) ) )
35
40
}
36
41
42
+ /// Creates a goal `clauses => goal`. The clauses are given as an iterator
43
+ /// and the goal is returned via the contained closure.
37
44
pub ( crate ) fn implies < CS , C , G > (
38
45
& mut self ,
39
46
clauses : CS ,
@@ -51,54 +58,161 @@ impl<'i, I: Interner> GoalBuilder<'i, I> {
51
58
. intern ( self . interner ( ) )
52
59
}
53
60
61
+ /// Given a bound value `binders` like `<P0..Pn> V`,
62
+ /// creates a goal `forall<Q0..Qn> { G }` where
63
+ /// the goal `G` is created by invoking a helper
64
+ /// function `body`.
65
+ ///
66
+ /// # Parameters to `body`
67
+ ///
68
+ /// `body` will be invoked with:
69
+ ///
70
+ /// * the goal builder `self`
71
+ /// * the substitution `Q0..Qn`
72
+ /// * the bound value `[P0..Pn => Q0..Qn] V` instantiated
73
+ /// with the substitution
74
+ /// * the value `passthru`, appropriately shifted so that
75
+ /// any debruijn indices within account for the new binder
76
+ ///
77
+ /// # Why is `body` a function and not a closure?
78
+ ///
79
+ /// This is to ensure that `body` doesn't accidentally reference
80
+ /// values from the environment whose debruijn indices do not
81
+ /// account for the new binder being created.
54
82
pub ( crate ) fn forall < G , B , P > (
55
83
& mut self ,
56
84
binders : & Binders < B > ,
57
85
passthru : P ,
58
- body : fn ( & mut Self , & B , P :: Result ) -> G ,
86
+ body : fn ( & mut Self , Substitution < I > , B :: Result , P :: Result ) -> G ,
59
87
) -> Goal < I >
60
88
where
61
89
B : Fold < I > + HasInterner < Interner = I > ,
62
90
P : Fold < I > ,
63
91
B :: Result : std:: fmt:: Debug ,
64
92
G : CastTo < Goal < I > > ,
65
93
{
66
- self . quantified ( QuantifierKind :: ForAll , binders, passthru, body)
94
+ self . partially_quantified ( QuantifierKind :: ForAll , binders, & [ ] , passthru, body)
67
95
}
68
96
97
+ /// Like [`GoalBuilder::forall`], but for a `exists<Q0..Qn> { G }` goal.
69
98
pub ( crate ) fn exists < G , B , P > (
70
99
& mut self ,
71
100
binders : & Binders < B > ,
72
101
passthru : P ,
73
- body : fn ( & mut Self , & B , P :: Result ) -> G ,
102
+ body : fn ( & mut Self , Substitution < I > , B :: Result , P :: Result ) -> G ,
74
103
) -> Goal < I >
75
104
where
76
105
B : Fold < I > + HasInterner < Interner = I > ,
77
106
P : Fold < I > ,
78
107
B :: Result : std:: fmt:: Debug ,
79
108
G : CastTo < Goal < I > > ,
80
109
{
81
- self . quantified ( QuantifierKind :: Exists , binders, passthru, body)
110
+ self . partially_quantified ( QuantifierKind :: Exists , binders, & [ ] , passthru, body)
82
111
}
83
112
84
- pub ( crate ) fn quantified < G , B , P > (
113
+ /// Like `[GoalBuilder::forall`], except that it also takes
114
+ /// a (partial) substitution `S0..Sm` that provides some
115
+ /// suffix of the values for the bound value `<P0..Pn> V`.
116
+ ///
117
+ /// The resulting goal will be `forall<Q0..Q(n-m)> { G }`,
118
+ /// and the resulting substitution for the bound value `V`
119
+ /// will be `[Q0, .., Q(n-m), S0, .., Sm]`.
120
+ ///
121
+ /// This is useful for associated items within traits and impls:
122
+ /// the binders on such items contain both the binders from the trait
123
+ /// and impl as well as from the associated item itself. Here, the
124
+ /// "partial substitution" would be the values from the trait/impl.
125
+ pub ( crate ) fn partially_forall < G , B , P > (
126
+ & mut self ,
127
+ binders : & Binders < B > ,
128
+ partial_substitution : & Substitution < I > ,
129
+ passthru : P ,
130
+ body : fn ( & mut Self , Substitution < I > , B :: Result , P :: Result ) -> G ,
131
+ ) -> Goal < I >
132
+ where
133
+ B : Fold < I > + HasInterner < Interner = I > ,
134
+ P : Fold < I > ,
135
+ B :: Result : std:: fmt:: Debug ,
136
+ G : CastTo < Goal < I > > ,
137
+ {
138
+ self . partially_quantified (
139
+ QuantifierKind :: ForAll ,
140
+ binders,
141
+ partial_substitution. parameters ( self . interner ( ) ) ,
142
+ passthru,
143
+ body,
144
+ )
145
+ }
146
+
147
+ /// Like [`GoalBuilder::partially_forall`], but for a `exists` goal.
148
+ pub ( crate ) fn partially_exists < G , B , P > (
149
+ & mut self ,
150
+ binders : & Binders < B > ,
151
+ partial_substitution : & Substitution < I > ,
152
+ passthru : P ,
153
+ body : fn ( & mut Self , Substitution < I > , B :: Result , P :: Result ) -> G ,
154
+ ) -> Goal < I >
155
+ where
156
+ B : Fold < I > + HasInterner < Interner = I > ,
157
+ P : Fold < I > ,
158
+ B :: Result : std:: fmt:: Debug ,
159
+ G : CastTo < Goal < I > > ,
160
+ {
161
+ self . partially_quantified (
162
+ QuantifierKind :: Exists ,
163
+ binders,
164
+ partial_substitution. parameters ( self . interner ( ) ) ,
165
+ passthru,
166
+ body,
167
+ )
168
+ }
169
+
170
+ /// A combined helper functon for the various methods
171
+ /// to create `forall` and `exists` goals. See:
172
+ ///
173
+ /// * [`GoalBuilder::forall`]
174
+ /// * [`GoalBuilder::partially_forall`]
175
+ ///
176
+ /// for details.
177
+ pub ( crate ) fn partially_quantified < G , B , P > (
85
178
& mut self ,
86
179
quantifier_kind : QuantifierKind ,
87
180
binders : & Binders < B > ,
181
+ partial_substitution : & [ Parameter < I > ] ,
88
182
passthru : P ,
89
- body : fn ( & mut Self , & B , P :: Result ) -> G ,
183
+ body : fn ( & mut Self , Substitution < I > , B :: Result , P :: Result ) -> G ,
90
184
) -> Goal < I >
91
185
where
92
186
B : Fold < I > + HasInterner < Interner = I > ,
93
187
P : Fold < I > ,
94
188
B :: Result : std:: fmt:: Debug ,
95
189
G : CastTo < Goal < I > > ,
96
190
{
97
- let bound_goal = binders. map_ref ( |bound_value| {
191
+ let interner = self . interner ( ) ;
192
+ assert ! ( binders. binders. len( ) >= partial_substitution. len( ) ) ;
193
+ let split_point = binders. binders . len ( ) - partial_substitution. len ( ) ;
194
+ let ( quantified_binders, _) = binders. binders . split_at ( split_point) ;
195
+ let combined_values: Substitution < I > = Substitution :: from (
196
+ interner,
197
+ quantified_binders
198
+ . iter ( )
199
+ . zip ( 0 ..)
200
+ . map ( |p| p. to_parameter ( interner) )
201
+ . chain (
202
+ // Note that the values from the partial substitution must be shifted
203
+ // in by one to account for the new binder we are introducing.
204
+ partial_substitution. iter ( ) . map ( |p| p. shifted_in ( interner) ) ,
205
+ ) ,
206
+ ) ;
207
+ let bound_goal = {
208
+ let bound_value = binders. substitute ( interner, & combined_values) ;
98
209
let passthru_shifted = passthru. shifted_in ( self . interner ( ) ) ;
99
- let result = body ( self , bound_value, passthru_shifted) ;
100
- result. cast ( self . interner ( ) )
101
- } ) ;
210
+ let result = body ( self , combined_values, bound_value, passthru_shifted) ;
211
+ Binders {
212
+ binders : quantified_binders. to_vec ( ) ,
213
+ value : result. cast ( self . interner ( ) ) ,
214
+ }
215
+ } ;
102
216
GoalData :: Quantified ( quantifier_kind, bound_goal) . intern ( self . interner ( ) )
103
217
}
104
218
}
0 commit comments