@@ -281,7 +281,58 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
281
281
}
282
282
283
283
// 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
+ }
285
336
286
337
ty:: Bool
287
338
| ty:: Char
@@ -313,6 +364,19 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
313
364
}
314
365
}
315
366
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
+
316
380
// Returns a binder of the tupled inputs types, output type, and coroutine type
317
381
// from a builtin coroutine-closure type. If we don't yet know the closure kind of
318
382
// 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
323
387
self_ty : Ty < ' tcx > ,
324
388
goal_kind : ty:: ClosureKind ,
325
389
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
+ > {
328
394
match * self_ty. kind ( ) {
329
395
ty:: CoroutineClosure ( def_id, args) => {
330
396
let args = args. as_coroutine_closure ( ) ;
@@ -335,24 +401,11 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
335
401
if !closure_kind. extends ( goal_kind) {
336
402
return Err ( NoSolution ) ;
337
403
}
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,
346
407
)
347
408
} 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 ;
356
409
// When we don't know the closure kind (and therefore also the closure's upvars,
357
410
// which are computed at the same time), we must delay the computation of the
358
411
// 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
363
416
nested. push (
364
417
ty:: TraitRef :: new (
365
418
tcx,
366
- async_fn_kind_trait_def_id ,
419
+ tcx . require_lang_item ( LangItem :: AsyncFnKindHelper , None ) ,
367
420
[ kind_ty, Ty :: from_closure_kind ( tcx, goal_kind) ] ,
368
421
)
369
422
. to_predicate ( tcx) ,
370
423
) ;
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,
389
427
)
390
428
} ;
391
429
392
430
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
+ } ) ,
398
436
nested,
399
437
) )
400
438
}
@@ -418,7 +456,11 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
418
456
. def_id ;
419
457
let future_output_ty = Ty :: new_projection ( tcx, future_output_def_id, [ sig. output ( ) ] ) ;
420
458
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
+ } ) ,
422
464
nested,
423
465
) )
424
466
}
@@ -469,7 +511,14 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
469
511
. unwrap ( )
470
512
. def_id ;
471
513
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
+ ) )
473
522
}
474
523
475
524
ty:: Bool
@@ -502,6 +551,68 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
502
551
}
503
552
}
504
553
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
+
505
616
/// Assemble a list of predicates that would be present on a theoretical
506
617
/// user impl for an object type. These predicates must be checked any time
507
618
/// we assemble a built-in object candidate for an object type, since they
0 commit comments