@@ -281,7 +281,58 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
281281 }
282282
283283 // Coroutine-closures don't implement `Fn` traits the normal way.
284- ty:: CoroutineClosure ( ..) => Err ( NoSolution ) ,
284+ // Instead, they always implement `FnOnce`, but only implement
285+ // `FnMut`/`Fn` if they capture no upvars, since those may borrow
286+ // from the closure.
287+ ty:: CoroutineClosure ( def_id, args) => {
288+ let args = args. as_coroutine_closure ( ) ;
289+ let kind_ty = args. kind_ty ( ) ;
290+ let sig = args. coroutine_closure_sig ( ) . skip_binder ( ) ;
291+
292+ let coroutine_ty = if let Some ( closure_kind) = kind_ty. to_opt_closure_kind ( ) {
293+ if !closure_kind. extends ( goal_kind) {
294+ return Err ( NoSolution ) ;
295+ }
296+
297+ // If `Fn`/`FnMut`, we only implement this goal if we
298+ // have no captures.
299+ let no_borrows = match args. tupled_upvars_ty ( ) . kind ( ) {
300+ ty:: Tuple ( tys) => tys. is_empty ( ) ,
301+ ty:: Error ( _) => false ,
302+ _ => bug ! ( "tuple_fields called on non-tuple" ) ,
303+ } ;
304+ if closure_kind != ty:: ClosureKind :: FnOnce && !no_borrows {
305+ return Err ( NoSolution ) ;
306+ }
307+
308+ coroutine_closure_to_certain_coroutine (
309+ tcx,
310+ goal_kind,
311+ // No captures by ref, so this doesn't matter.
312+ tcx. lifetimes . re_static ,
313+ def_id,
314+ args,
315+ sig,
316+ )
317+ } else {
318+ // Closure kind is not yet determined, so we return ambiguity unless
319+ // the expected kind is `FnOnce` as that is always implemented.
320+ if goal_kind != ty:: ClosureKind :: FnOnce {
321+ return Ok ( None ) ;
322+ }
323+
324+ coroutine_closure_to_ambiguous_coroutine (
325+ tcx,
326+ goal_kind, // No captures by ref, so this doesn't matter.
327+ tcx. lifetimes . re_static ,
328+ def_id,
329+ args,
330+ sig,
331+ )
332+ } ;
333+
334+ Ok ( Some ( args. coroutine_closure_sig ( ) . rebind ( ( sig. tupled_inputs_ty , coroutine_ty) ) ) )
335+ }
285336
286337 ty:: Bool
287338 | ty:: Char
@@ -313,6 +364,19 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
313364 }
314365}
315366
367+ /// Relevant types for an async callable, including its inputs, output,
368+ /// and the return type you get from awaiting the output.
369+ #[ derive( Copy , Clone , Debug , TypeVisitable , TypeFoldable ) ]
370+ pub ( in crate :: solve) struct AsyncCallableRelevantTypes < ' tcx > {
371+ pub tupled_inputs_ty : Ty < ' tcx > ,
372+ /// Type returned by calling the closure
373+ /// i.e. `f()`.
374+ pub output_coroutine_ty : Ty < ' tcx > ,
375+ /// Type returned by `await`ing the output
376+ /// i.e. `f().await`.
377+ pub coroutine_return_ty : Ty < ' tcx > ,
378+ }
379+
316380// Returns a binder of the tupled inputs types, output type, and coroutine type
317381// from a builtin coroutine-closure type. If we don't yet know the closure kind of
318382// the coroutine-closure, emit an additional trait predicate for `AsyncFnKindHelper`
@@ -323,8 +387,10 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
323387 self_ty : Ty < ' tcx > ,
324388 goal_kind : ty:: ClosureKind ,
325389 env_region : ty:: Region < ' tcx > ,
326- ) -> Result < ( ty:: Binder < ' tcx , ( Ty < ' tcx > , Ty < ' tcx > , Ty < ' tcx > ) > , Vec < ty:: Predicate < ' tcx > > ) , NoSolution >
327- {
390+ ) -> Result <
391+ ( ty:: Binder < ' tcx , AsyncCallableRelevantTypes < ' tcx > > , Vec < ty:: Predicate < ' tcx > > ) ,
392+ NoSolution ,
393+ > {
328394 match * self_ty. kind ( ) {
329395 ty:: CoroutineClosure ( def_id, args) => {
330396 let args = args. as_coroutine_closure ( ) ;
@@ -335,24 +401,11 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
335401 if !closure_kind. extends ( goal_kind) {
336402 return Err ( NoSolution ) ;
337403 }
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 ( ) ,
404+
405+ coroutine_closure_to_certain_coroutine (
406+ tcx, goal_kind, env_region, def_id, args, sig,
346407 )
347408 } else {
348- let async_fn_kind_trait_def_id =
349- tcx. require_lang_item ( LangItem :: AsyncFnKindHelper , None ) ;
350- let upvars_projection_def_id = tcx
351- . associated_items ( async_fn_kind_trait_def_id)
352- . filter_by_name_unhygienic ( sym:: Upvars )
353- . next ( )
354- . unwrap ( )
355- . def_id ;
356409 // When we don't know the closure kind (and therefore also the closure's upvars,
357410 // which are computed at the same time), we must delay the computation of the
358411 // generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait
@@ -363,38 +416,23 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
363416 nested. push (
364417 ty:: TraitRef :: new (
365418 tcx,
366- async_fn_kind_trait_def_id ,
419+ tcx . require_lang_item ( LangItem :: AsyncFnKindHelper , None ) ,
367420 [ kind_ty, Ty :: from_closure_kind ( tcx, goal_kind) ] ,
368421 )
369422 . to_predicate ( tcx) ,
370423 ) ;
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,
424+
425+ coroutine_closure_to_ambiguous_coroutine (
426+ tcx, goal_kind, env_region, def_id, args, sig,
389427 )
390428 } ;
391429
392430 Ok ( (
393- args. coroutine_closure_sig ( ) . rebind ( (
394- sig. tupled_inputs_ty ,
395- sig . return_ty ,
396- coroutine_ty ,
397- ) ) ,
431+ args. coroutine_closure_sig ( ) . rebind ( AsyncCallableRelevantTypes {
432+ tupled_inputs_ty : sig. tupled_inputs_ty ,
433+ output_coroutine_ty : coroutine_ty ,
434+ coroutine_return_ty : sig . return_ty ,
435+ } ) ,
398436 nested,
399437 ) )
400438 }
@@ -418,7 +456,11 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
418456 . def_id ;
419457 let future_output_ty = Ty :: new_projection ( tcx, future_output_def_id, [ sig. output ( ) ] ) ;
420458 Ok ( (
421- bound_sig. rebind ( ( Ty :: new_tup ( tcx, sig. inputs ( ) ) , sig. output ( ) , future_output_ty) ) ,
459+ bound_sig. rebind ( AsyncCallableRelevantTypes {
460+ tupled_inputs_ty : Ty :: new_tup ( tcx, sig. inputs ( ) ) ,
461+ output_coroutine_ty : sig. output ( ) ,
462+ coroutine_return_ty : future_output_ty,
463+ } ) ,
422464 nested,
423465 ) )
424466 }
@@ -469,7 +511,14 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
469511 . unwrap ( )
470512 . def_id ;
471513 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) )
514+ Ok ( (
515+ bound_sig. rebind ( AsyncCallableRelevantTypes {
516+ tupled_inputs_ty : sig. inputs ( ) [ 0 ] ,
517+ output_coroutine_ty : sig. output ( ) ,
518+ coroutine_return_ty : future_output_ty,
519+ } ) ,
520+ nested,
521+ ) )
473522 }
474523
475524 ty:: Bool
@@ -502,6 +551,68 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
502551 }
503552}
504553
554+ /// Given a coroutine-closure, project to its returned coroutine when we are *certain*
555+ /// that the closure's kind is compatible with the goal.
556+ fn coroutine_closure_to_certain_coroutine < ' tcx > (
557+ tcx : TyCtxt < ' tcx > ,
558+ goal_kind : ty:: ClosureKind ,
559+ goal_region : ty:: Region < ' tcx > ,
560+ def_id : DefId ,
561+ args : ty:: CoroutineClosureArgs < ' tcx > ,
562+ sig : ty:: CoroutineClosureSignature < ' tcx > ,
563+ ) -> Ty < ' tcx > {
564+ sig. to_coroutine_given_kind_and_upvars (
565+ tcx,
566+ args. parent_args ( ) ,
567+ tcx. coroutine_for_closure ( def_id) ,
568+ goal_kind,
569+ goal_region,
570+ args. tupled_upvars_ty ( ) ,
571+ args. coroutine_captures_by_ref_ty ( ) ,
572+ )
573+ }
574+
575+ /// Given a coroutine-closure, project to its returned coroutine when we are *not certain*
576+ /// that the closure's kind is compatible with the goal, and therefore also don't know
577+ /// yet what the closure's upvars are.
578+ ///
579+ /// Note that we do not also push a `AsyncFnKindHelper` goal here.
580+ fn coroutine_closure_to_ambiguous_coroutine < ' tcx > (
581+ tcx : TyCtxt < ' tcx > ,
582+ goal_kind : ty:: ClosureKind ,
583+ goal_region : ty:: Region < ' tcx > ,
584+ def_id : DefId ,
585+ args : ty:: CoroutineClosureArgs < ' tcx > ,
586+ sig : ty:: CoroutineClosureSignature < ' tcx > ,
587+ ) -> Ty < ' tcx > {
588+ let async_fn_kind_trait_def_id = tcx. require_lang_item ( LangItem :: AsyncFnKindHelper , None ) ;
589+ let upvars_projection_def_id = tcx
590+ . associated_items ( async_fn_kind_trait_def_id)
591+ . filter_by_name_unhygienic ( sym:: Upvars )
592+ . next ( )
593+ . unwrap ( )
594+ . def_id ;
595+ let tupled_upvars_ty = Ty :: new_projection (
596+ tcx,
597+ upvars_projection_def_id,
598+ [
599+ ty:: GenericArg :: from ( args. kind_ty ( ) ) ,
600+ Ty :: from_closure_kind ( tcx, goal_kind) . into ( ) ,
601+ goal_region. into ( ) ,
602+ sig. tupled_inputs_ty . into ( ) ,
603+ args. tupled_upvars_ty ( ) . into ( ) ,
604+ args. coroutine_captures_by_ref_ty ( ) . into ( ) ,
605+ ] ,
606+ ) ;
607+ sig. to_coroutine (
608+ tcx,
609+ args. parent_args ( ) ,
610+ Ty :: from_closure_kind ( tcx, goal_kind) ,
611+ tcx. coroutine_for_closure ( def_id) ,
612+ tupled_upvars_ty,
613+ )
614+ }
615+
505616/// Assemble a list of predicates that would be present on a theoretical
506617/// user impl for an object type. These predicates must be checked any time
507618/// we assemble a built-in object candidate for an object type, since they
0 commit comments