@@ -81,8 +81,6 @@ pub fn check_crate(tcx: ty::ctxt,
81
81
tcx. sess . abort_if_errors ( ) ;
82
82
}
83
83
84
- type check_fn = @fn ( Context , @freevar_entry ) ;
85
-
86
84
fn check_struct_safe_for_destructor ( cx : Context ,
87
85
span : span ,
88
86
struct_did : def_id ) {
@@ -163,30 +161,43 @@ fn check_item(item: @item, (cx, visitor): (Context, visit::vt<Context>)) {
163
161
// Yields the appropriate function to check the kind of closed over
164
162
// variables. `id` is the node_id for some expression that creates the
165
163
// closure.
166
- fn with_appropriate_checker ( cx : Context , id : node_id , b : & fn ( check_fn ) ) {
167
- fn check_for_uniq ( cx : Context , fv : @freevar_entry ) {
164
+ fn with_appropriate_checker ( cx : Context , id : node_id ,
165
+ b : & fn ( checker : & fn ( Context , @freevar_entry ) ) ) {
166
+ fn check_for_uniq ( cx : Context , fv : @freevar_entry , bounds : ty:: BuiltinBounds ) {
168
167
// all captured data must be owned, regardless of whether it is
169
168
// moved in or copied in.
170
169
let id = ast_util:: def_id_of_def ( fv. def ) . node ;
171
170
let var_t = ty:: node_id_to_type ( cx. tcx , id) ;
171
+
172
+ // FIXME(#3569): Once closure capabilities are restricted based on their
173
+ // incoming bounds, make this check conditional based on the bounds.
172
174
if !check_owned ( cx, var_t, fv. span ) { return ; }
173
175
174
176
// check that only immutable variables are implicitly copied in
175
177
check_imm_free_var ( cx, fv. def , fv. span ) ;
178
+
179
+ check_freevar_bounds ( cx, fv. span , var_t, bounds) ;
176
180
}
177
181
178
- fn check_for_box ( cx : Context , fv : @freevar_entry ) {
182
+ fn check_for_box ( cx : Context , fv : @freevar_entry , bounds : ty :: BuiltinBounds ) {
179
183
// all captured data must be owned
180
184
let id = ast_util:: def_id_of_def ( fv. def ) . node ;
181
185
let var_t = ty:: node_id_to_type ( cx. tcx , id) ;
186
+
187
+ // FIXME(#3569): Once closure capabilities are restricted based on their
188
+ // incoming bounds, make this check conditional based on the bounds.
182
189
if !check_durable ( cx. tcx , var_t, fv. span ) { return ; }
183
190
184
191
// check that only immutable variables are implicitly copied in
185
192
check_imm_free_var ( cx, fv. def , fv. span ) ;
193
+
194
+ check_freevar_bounds ( cx, fv. span , var_t, bounds) ;
186
195
}
187
196
188
- fn check_for_block ( _cx : Context , _fv : @freevar_entry ) {
189
- // no restrictions
197
+ fn check_for_block ( cx : Context , fv : @freevar_entry , bounds : ty:: BuiltinBounds ) {
198
+ let id = ast_util:: def_id_of_def ( fv. def ) . node ;
199
+ let var_t = ty:: node_id_to_type ( cx. tcx , id) ;
200
+ check_freevar_bounds ( cx, fv. span , var_t, bounds) ;
190
201
}
191
202
192
203
fn check_for_bare ( cx : Context , fv : @freevar_entry ) {
@@ -197,14 +208,14 @@ fn with_appropriate_checker(cx: Context, id: node_id, b: &fn(check_fn)) {
197
208
198
209
let fty = ty:: node_id_to_type ( cx. tcx , id) ;
199
210
match ty:: get ( fty) . sty {
200
- ty:: ty_closure( ty:: ClosureTy { sigil : OwnedSigil , _} ) => {
201
- b ( check_for_uniq)
211
+ ty:: ty_closure( ty:: ClosureTy { sigil : OwnedSigil , bounds : bounds , _} ) => {
212
+ b ( |cx , fv| check_for_uniq ( cx , fv , bounds ) )
202
213
}
203
- ty:: ty_closure( ty:: ClosureTy { sigil : ManagedSigil , _} ) => {
204
- b ( check_for_box)
214
+ ty:: ty_closure( ty:: ClosureTy { sigil : ManagedSigil , bounds : bounds , _} ) => {
215
+ b ( |cx , fv| check_for_box ( cx , fv , bounds ) )
205
216
}
206
- ty:: ty_closure( ty:: ClosureTy { sigil : BorrowedSigil , _} ) => {
207
- b ( check_for_block)
217
+ ty:: ty_closure( ty:: ClosureTy { sigil : BorrowedSigil , bounds : bounds , _} ) => {
218
+ b ( |cx , fv| check_for_block ( cx , fv , bounds ) )
208
219
}
209
220
ty:: ty_bare_fn( _) => {
210
221
b ( check_for_bare)
@@ -272,7 +283,7 @@ pub fn check_expr(e: @expr, (cx, v): (Context, visit::vt<Context>)) {
272
283
type_param_defs. repr( cx. tcx) ) ;
273
284
}
274
285
for ts. iter( ) . zip( type_param_defs. iter( ) ) . advance |( & ty, type_param_def) | {
275
- check_bounds ( cx, type_parameter_id, e. span, ty, type_param_def)
286
+ check_typaram_bounds ( cx, type_parameter_id, e. span, ty, type_param_def)
276
287
}
277
288
}
278
289
}
@@ -315,7 +326,7 @@ fn check_ty(aty: @Ty, (cx, v): (Context, visit::vt<Context>)) {
315
326
let type_param_defs =
316
327
ty:: lookup_item_type( cx. tcx, did) . generics. type_param_defs;
317
328
for ts. iter( ) . zip( type_param_defs. iter( ) ) . advance |( & ty, type_param_def) | {
318
- check_bounds ( cx, aty. id, aty. span, ty, type_param_def)
329
+ check_typaram_bounds ( cx, aty. id, aty. span, ty, type_param_def)
319
330
}
320
331
}
321
332
}
@@ -324,19 +335,26 @@ fn check_ty(aty: @Ty, (cx, v): (Context, visit::vt<Context>)) {
324
335
visit:: visit_ty( aty, ( cx, v) ) ;
325
336
}
326
337
327
- pub fn check_bounds ( cx : Context ,
328
- _type_parameter_id : node_id ,
329
- sp : span ,
330
- ty : ty:: t ,
331
- type_param_def : & ty:: TypeParameterDef )
338
+ pub fn check_builtin_bounds( cx: Context , ty: ty:: t, bounds: ty:: BuiltinBounds )
339
+ -> ty:: BuiltinBounds // returns the missing bounds
332
340
{
333
341
let kind = ty:: type_contents( cx. tcx, ty) ;
334
342
let mut missing = ty:: EmptyBuiltinBounds ( ) ;
335
- for type_param_def . bounds. builtin_bounds . each |bound| {
343
+ for bounds. each |bound| {
336
344
if !kind. meets_bound( cx. tcx, bound) {
337
345
missing. add( bound) ;
338
346
}
339
347
}
348
+ missing
349
+ }
350
+
351
+ pub fn check_typaram_bounds ( cx : Context ,
352
+ _type_parameter_id : node_id ,
353
+ sp : span ,
354
+ ty : ty:: t ,
355
+ type_param_def : & ty:: TypeParameterDef )
356
+ {
357
+ let missing = check_builtin_bounds ( cx, ty, type_param_def. bounds . builtin_bounds ) ;
340
358
if !missing. is_empty ( ) {
341
359
cx. tcx . sess . span_err (
342
360
sp,
@@ -347,6 +365,23 @@ pub fn check_bounds(cx: Context,
347
365
}
348
366
}
349
367
368
+ pub fn check_freevar_bounds ( cx : Context , sp : span , ty : ty:: t ,
369
+ bounds : ty:: BuiltinBounds )
370
+ {
371
+ let missing = check_builtin_bounds ( cx, ty, bounds) ;
372
+ if !missing. is_empty ( ) {
373
+ cx. tcx . sess . span_err (
374
+ sp,
375
+ fmt ! ( "cannot capture variable of type `%s`, which does not fulfill \
376
+ `%s`, in a bounded closure",
377
+ ty_to_str( cx. tcx, ty) , missing. user_string( cx. tcx) ) ) ;
378
+ cx. tcx . sess . span_note (
379
+ sp,
380
+ fmt ! ( "this closure's environment must satisfy `%s`" ,
381
+ bounds. user_string( cx. tcx) ) ) ;
382
+ }
383
+ }
384
+
350
385
fn is_nullary_variant ( cx : Context , ex: @expr) -> bool {
351
386
match ex. node {
352
387
expr_path( _) => {
0 commit comments