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