@@ -2446,8 +2446,9 @@ fn confirm_callable_candidate<'cx, 'tcx>(
24462446fn confirm_async_closure_candidate < ' cx , ' tcx > (
24472447 selcx : & mut SelectionContext < ' cx , ' tcx > ,
24482448 obligation : & ProjectionTyObligation < ' tcx > ,
2449- mut nested : Vec < PredicateObligation < ' tcx > > ,
2449+ nested : Vec < PredicateObligation < ' tcx > > ,
24502450) -> Progress < ' tcx > {
2451+ let tcx = selcx. tcx ( ) ;
24512452 let self_ty = selcx. infcx . shallow_resolve ( obligation. predicate . self_ty ( ) ) ;
24522453 let ty:: CoroutineClosure ( def_id, args) = * self_ty. kind ( ) else {
24532454 unreachable ! (
@@ -2456,76 +2457,48 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
24562457 } ;
24572458 let args = args. as_coroutine_closure ( ) ;
24582459 let kind_ty = args. kind_ty ( ) ;
2460+ let sig = args. coroutine_closure_sig ( ) . skip_binder ( ) ;
24592461
2460- let tcx = selcx. tcx ( ) ;
24612462 let goal_kind =
24622463 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-
24752464 let env_region = match goal_kind {
24762465 ty:: ClosureKind :: Fn | ty:: ClosureKind :: FnMut => obligation. predicate . args . region_at ( 2 ) ,
24772466 ty:: ClosureKind :: FnOnce => tcx. lifetimes . re_static ,
24782467 } ;
24792468
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 (
25132477 tcx,
25142478 args. parent_args ( ) ,
2515- Ty :: from_closure_kind ( tcx, goal_kind) ,
25162479 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 ( ) ,
25262484 )
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`.
25292502 let tupled_upvars_ty = Ty :: new_projection (
25302503 tcx,
25312504 upvars_projection_def_id,
@@ -2538,37 +2511,38 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
25382511 args. coroutine_captures_by_ref_ty ( ) . into ( ) ,
25392512 ] ,
25402513 ) ;
2541- let coroutine_ty = sig. to_coroutine (
2514+ sig. to_coroutine (
25422515 tcx,
25432516 args. parent_args ( ) ,
25442517 Ty :: from_closure_kind ( tcx, goal_kind) ,
25452518 tcx. coroutine_for_closure ( def_id) ,
25462519 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 ( ) ,
25592520 )
25602521 }
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+ } ;
25692537
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)
25722546}
25732547
25742548fn confirm_async_fn_kind_helper_candidate < ' cx , ' tcx > (
0 commit comments