13
13
use super :: { check_fn, Expectation , FnCtxt } ;
14
14
15
15
use astconv:: AstConv ;
16
+ use rustc:: hir:: def_id:: DefId ;
17
+ use rustc:: infer:: LateBoundRegionConversionTime ;
16
18
use rustc:: infer:: type_variable:: TypeVariableOrigin ;
17
19
use rustc:: ty:: { self , ToPolyTraitRef , Ty } ;
18
20
use rustc:: ty:: subst:: Substs ;
21
+ use rustc:: ty:: TypeFoldable ;
19
22
use std:: cmp;
20
23
use std:: iter;
21
24
use syntax:: abi:: Abi ;
22
25
use rustc:: hir;
23
26
27
+ struct ClosureSignatures < ' tcx > {
28
+ bound_sig : ty:: PolyFnSig < ' tcx > ,
29
+ liberated_sig : ty:: FnSig < ' tcx > ,
30
+ }
31
+
24
32
impl < ' a , ' gcx , ' tcx > FnCtxt < ' a , ' gcx , ' tcx > {
25
33
pub fn check_expr_closure ( & self ,
26
34
expr : & hir:: Expr ,
@@ -56,15 +64,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
56
64
expected_sig) ;
57
65
58
66
let expr_def_id = self . tcx . hir . local_def_id ( expr. id ) ;
59
- let sig = self . ty_of_closure ( decl, expected_sig) ;
60
67
61
- debug ! ( "check_closure: ty_of_closure returns {:?}" , sig) ;
68
+ let ClosureSignatures { bound_sig, liberated_sig } =
69
+ self . sig_of_closure ( expr_def_id, decl, body, expected_sig) ;
62
70
63
- // `deduce_expectations_from_expected_type` introduces late-bound
64
- // lifetimes defined elsewhere, which we need to anonymize away.
65
- let sig = self . tcx . anonymize_late_bound_regions ( & sig) ;
71
+ debug ! ( "check_closure: ty_of_closure returns {:?}" , liberated_sig) ;
66
72
67
- debug ! ( "check_closure: anonymized sig={:?}" , sig ) ;
73
+ let interior = check_fn ( self , self . param_env , liberated_sig , decl , expr . id , body , true ) . 1 ;
68
74
69
75
// Create type variables (for now) to represent the transformed
70
76
// types of upvars. These will be unified during the upvar
@@ -75,14 +81,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
75
81
|_, _| span_bug ! ( expr. span, "closure has region param" ) ,
76
82
|_, _| self . infcx . next_ty_var ( TypeVariableOrigin :: TransformedUpvar ( expr. span ) )
77
83
) ;
78
-
79
- let fn_sig = self . liberate_late_bound_regions ( expr_def_id, & sig) ;
80
- let fn_sig = self . inh . normalize_associated_types_in ( body. value . span ,
81
- body. value . id ,
82
- self . param_env ,
83
- & fn_sig) ;
84
-
85
- let interior = check_fn ( self , self . param_env , fn_sig, decl, expr. id , body, true ) . 1 ;
84
+ let closure_type = self . tcx . mk_closure ( expr_def_id, substs) ;
86
85
87
86
if let Some ( interior) = interior {
88
87
let closure_substs = ty:: ClosureSubsts {
@@ -91,13 +90,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
91
90
return self . tcx . mk_generator ( expr_def_id, closure_substs, interior) ;
92
91
}
93
92
94
- let closure_type = self . tcx . mk_closure ( expr_def_id, substs) ;
95
-
96
93
debug ! ( "check_closure: expr.id={:?} closure_type={:?}" , expr. id, closure_type) ;
97
94
98
95
// Tuple up the arguments and insert the resulting function type into
99
96
// the `closures` table.
100
- let sig = sig . map_bound ( |sig| self . tcx . mk_fn_sig (
97
+ let sig = bound_sig . map_bound ( |sig| self . tcx . mk_fn_sig (
101
98
iter:: once ( self . tcx . intern_tup ( sig. inputs ( ) , false ) ) ,
102
99
sig. output ( ) ,
103
100
sig. variadic ,
@@ -271,71 +268,214 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
271
268
}
272
269
}
273
270
271
+ fn sig_of_closure ( & self ,
272
+ expr_def_id : DefId ,
273
+ decl : & hir:: FnDecl ,
274
+ body : & hir:: Body ,
275
+ expected_sig : Option < ty:: FnSig < ' tcx > > )
276
+ -> ClosureSignatures < ' tcx >
277
+ {
278
+ if let Some ( e) = expected_sig {
279
+ self . sig_of_closure_with_expectation ( expr_def_id, decl, body, e)
280
+ } else {
281
+ self . sig_of_closure_no_expectation ( expr_def_id, decl, body)
282
+ }
283
+ }
284
+
285
+ /// If there is no expected signature, then we will convert the
286
+ /// types that the user gave into a signature.
287
+ fn sig_of_closure_no_expectation ( & self ,
288
+ expr_def_id : DefId ,
289
+ decl : & hir:: FnDecl ,
290
+ body : & hir:: Body )
291
+ -> ClosureSignatures < ' tcx >
292
+ {
293
+ debug ! ( "sig_of_closure_no_expectation()" ) ;
294
+
295
+ let bound_sig = self . supplied_sig_of_closure ( decl) ;
296
+
297
+ self . closure_sigs ( expr_def_id, body, bound_sig)
298
+ }
299
+
274
300
/// Invoked to compute the signature of a closure expression. This
275
301
/// combines any user-provided type annotations (e.g., `|x: u32|
276
302
/// -> u32 { .. }`) with the expected signature.
277
303
///
278
- /// The arguments here are a bit odd-ball:
304
+ /// The approach is as follows:
305
+ ///
306
+ /// - Let `S` be the (higher-ranked) signature that we derive from the user's annotations.
307
+ /// - Let `E` be the (higher-ranked) signature that we derive from the expectations, if any.
308
+ /// - If we have no expectation `E`, then the signature of the closure is `S`.
309
+ /// - Otherwise, the signature of the closure is E. Moreover:
310
+ /// - Skolemize the late-bound regions in `E`, yielding `E'`.
311
+ /// - Instantiate all the late-bound regions bound in the closure within `S`
312
+ /// with fresh (existential) variables, yielding `S'`
313
+ /// - Require that `E' = S'`
314
+ /// - We could use some kind of subtyping relationship here,
315
+ /// I imagine, but equality is easier and works fine for
316
+ /// our purposes.
317
+ ///
318
+ /// The key intuition here is that the user's types must be valid
319
+ /// from "the inside" of the closure, but the expectation
320
+ /// ultimately drives the overall signature.
321
+ ///
322
+ /// # Examples
323
+ ///
324
+ /// ```
325
+ /// fn with_closure<F>(_: F)
326
+ /// where F: Fn(&u32) -> &u32 { .. }
327
+ ///
328
+ /// with_closure(|x: &u32| { ... })
329
+ /// ```
330
+ ///
331
+ /// Here:
332
+ /// - E would be `fn(&u32) -> &u32`.
333
+ /// - S would be `fn(&u32) ->
334
+ /// - E' is `&'!0 u32 -> &'!0 u32`
335
+ /// - S' is `&'?0 u32 -> ?T`
336
+ ///
337
+ /// S' can be unified with E' with `['?0 = '!0, ?T = &'!10 u32]`.
338
+ ///
339
+ /// # Arguments
279
340
///
341
+ /// - `expr_def_id`: the def-id of the closure expression
280
342
/// - `decl`: the HIR declaration of the closure
343
+ /// - `body`: the body of the closure
281
344
/// - `expected_sig`: the expected signature (if any). Note that
282
345
/// this is missing a binder: that is, there may be late-bound
283
346
/// regions with depth 1, which are bound then by the closure.
284
- fn ty_of_closure ( & self ,
285
- decl : & hir:: FnDecl ,
286
- expected_sig : Option < ty:: FnSig < ' tcx > > )
287
- -> ty:: PolyFnSig < ' tcx >
347
+ fn sig_of_closure_with_expectation ( & self ,
348
+ expr_def_id : DefId ,
349
+ decl : & hir:: FnDecl ,
350
+ body : & hir:: Body ,
351
+ expected_sig : ty:: FnSig < ' tcx > )
352
+ -> ClosureSignatures < ' tcx >
288
353
{
289
- let astconv: & AstConv = self ;
290
-
291
- debug ! ( "ty_of_closure(expected_sig={:?})" ,
292
- expected_sig) ;
354
+ debug ! ( "sig_of_closure_with_expectation(expected_sig={:?})" , expected_sig) ;
355
+
356
+ // Watch out for some surprises and just ignore the
357
+ // expectation if things don't see to match up with what we
358
+ // expect.
359
+ if expected_sig. variadic != decl. variadic {
360
+ return self . sig_of_closure_no_expectation ( expr_def_id, decl, body) ;
361
+ } else if expected_sig. inputs_and_output . len ( ) != decl. inputs . len ( ) + 1 {
362
+ // we could probably handle this case more gracefully
363
+ return self . sig_of_closure_no_expectation ( expr_def_id, decl, body) ;
364
+ }
293
365
294
- let input_tys = decl. inputs . iter ( ) . enumerate ( ) . map ( |( i, a) | {
295
- let expected_arg_ty = expected_sig. as_ref ( ) . and_then ( |e| {
296
- // no guarantee that the correct number of expected args
297
- // were supplied
298
- if i < e. inputs ( ) . len ( ) {
299
- Some ( e. inputs ( ) [ i] )
300
- } else {
301
- None
302
- }
303
- } ) ;
366
+ // Create a `PolyFnSig`. Note the oddity that late bound
367
+ // regions appearing free in `expected_sig` are now bound up
368
+ // in this binder we are creating.
369
+ assert ! ( !expected_sig. has_regions_escaping_depth( 1 ) ) ;
370
+ let bound_sig =
371
+ ty:: Binder ( self . tcx . mk_fn_sig (
372
+ expected_sig. inputs ( ) . iter ( ) . cloned ( ) ,
373
+ expected_sig. output ( ) ,
374
+ decl. variadic ,
375
+ hir:: Unsafety :: Normal ,
376
+ Abi :: RustCall ) ) ;
377
+
378
+ // `deduce_expectations_from_expected_type` introduces
379
+ // late-bound lifetimes defined elsewhere, which we now
380
+ // anonymize away, so as not to confuse the user.
381
+ let bound_sig = self . tcx . anonymize_late_bound_regions ( & bound_sig) ;
382
+
383
+ let closure_sigs = self . closure_sigs ( expr_def_id, body, bound_sig) ;
384
+
385
+ // Up till this point, we have ignored the annotations that the user
386
+ // gave. This function will check that they unify successfully.
387
+ // Along the way, it also writes out entries for types that the user
388
+ // wrote into our tables, which are then later used by the privacy
389
+ // check.
390
+ self . check_supplied_sig_against_expectation ( decl, & closure_sigs) ;
391
+
392
+ closure_sigs
393
+ }
304
394
305
- let input_ty = astconv. ty_of_arg ( a, expected_arg_ty) ;
306
- debug ! ( "ty_of_closure: i={} input_ty={:?} expected_arg_ty={:?}" ,
307
- i, input_ty, expected_arg_ty) ;
395
+ /// Enforce the user's types against the expectation. See
396
+ /// `sig_of_closure_with_expectation` for details on the overall
397
+ /// strategy.
398
+ fn check_supplied_sig_against_expectation ( & self ,
399
+ decl : & hir:: FnDecl ,
400
+ expected_sigs : & ClosureSignatures < ' tcx > )
401
+ {
402
+ // Get the signature S that the user gave.
403
+ //
404
+ // (See comment on `sig_of_closure_with_expectation` for the
405
+ // meaning of these letters.)
406
+ let supplied_sig = self . supplied_sig_of_closure ( decl) ;
407
+
408
+ debug ! ( "check_supplied_sig_against_expectation: supplied_sig={:?}" ,
409
+ supplied_sig) ;
410
+
411
+ // The liberated version of this signature should be be a subtype
412
+ // of the liberated form of the expectation.
413
+ for ( ( hir_ty, & supplied_ty) , expected_ty) in
414
+ decl. inputs . iter ( )
415
+ . zip ( * supplied_sig. inputs ( ) . skip_binder ( ) ) // binder moved to (*) below
416
+ . zip ( expected_sigs. liberated_sig . inputs ( ) ) // `liberated_sig` is E'.
417
+ {
418
+ // Instantiate (this part of..) S to S', i.e., with fresh variables.
419
+ let ( supplied_ty, _) = self . infcx . replace_late_bound_regions_with_fresh_var (
420
+ hir_ty. span ,
421
+ LateBoundRegionConversionTime :: FnCall ,
422
+ & ty:: Binder ( supplied_ty) ) ; // recreated from (*) above
423
+
424
+ // Check that E' = S'.
425
+ self . demand_eqtype ( hir_ty. span , expected_ty, supplied_ty) ;
426
+ }
308
427
309
- input_ty
310
- } ) ;
428
+ let ( supplied_output_ty, _) = self . infcx . replace_late_bound_regions_with_fresh_var (
429
+ decl. output . span ( ) ,
430
+ LateBoundRegionConversionTime :: FnCall ,
431
+ & supplied_sig. output ( ) ) ;
432
+ self . demand_eqtype ( decl. output . span ( ) ,
433
+ expected_sigs. liberated_sig . output ( ) ,
434
+ supplied_output_ty) ;
435
+ }
311
436
312
- let expected_ret_ty = expected_sig. as_ref ( ) . map ( |e| e. output ( ) ) ;
437
+ /// If there is no expected signature, then we will convert the
438
+ /// types that the user gave into a signature.
439
+ fn supplied_sig_of_closure ( & self ,
440
+ decl : & hir:: FnDecl )
441
+ -> ty:: PolyFnSig < ' tcx >
442
+ {
443
+ let astconv: & AstConv = self ;
313
444
314
- let output_ty = match decl. output {
315
- hir:: Return ( ref output) => {
316
- if let ( & hir:: TyInfer , Some ( expected_ret_ty) ) = ( & output. node , expected_ret_ty) {
317
- astconv. record_ty ( output. hir_id , expected_ret_ty, output. span ) ;
318
- expected_ret_ty
319
- } else {
320
- astconv. ast_ty_to_ty ( & output)
321
- }
322
- }
323
- hir:: DefaultReturn ( span) => {
324
- if let Some ( expected_ret_ty) = expected_ret_ty {
325
- expected_ret_ty
326
- } else {
327
- astconv. ty_infer ( span)
328
- }
329
- }
445
+ // First, convert the types that the user supplied (if any).
446
+ let supplied_arguments =
447
+ decl. inputs
448
+ . iter ( )
449
+ . map ( |a| astconv. ast_ty_to_ty ( a) ) ;
450
+ let supplied_return = match decl. output {
451
+ hir:: Return ( ref output) => astconv. ast_ty_to_ty ( & output) ,
452
+ hir:: DefaultReturn ( _) => astconv. ty_infer ( decl. output . span ( ) ) ,
330
453
} ;
331
454
332
- debug ! ( "ty_of_closure: output_ty={:?}" , output_ty) ;
333
-
334
- ty:: Binder ( self . tcx . mk_fn_sig (
335
- input_tys,
336
- output_ty,
455
+ let result = ty:: Binder ( self . tcx . mk_fn_sig (
456
+ supplied_arguments,
457
+ supplied_return,
337
458
decl. variadic ,
338
459
hir:: Unsafety :: Normal ,
339
- Abi :: RustCall ) )
460
+ Abi :: RustCall ) ) ;
461
+
462
+ debug ! ( "supplied_sig_of_closure: result={:?}" , result) ;
463
+
464
+ result
465
+ }
466
+
467
+ fn closure_sigs ( & self ,
468
+ expr_def_id : DefId ,
469
+ body : & hir:: Body ,
470
+ bound_sig : ty:: PolyFnSig < ' tcx > )
471
+ -> ClosureSignatures < ' tcx >
472
+ {
473
+ let liberated_sig = self . liberate_late_bound_regions ( expr_def_id, & bound_sig) ;
474
+ let liberated_sig = self . inh . normalize_associated_types_in ( body. value . span ,
475
+ body. value . id ,
476
+ self . param_env ,
477
+ & liberated_sig) ;
478
+ ClosureSignatures { bound_sig, liberated_sig }
340
479
}
341
480
}
481
+
0 commit comments