@@ -41,6 +41,7 @@ impl Program {
41
41
}
42
42
}
43
43
44
+ /// A trait for retrieving all types appearing in some Chalk construction.
44
45
trait FoldInputTypes {
45
46
fn fold ( & self , accumulator : & mut Vec < Ty > ) ;
46
47
}
@@ -77,7 +78,10 @@ impl FoldInputTypes for Ty {
77
78
accumulator. push ( self . clone ( ) ) ;
78
79
proj. parameters . fold ( accumulator) ;
79
80
}
80
- _ => ( ) ,
81
+
82
+ // Type parameters and higher-kinded types do not carry any input types (so we can sort
83
+ // of assume they are always WF).
84
+ Ty :: Var ( ..) | Ty :: ForAll ( ..) => ( ) ,
81
85
}
82
86
}
83
87
}
@@ -108,13 +112,15 @@ impl FoldInputTypes for DomainGoal {
108
112
DomainGoal :: Implemented ( ref tr) => tr. fold ( accumulator) ,
109
113
DomainGoal :: Normalize ( ref n) => n. fold ( accumulator) ,
110
114
DomainGoal :: UnselectedNormalize ( ref n) => n. fold ( accumulator) ,
115
+ DomainGoal :: WellFormed ( ..) | DomainGoal :: FromEnv ( ..) => panic ! ( "unexpected where clause" ) ,
111
116
_ => ( ) ,
112
117
}
113
118
}
114
119
}
115
120
116
121
impl WfSolver {
117
122
fn verify_struct_decl ( & self , struct_datum : & StructDatum ) -> bool {
123
+ // We retrieve all the input types of the struct fields.
118
124
let mut input_types = Vec :: new ( ) ;
119
125
struct_datum. binders . value . fields . fold ( & mut input_types) ;
120
126
struct_datum. binders . value . where_clauses . fold ( & mut input_types) ;
@@ -124,7 +130,6 @@ impl WfSolver {
124
130
}
125
131
126
132
let goals = input_types. into_iter ( ) . map ( |ty| WellFormed :: Ty ( ty) . cast ( ) ) ;
127
-
128
133
let goal = goals. fold1 ( |goal, leaf| Goal :: And ( Box :: new ( goal) , Box :: new ( leaf) ) )
129
134
. expect ( "at least one goal" ) ;
130
135
@@ -137,6 +142,8 @@ impl WfSolver {
137
142
. map ( |wc| wc. into_from_env_clause ( ) )
138
143
. collect ( ) ;
139
144
145
+ // We ask that the above input types are well-formed provided that all the where-clauses
146
+ // on the struct definition hold.
140
147
let goal = Goal :: Implies ( hypotheses, Box :: new ( goal) )
141
148
. quantify ( QuantifierKind :: ForAll , struct_datum. binders . binders . clone ( ) ) ;
142
149
@@ -152,9 +159,62 @@ impl WfSolver {
152
159
_ => return true
153
160
} ;
154
161
162
+ // We retrieve all the input types of the where clauses appearing on the trait impl,
163
+ // e.g. in:
164
+ // ```
165
+ // impl<T, K> Foo for (Set<K>, Vec<Box<T>>) { ... }
166
+ // ```
167
+ // we would retrieve `Set<K>`, `Box<T>`, `Vec<Box<T>>`, `(Set<K>, Vec<Box<T>>)`.
168
+ // We will have to prove that these types are well-formed.
155
169
let mut input_types = Vec :: new ( ) ;
156
170
impl_datum. binders . value . where_clauses . fold ( & mut input_types) ;
157
171
172
+ // We partition the input types of the type on which we implement the trait in two categories:
173
+ // * projection types, e.g. `<T as Iterator>::Item`: we will have to prove that these types
174
+ // are well-formed, e.g. that we can show that `T: Iterator` holds
175
+ // * any other types, e.g. `HashSet<K>`: we will *assume* that these types are well-formed, e.g.
176
+ // we will be able to derive that `K: Hash` holds without writing any where clause.
177
+ //
178
+ // Examples:
179
+ // ```
180
+ // struct HashSet<K> where K: Hash { ... }
181
+ //
182
+ // impl<K> Foo for HashSet<K> {
183
+ // // Inside here, we can rely on the fact that `K: Hash` holds
184
+ // }
185
+ // ```
186
+ //
187
+ // ```
188
+ // impl<T> Foo for <T as Iterator>::Item {
189
+ // // The impl is not well-formed, as an exception we do not assume that
190
+ // // `<T as Iterator>::Item` is well-formed and instead want to prove it.
191
+ // }
192
+ // ```
193
+ //
194
+ // ```
195
+ // impl<T> Foo for <T as Iterator>::Item where T: Iterator {
196
+ // // Now ok.
197
+ // }
198
+ // ```
199
+ let mut header_input_types = Vec :: new ( ) ;
200
+ trait_ref. fold ( & mut header_input_types) ;
201
+ let ( header_projection_types, header_other_types) : ( Vec < _ > , Vec < _ > ) =
202
+ header_input_types. into_iter ( )
203
+ . partition ( |ty| ty. is_projection ( ) ) ;
204
+
205
+ // Associated type values are special because they can be parametric (independently of
206
+ // the impl), so we issue a special goal which is quantified using the binders of the
207
+ // associated type value, for example in:
208
+ // ```
209
+ // trait Foo {
210
+ // type Item<'a>
211
+ // }
212
+ //
213
+ // impl<T> Foo for Box<T> {
214
+ // type Item<'a> = Box<&'a T>;
215
+ // }
216
+ // ```
217
+ // we would issue the following subgoal: `forall<'a> { WellFormed(Box<&'a T>) }`.
158
218
let compute_assoc_ty_goal = |assoc_ty : & AssociatedTyValue | {
159
219
let mut input_types = Vec :: new ( ) ;
160
220
assoc_ty. value . value . ty . fold ( & mut input_types) ;
@@ -176,12 +236,8 @@ impl WfSolver {
176
236
. iter ( )
177
237
. filter_map ( compute_assoc_ty_goal) ;
178
238
179
- let mut header_input_types = Vec :: new ( ) ;
180
- trait_ref. fold ( & mut header_input_types) ;
181
- let ( header_projection_types, header_other_types) : ( Vec < _ > , Vec < _ > ) =
182
- header_input_types. into_iter ( )
183
- . partition ( |ty| ty. is_projection ( ) ) ;
184
-
239
+ // Things to prove well-formed: input types of the where-clauses, projection types
240
+ // appearing in the header, associated type values, and of course the trait ref.
185
241
let goals =
186
242
input_types. into_iter ( )
187
243
. chain ( header_projection_types. into_iter ( ) )
@@ -191,6 +247,10 @@ impl WfSolver {
191
247
192
248
let goal = goals. fold1 ( |goal, leaf| Goal :: And ( Box :: new ( goal) , Box :: new ( leaf) ) )
193
249
. expect ( "at least one goal" ) ;
250
+
251
+ // Assumptions: types appearing in the header which are not projection types are
252
+ // assumed to be well-formed, and where clauses declared on the impl are assumed
253
+ // to hold.
194
254
let hypotheses =
195
255
impl_datum. binders
196
256
. value
0 commit comments