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