@@ -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 ) {
@@ -129,7 +127,8 @@ fn check_item(item: @item, (cx, visitor): (Context, visit::vt<Context>)) {
129
127
if cx. tcx . lang_items . drop_trait ( ) == trait_def_id {
130
128
// Yes, it's a destructor.
131
129
match self_type. node {
132
- ty_path( _, path_node_id) => {
130
+ ty_path( _, bounds, path_node_id) => {
131
+ assert ! ( bounds. is_empty( ) ) ;
133
132
let struct_def = cx. tcx . def_map . get_copy (
134
133
& path_node_id) ;
135
134
let struct_did =
@@ -162,30 +161,43 @@ fn check_item(item: @item, (cx, visitor): (Context, visit::vt<Context>)) {
162
161
// Yields the appropriate function to check the kind of closed over
163
162
// variables. `id` is the node_id for some expression that creates the
164
163
// 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 ) {
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 ) {
167
167
// all captured data must be owned, regardless of whether it is
168
168
// moved in or copied in.
169
169
let id = ast_util:: def_id_of_def ( fv. def ) . node ;
170
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.
171
174
if !check_owned ( cx, var_t, fv. span ) { return ; }
172
175
173
176
// check that only immutable variables are implicitly copied in
174
177
check_imm_free_var ( cx, fv. def , fv. span ) ;
178
+
179
+ check_freevar_bounds ( cx, fv. span , var_t, bounds) ;
175
180
}
176
181
177
- fn check_for_box ( cx : Context , fv : @freevar_entry ) {
182
+ fn check_for_box ( cx : Context , fv : @freevar_entry , bounds : ty :: BuiltinBounds ) {
178
183
// all captured data must be owned
179
184
let id = ast_util:: def_id_of_def ( fv. def ) . node ;
180
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.
181
189
if !check_durable ( cx. tcx , var_t, fv. span ) { return ; }
182
190
183
191
// check that only immutable variables are implicitly copied in
184
192
check_imm_free_var ( cx, fv. def , fv. span ) ;
193
+
194
+ check_freevar_bounds ( cx, fv. span , var_t, bounds) ;
185
195
}
186
196
187
- fn check_for_block ( _cx : Context , _fv : @freevar_entry ) {
188
- // 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) ;
189
201
}
190
202
191
203
fn check_for_bare ( cx : Context , fv : @freevar_entry ) {
@@ -196,14 +208,14 @@ fn with_appropriate_checker(cx: Context, id: node_id, b: &fn(check_fn)) {
196
208
197
209
let fty = ty:: node_id_to_type ( cx. tcx , id) ;
198
210
match ty:: get ( fty) . sty {
199
- ty:: ty_closure( ty:: ClosureTy { sigil : OwnedSigil , _} ) => {
200
- b ( check_for_uniq)
211
+ ty:: ty_closure( ty:: ClosureTy { sigil : OwnedSigil , bounds : bounds , _} ) => {
212
+ b ( |cx , fv| check_for_uniq ( cx , fv , bounds ) )
201
213
}
202
- ty:: ty_closure( ty:: ClosureTy { sigil : ManagedSigil , _} ) => {
203
- b ( check_for_box)
214
+ ty:: ty_closure( ty:: ClosureTy { sigil : ManagedSigil , bounds : bounds , _} ) => {
215
+ b ( |cx , fv| check_for_box ( cx , fv , bounds ) )
204
216
}
205
- ty:: ty_closure( ty:: ClosureTy { sigil : BorrowedSigil , _} ) => {
206
- b ( check_for_block)
217
+ ty:: ty_closure( ty:: ClosureTy { sigil : BorrowedSigil , bounds : bounds , _} ) => {
218
+ b ( |cx , fv| check_for_block ( cx , fv , bounds ) )
207
219
}
208
220
ty:: ty_bare_fn( _) => {
209
221
b ( check_for_bare)
@@ -271,15 +283,21 @@ pub fn check_expr(e: @expr, (cx, v): (Context, visit::vt<Context>)) {
271
283
type_param_defs. repr( cx. tcx) ) ;
272
284
}
273
285
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)
286
+ check_typaram_bounds ( cx, type_parameter_id, e. span, ty, type_param_def)
275
287
}
276
288
}
277
289
}
278
290
279
291
match e. node {
280
292
expr_cast( source, _) => {
281
293
check_cast_for_escaping_regions( cx, source, e) ;
282
- check_kind_bounds_of_cast( cx, source, e) ;
294
+ match ty:: get( ty:: expr_ty( cx. tcx, e) ) . sty {
295
+ ty : : ty_trait( _, _, store, _, bounds) => {
296
+ let source_ty = ty:: expr_ty( cx. tcx, source) ;
297
+ check_trait_cast_bounds( cx, e. span, source_ty, bounds, store)
298
+ }
299
+ _ => { }
300
+ }
283
301
}
284
302
expr_copy( expr) => {
285
303
// Note: This is the only place where we must check whether the
@@ -307,14 +325,14 @@ pub fn check_expr(e: @expr, (cx, v): (Context, visit::vt<Context>)) {
307
325
308
326
fn check_ty( aty: @Ty , ( cx, v) : ( Context , visit:: vt < Context > ) ) {
309
327
match aty. node {
310
- ty_path( _, id) => {
328
+ ty_path( _, _ , id) => {
311
329
let r = cx. tcx. node_type_substs. find( & id) ;
312
330
for r. iter( ) . advance |ts| {
313
331
let did = ast_util:: def_id_of_def( cx. tcx. def_map. get_copy( & id) ) ;
314
332
let type_param_defs =
315
333
ty:: lookup_item_type( cx. tcx, did) . generics. type_param_defs;
316
334
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)
335
+ check_typaram_bounds ( cx, aty. id, aty. span, ty, type_param_def)
318
336
}
319
337
}
320
338
}
@@ -323,20 +341,29 @@ fn check_ty(aty: @Ty, (cx, v): (Context, visit::vt<Context>)) {
323
341
visit:: visit_ty( aty, ( cx, v) ) ;
324
342
}
325
343
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 )
344
+ // Calls "any_missing" if any bounds were missing.
345
+ pub fn check_builtin_bounds ( cx : Context , ty : ty:: t , bounds : ty:: BuiltinBounds ,
346
+ any_missing : & fn ( ty:: BuiltinBounds ) )
331
347
{
332
348
let kind = ty:: type_contents ( cx. tcx , ty) ;
333
349
let mut missing = ty:: EmptyBuiltinBounds ( ) ;
334
- for type_param_def . bounds. builtin_bounds . each |bound| {
350
+ for bounds. each |bound| {
335
351
if !kind. meets_bound ( cx. tcx , bound) {
336
352
missing. add ( bound) ;
337
353
}
338
354
}
339
355
if !missing. is_empty ( ) {
356
+ any_missing ( missing) ;
357
+ }
358
+ }
359
+
360
+ pub fn check_typaram_bounds ( cx : Context ,
361
+ _type_parameter_id : node_id ,
362
+ sp : span ,
363
+ ty : ty:: t ,
364
+ type_param_def : & ty:: TypeParameterDef )
365
+ {
366
+ do check_builtin_bounds ( cx, ty, type_param_def. bounds . builtin_bounds ) |missing| {
340
367
cx. tcx . sess . span_err (
341
368
sp,
342
369
fmt ! ( "instantiating a type parameter with an incompatible type \
@@ -346,6 +373,38 @@ pub fn check_bounds(cx: Context,
346
373
}
347
374
}
348
375
376
+ pub fn check_freevar_bounds ( cx : Context , sp : span , ty : ty:: t ,
377
+ bounds : ty:: BuiltinBounds )
378
+ {
379
+ do check_builtin_bounds ( cx, ty, bounds) |missing| {
380
+ cx. tcx . sess . span_err (
381
+ sp,
382
+ fmt ! ( "cannot capture variable of type `%s`, which does not fulfill \
383
+ `%s`, in a bounded closure",
384
+ ty_to_str( cx. tcx, ty) , missing. user_string( cx. tcx) ) ) ;
385
+ cx. tcx . sess . span_note (
386
+ sp,
387
+ fmt ! ( "this closure's environment must satisfy `%s`" ,
388
+ bounds. user_string( cx. tcx) ) ) ;
389
+ }
390
+ }
391
+
392
+ pub fn check_trait_cast_bounds( cx : Context , sp : span , ty : ty:: t ,
393
+ bounds : ty:: BuiltinBounds , store : ty:: TraitStore ) {
394
+ do check_builtin_bounds ( cx, ty, bounds) |missing| {
395
+ cx. tcx . sess . span_err ( sp,
396
+ fmt ! ( "cannot pack type `%s`, which does not fulfill \
397
+ `%s`, as a trait bounded by %s",
398
+ ty_to_str( cx. tcx, ty) , missing. user_string( cx. tcx) ,
399
+ bounds. user_string( cx. tcx) ) ) ;
400
+ }
401
+ // FIXME(#3569): Remove this check when the corresponding restriction
402
+ // is made with type contents.
403
+ if store == ty:: UniqTraitStore && !ty:: type_is_owned ( cx. tcx , ty) {
404
+ cx. tcx . sess . span_err ( sp, "uniquely-owned trait objects must be sendable" ) ;
405
+ }
406
+ }
407
+
349
408
fn is_nullary_variant ( cx : Context , ex: @expr) -> bool {
350
409
match ex. node {
351
410
expr_path( _) => {
@@ -528,19 +587,3 @@ pub fn check_cast_for_escaping_regions(
528
587
cx. tcx . region_maps . is_subregion_of ( r_sub, r_sup)
529
588
}
530
589
}
531
-
532
- /// Ensures that values placed into a ~Trait are copyable and sendable.
533
- pub fn check_kind_bounds_of_cast ( cx : Context , source: @expr, target: @expr) {
534
- let target_ty = ty:: expr_ty ( cx. tcx , target) ;
535
- match ty:: get ( target_ty) . sty {
536
- ty:: ty_trait( _, _, ty:: UniqTraitStore , _) => {
537
- let source_ty = ty:: expr_ty ( cx. tcx , source) ;
538
- if !ty:: type_is_owned ( cx. tcx , source_ty) {
539
- cx. tcx . sess . span_err (
540
- target. span ,
541
- "uniquely-owned trait objects must be sendable" ) ;
542
- }
543
- }
544
- _ => { } // Nothing to do.
545
- }
546
- }
0 commit comments