@@ -323,34 +323,27 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
323323 self_ty : Ty < ' tcx > ,
324324 goal_kind : ty:: ClosureKind ,
325325 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+ {
330328 match * self_ty. kind ( ) {
331329 ty:: CoroutineClosure ( def_id, args) => {
332330 let args = args. as_coroutine_closure ( ) ;
333331 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 ( ) {
336335 if !closure_kind. extends ( goal_kind) {
337336 return Err ( NoSolution ) ;
338337 }
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+ )
354347 } else {
355348 let async_fn_kind_trait_def_id =
356349 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
367360 // the goal kind <= the closure kind. As a projection `AsyncFnKindHelper::Upvars`
368361 // will project to the right upvars for the generator, appending the inputs and
369362 // 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+ ) )
403400 }
404401
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+ }
406474
407475 ty:: Bool
408476 | ty:: Char
0 commit comments