@@ -323,34 +323,27 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
323
323
self_ty : Ty < ' tcx > ,
324
324
goal_kind : ty:: ClosureKind ,
325
325
env_region : ty:: Region < ' tcx > ,
326
- ) -> Result <
327
- ( ty:: Binder < ' tcx , ( Ty < ' tcx > , Ty < ' tcx > , Ty < ' tcx > ) > , Option < ty:: Predicate < ' tcx > > ) ,
328
- NoSolution ,
329
- > {
326
+ ) -> Result < ( ty:: Binder < ' tcx , ( Ty < ' tcx > , Ty < ' tcx > , Ty < ' tcx > ) > , Vec < ty:: Predicate < ' tcx > > ) , NoSolution >
327
+ {
330
328
match * self_ty. kind ( ) {
331
329
ty:: CoroutineClosure ( def_id, args) => {
332
330
let args = args. as_coroutine_closure ( ) ;
333
331
let kind_ty = args. kind_ty ( ) ;
334
-
335
- if let Some ( closure_kind) = kind_ty. to_opt_closure_kind ( ) {
332
+ let sig = args. coroutine_closure_sig ( ) . skip_binder ( ) ;
333
+ let mut nested = vec ! [ ] ;
334
+ let coroutine_ty = if let Some ( closure_kind) = kind_ty. to_opt_closure_kind ( ) {
336
335
if !closure_kind. extends ( goal_kind) {
337
336
return Err ( NoSolution ) ;
338
337
}
339
- Ok ( (
340
- args. coroutine_closure_sig ( ) . map_bound ( |sig| {
341
- let coroutine_ty = sig. to_coroutine_given_kind_and_upvars (
342
- tcx,
343
- args. parent_args ( ) ,
344
- tcx. coroutine_for_closure ( def_id) ,
345
- goal_kind,
346
- env_region,
347
- args. tupled_upvars_ty ( ) ,
348
- args. coroutine_captures_by_ref_ty ( ) ,
349
- ) ;
350
- ( sig. tupled_inputs_ty , sig. return_ty , coroutine_ty)
351
- } ) ,
352
- None ,
353
- ) )
338
+ sig. to_coroutine_given_kind_and_upvars (
339
+ tcx,
340
+ args. parent_args ( ) ,
341
+ tcx. coroutine_for_closure ( def_id) ,
342
+ goal_kind,
343
+ env_region,
344
+ args. tupled_upvars_ty ( ) ,
345
+ args. coroutine_captures_by_ref_ty ( ) ,
346
+ )
354
347
} else {
355
348
let async_fn_kind_trait_def_id =
356
349
tcx. require_lang_item ( LangItem :: AsyncFnKindHelper , None ) ;
@@ -367,42 +360,117 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
367
360
// the goal kind <= the closure kind. As a projection `AsyncFnKindHelper::Upvars`
368
361
// will project to the right upvars for the generator, appending the inputs and
369
362
// coroutine upvars respecting the closure kind.
370
- Ok ( (
371
- args. coroutine_closure_sig ( ) . map_bound ( |sig| {
372
- let tupled_upvars_ty = Ty :: new_projection (
373
- tcx,
374
- upvars_projection_def_id,
375
- [
376
- ty:: GenericArg :: from ( kind_ty) ,
377
- Ty :: from_closure_kind ( tcx, goal_kind) . into ( ) ,
378
- env_region. into ( ) ,
379
- sig. tupled_inputs_ty . into ( ) ,
380
- args. tupled_upvars_ty ( ) . into ( ) ,
381
- args. coroutine_captures_by_ref_ty ( ) . into ( ) ,
382
- ] ,
383
- ) ;
384
- let coroutine_ty = sig. to_coroutine (
385
- tcx,
386
- args. parent_args ( ) ,
387
- Ty :: from_closure_kind ( tcx, goal_kind) ,
388
- tcx. coroutine_for_closure ( def_id) ,
389
- tupled_upvars_ty,
390
- ) ;
391
- ( sig. tupled_inputs_ty , sig. return_ty , coroutine_ty)
392
- } ) ,
393
- Some (
394
- ty:: TraitRef :: new (
395
- tcx,
396
- async_fn_kind_trait_def_id,
397
- [ kind_ty, Ty :: from_closure_kind ( tcx, goal_kind) ] ,
398
- )
399
- . to_predicate ( tcx) ,
400
- ) ,
401
- ) )
402
- }
363
+ nested. push (
364
+ ty:: TraitRef :: new (
365
+ tcx,
366
+ async_fn_kind_trait_def_id,
367
+ [ kind_ty, Ty :: from_closure_kind ( tcx, goal_kind) ] ,
368
+ )
369
+ . to_predicate ( tcx) ,
370
+ ) ;
371
+ let tupled_upvars_ty = Ty :: new_projection (
372
+ tcx,
373
+ upvars_projection_def_id,
374
+ [
375
+ ty:: GenericArg :: from ( kind_ty) ,
376
+ Ty :: from_closure_kind ( tcx, goal_kind) . into ( ) ,
377
+ env_region. into ( ) ,
378
+ sig. tupled_inputs_ty . into ( ) ,
379
+ args. tupled_upvars_ty ( ) . into ( ) ,
380
+ args. coroutine_captures_by_ref_ty ( ) . into ( ) ,
381
+ ] ,
382
+ ) ;
383
+ sig. to_coroutine (
384
+ tcx,
385
+ args. parent_args ( ) ,
386
+ Ty :: from_closure_kind ( tcx, goal_kind) ,
387
+ tcx. coroutine_for_closure ( def_id) ,
388
+ tupled_upvars_ty,
389
+ )
390
+ } ;
391
+
392
+ Ok ( (
393
+ args. coroutine_closure_sig ( ) . rebind ( (
394
+ sig. tupled_inputs_ty ,
395
+ sig. return_ty ,
396
+ coroutine_ty,
397
+ ) ) ,
398
+ nested,
399
+ ) )
403
400
}
404
401
405
- ty:: FnDef ( ..) | ty:: FnPtr ( ..) | ty:: Closure ( ..) => Err ( NoSolution ) ,
402
+ ty:: FnDef ( ..) | ty:: FnPtr ( ..) => {
403
+ let bound_sig = self_ty. fn_sig ( tcx) ;
404
+ let sig = bound_sig. skip_binder ( ) ;
405
+ let future_trait_def_id = tcx. require_lang_item ( LangItem :: Future , None ) ;
406
+ // `FnDef` and `FnPtr` only implement `AsyncFn*` when their
407
+ // return type implements `Future`.
408
+ let nested = vec ! [
409
+ bound_sig
410
+ . rebind( ty:: TraitRef :: new( tcx, future_trait_def_id, [ sig. output( ) ] ) )
411
+ . to_predicate( tcx) ,
412
+ ] ;
413
+ let future_output_def_id = tcx
414
+ . associated_items ( future_trait_def_id)
415
+ . filter_by_name_unhygienic ( sym:: Output )
416
+ . next ( )
417
+ . unwrap ( )
418
+ . def_id ;
419
+ let future_output_ty = Ty :: new_projection ( tcx, future_output_def_id, [ sig. output ( ) ] ) ;
420
+ Ok ( (
421
+ bound_sig. rebind ( ( Ty :: new_tup ( tcx, sig. inputs ( ) ) , sig. output ( ) , future_output_ty) ) ,
422
+ nested,
423
+ ) )
424
+ }
425
+ ty:: Closure ( _, args) => {
426
+ let args = args. as_closure ( ) ;
427
+ let bound_sig = args. sig ( ) ;
428
+ let sig = bound_sig. skip_binder ( ) ;
429
+ let future_trait_def_id = tcx. require_lang_item ( LangItem :: Future , None ) ;
430
+ // `Closure`s only implement `AsyncFn*` when their return type
431
+ // implements `Future`.
432
+ let mut nested = vec ! [
433
+ bound_sig
434
+ . rebind( ty:: TraitRef :: new( tcx, future_trait_def_id, [ sig. output( ) ] ) )
435
+ . to_predicate( tcx) ,
436
+ ] ;
437
+
438
+ // Additionally, we need to check that the closure kind
439
+ // is still compatible.
440
+ let kind_ty = args. kind_ty ( ) ;
441
+ if let Some ( closure_kind) = kind_ty. to_opt_closure_kind ( ) {
442
+ if !closure_kind. extends ( goal_kind) {
443
+ return Err ( NoSolution ) ;
444
+ }
445
+ } else {
446
+ let async_fn_kind_trait_def_id =
447
+ tcx. require_lang_item ( LangItem :: AsyncFnKindHelper , None ) ;
448
+ // When we don't know the closure kind (and therefore also the closure's upvars,
449
+ // which are computed at the same time), we must delay the computation of the
450
+ // generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait
451
+ // goal functions similarly to the old `ClosureKind` predicate, and ensures that
452
+ // the goal kind <= the closure kind. As a projection `AsyncFnKindHelper::Upvars`
453
+ // will project to the right upvars for the generator, appending the inputs and
454
+ // coroutine upvars respecting the closure kind.
455
+ nested. push (
456
+ ty:: TraitRef :: new (
457
+ tcx,
458
+ async_fn_kind_trait_def_id,
459
+ [ kind_ty, Ty :: from_closure_kind ( tcx, goal_kind) ] ,
460
+ )
461
+ . to_predicate ( tcx) ,
462
+ ) ;
463
+ }
464
+
465
+ let future_output_def_id = tcx
466
+ . associated_items ( future_trait_def_id)
467
+ . filter_by_name_unhygienic ( sym:: Output )
468
+ . next ( )
469
+ . unwrap ( )
470
+ . def_id ;
471
+ let future_output_ty = Ty :: new_projection ( tcx, future_output_def_id, [ sig. output ( ) ] ) ;
472
+ Ok ( ( bound_sig. rebind ( ( sig. inputs ( ) [ 0 ] , sig. output ( ) , future_output_ty) ) , nested) )
473
+ }
406
474
407
475
ty:: Bool
408
476
| ty:: Char
0 commit comments