@@ -2446,8 +2446,9 @@ fn confirm_callable_candidate<'cx, 'tcx>(
2446
2446
fn confirm_async_closure_candidate < ' cx , ' tcx > (
2447
2447
selcx : & mut SelectionContext < ' cx , ' tcx > ,
2448
2448
obligation : & ProjectionTyObligation < ' tcx > ,
2449
- mut nested : Vec < PredicateObligation < ' tcx > > ,
2449
+ nested : Vec < PredicateObligation < ' tcx > > ,
2450
2450
) -> Progress < ' tcx > {
2451
+ let tcx = selcx. tcx ( ) ;
2451
2452
let self_ty = selcx. infcx . shallow_resolve ( obligation. predicate . self_ty ( ) ) ;
2452
2453
let ty:: CoroutineClosure ( def_id, args) = * self_ty. kind ( ) else {
2453
2454
unreachable ! (
@@ -2456,76 +2457,48 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
2456
2457
} ;
2457
2458
let args = args. as_coroutine_closure ( ) ;
2458
2459
let kind_ty = args. kind_ty ( ) ;
2460
+ let sig = args. coroutine_closure_sig ( ) . skip_binder ( ) ;
2459
2461
2460
- let tcx = selcx. tcx ( ) ;
2461
2462
let goal_kind =
2462
2463
tcx. async_fn_trait_kind_from_def_id ( obligation. predicate . trait_def_id ( tcx) ) . unwrap ( ) ;
2463
-
2464
- let async_fn_kind_helper_trait_def_id =
2465
- tcx. require_lang_item ( LangItem :: AsyncFnKindHelper , None ) ;
2466
- nested. push ( obligation. with (
2467
- tcx,
2468
- ty:: TraitRef :: new (
2469
- tcx,
2470
- async_fn_kind_helper_trait_def_id,
2471
- [ kind_ty, Ty :: from_closure_kind ( tcx, goal_kind) ] ,
2472
- ) ,
2473
- ) ) ;
2474
-
2475
2464
let env_region = match goal_kind {
2476
2465
ty:: ClosureKind :: Fn | ty:: ClosureKind :: FnMut => obligation. predicate . args . region_at ( 2 ) ,
2477
2466
ty:: ClosureKind :: FnOnce => tcx. lifetimes . re_static ,
2478
2467
} ;
2479
2468
2480
- let upvars_projection_def_id = tcx
2481
- . associated_items ( async_fn_kind_helper_trait_def_id)
2482
- . filter_by_name_unhygienic ( sym:: Upvars )
2483
- . next ( )
2484
- . unwrap ( )
2485
- . def_id ;
2486
-
2487
- // FIXME(async_closures): Confirmation is kind of a mess here. Ideally,
2488
- // we'd short-circuit when we know that the goal_kind >= closure_kind, and not
2489
- // register a nested predicate or create a new projection ty here. But I'm too
2490
- // lazy to make this more efficient atm, and we can always tweak it later,
2491
- // since all this does is make the solver do more work.
2492
- //
2493
- // The code duplication due to the different length args is kind of weird, too.
2494
- //
2495
- // See the logic in `structural_traits` in the new solver to understand a bit
2496
- // more clearly how this *should* look.
2497
- let poly_cache_entry = args. coroutine_closure_sig ( ) . map_bound ( |sig| {
2498
- let ( projection_ty, term) = match tcx. item_name ( obligation. predicate . def_id ) {
2499
- sym:: CallOnceFuture => {
2500
- let tupled_upvars_ty = Ty :: new_projection (
2501
- tcx,
2502
- upvars_projection_def_id,
2503
- [
2504
- ty:: GenericArg :: from ( kind_ty) ,
2505
- Ty :: from_closure_kind ( tcx, goal_kind) . into ( ) ,
2506
- env_region. into ( ) ,
2507
- sig. tupled_inputs_ty . into ( ) ,
2508
- args. tupled_upvars_ty ( ) . into ( ) ,
2509
- args. coroutine_captures_by_ref_ty ( ) . into ( ) ,
2510
- ] ,
2511
- ) ;
2512
- let coroutine_ty = sig. to_coroutine (
2469
+ let item_name = tcx. item_name ( obligation. predicate . def_id ) ;
2470
+ let term = match item_name {
2471
+ sym:: CallOnceFuture | sym:: CallMutFuture | sym:: CallFuture => {
2472
+ if let Some ( closure_kind) = kind_ty. to_opt_closure_kind ( ) {
2473
+ if !closure_kind. extends ( goal_kind) {
2474
+ bug ! ( "we should not be confirming if the closure kind is not met" ) ;
2475
+ }
2476
+ sig. to_coroutine_given_kind_and_upvars (
2513
2477
tcx,
2514
2478
args. parent_args ( ) ,
2515
- Ty :: from_closure_kind ( tcx, goal_kind) ,
2516
2479
tcx. coroutine_for_closure ( def_id) ,
2517
- tupled_upvars_ty,
2518
- ) ;
2519
- (
2520
- ty:: AliasTy :: new (
2521
- tcx,
2522
- obligation. predicate . def_id ,
2523
- [ self_ty, sig. tupled_inputs_ty ] ,
2524
- ) ,
2525
- coroutine_ty. into ( ) ,
2480
+ goal_kind,
2481
+ env_region,
2482
+ args. tupled_upvars_ty ( ) ,
2483
+ args. coroutine_captures_by_ref_ty ( ) ,
2526
2484
)
2527
- }
2528
- sym:: CallMutFuture | sym:: CallFuture => {
2485
+ } else {
2486
+ let async_fn_kind_trait_def_id =
2487
+ tcx. require_lang_item ( LangItem :: AsyncFnKindHelper , None ) ;
2488
+ let upvars_projection_def_id = tcx
2489
+ . associated_items ( async_fn_kind_trait_def_id)
2490
+ . filter_by_name_unhygienic ( sym:: Upvars )
2491
+ . next ( )
2492
+ . unwrap ( )
2493
+ . def_id ;
2494
+ // When we don't know the closure kind (and therefore also the closure's upvars,
2495
+ // which are computed at the same time), we must delay the computation of the
2496
+ // generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait
2497
+ // goal functions similarly to the old `ClosureKind` predicate, and ensures that
2498
+ // the goal kind <= the closure kind. As a projection `AsyncFnKindHelper::Upvars`
2499
+ // will project to the right upvars for the generator, appending the inputs and
2500
+ // coroutine upvars respecting the closure kind.
2501
+ // N.B. No need to register a `AsyncFnKindHelper` goal here, it's already in `nested`.
2529
2502
let tupled_upvars_ty = Ty :: new_projection (
2530
2503
tcx,
2531
2504
upvars_projection_def_id,
@@ -2538,37 +2511,38 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
2538
2511
args. coroutine_captures_by_ref_ty ( ) . into ( ) ,
2539
2512
] ,
2540
2513
) ;
2541
- let coroutine_ty = sig. to_coroutine (
2514
+ sig. to_coroutine (
2542
2515
tcx,
2543
2516
args. parent_args ( ) ,
2544
2517
Ty :: from_closure_kind ( tcx, goal_kind) ,
2545
2518
tcx. coroutine_for_closure ( def_id) ,
2546
2519
tupled_upvars_ty,
2547
- ) ;
2548
- (
2549
- ty:: AliasTy :: new (
2550
- tcx,
2551
- obligation. predicate . def_id ,
2552
- [
2553
- ty:: GenericArg :: from ( self_ty) ,
2554
- sig. tupled_inputs_ty . into ( ) ,
2555
- env_region. into ( ) ,
2556
- ] ,
2557
- ) ,
2558
- coroutine_ty. into ( ) ,
2559
2520
)
2560
2521
}
2561
- sym:: Output => (
2562
- ty:: AliasTy :: new ( tcx, obligation. predicate . def_id , [ self_ty, sig. tupled_inputs_ty ] ) ,
2563
- sig. return_ty . into ( ) ,
2564
- ) ,
2565
- name => bug ! ( "no such associated type: {name}" ) ,
2566
- } ;
2567
- ty:: ProjectionPredicate { projection_ty, term }
2568
- } ) ;
2522
+ }
2523
+ sym:: Output => sig. return_ty ,
2524
+ name => bug ! ( "no such associated type: {name}" ) ,
2525
+ } ;
2526
+ let projection_ty = match item_name {
2527
+ sym:: CallOnceFuture | sym:: Output => {
2528
+ ty:: AliasTy :: new ( tcx, obligation. predicate . def_id , [ self_ty, sig. tupled_inputs_ty ] )
2529
+ }
2530
+ sym:: CallMutFuture | sym:: CallFuture => ty:: AliasTy :: new (
2531
+ tcx,
2532
+ obligation. predicate . def_id ,
2533
+ [ ty:: GenericArg :: from ( self_ty) , sig. tupled_inputs_ty . into ( ) , env_region. into ( ) ] ,
2534
+ ) ,
2535
+ name => bug ! ( "no such associated type: {name}" ) ,
2536
+ } ;
2569
2537
2570
- confirm_param_env_candidate ( selcx, obligation, poly_cache_entry, true )
2571
- . with_addl_obligations ( nested)
2538
+ confirm_param_env_candidate (
2539
+ selcx,
2540
+ obligation,
2541
+ args. coroutine_closure_sig ( )
2542
+ . rebind ( ty:: ProjectionPredicate { projection_ty, term : term. into ( ) } ) ,
2543
+ true ,
2544
+ )
2545
+ . with_addl_obligations ( nested)
2572
2546
}
2573
2547
2574
2548
fn confirm_async_fn_kind_helper_candidate < ' cx , ' tcx > (
0 commit comments