@@ -453,25 +453,116 @@ class TupleInitializationResultPlan final : public ResultPlan {
453
453
454
454
class ForeignAsyncInitializationPlan final : public ResultPlan {
455
455
SILLocation loc;
456
+ CalleeTypeInfo calleeTypeInfo;
457
+ SILType opaqueResumeType;
458
+ SILValue resumeBuf;
459
+ SILValue continuation;
460
+
456
461
public:
457
- ForeignAsyncInitializationPlan (SILLocation loc) : loc(loc) {}
462
+ ForeignAsyncInitializationPlan (SILGenFunction &SGF, SILLocation loc,
463
+ const CalleeTypeInfo &calleeTypeInfo)
464
+ : loc(loc), calleeTypeInfo(calleeTypeInfo)
465
+ {
466
+ // Allocate space to receive the resume value when the continuation is
467
+ // resumed.
468
+ opaqueResumeType = SGF.getLoweredType (AbstractionPattern::getOpaque (),
469
+ calleeTypeInfo.substResultType );
470
+ resumeBuf = SGF.emitTemporaryAllocation (loc, opaqueResumeType);
471
+ }
458
472
459
473
void
460
474
gatherIndirectResultAddrs (SILGenFunction &SGF, SILLocation loc,
461
475
SmallVectorImpl<SILValue> &outList) const override {
462
- // TODO: Move values from the continuation result buffer to the individual
463
- // out argument buffers, unless we were able to emit the resume buffer
464
- // in-place.
476
+ // A foreign async function shouldn't have any indirect results.
477
+ }
478
+
479
+ ManagedValue
480
+ emitForeignAsyncCompletionHandler (SILGenFunction &SGF, SILLocation loc)
481
+ override {
482
+ // Get the current continuation for the task.
483
+ auto continuationDecl = calleeTypeInfo.foreign .async ->completionHandlerErrorParamIndex ()
484
+ ? SGF.getASTContext ().getUnsafeThrowingContinuationDecl ()
485
+ : SGF.getASTContext ().getUnsafeContinuationDecl ();
486
+
487
+ auto continuationTy = BoundGenericType::get (continuationDecl, Type (),
488
+ calleeTypeInfo.substResultType )
489
+ ->getCanonicalType ();
490
+
491
+
492
+ continuation = SGF.B .createGetAsyncContinuationAddr (loc, resumeBuf,
493
+ SILType::getPrimitiveObjectType (continuationTy));
494
+
495
+ // Stash it in a buffer for a block object.
496
+ auto blockStorageTy = SILType::getPrimitiveAddressType (SILBlockStorageType::get (continuationTy));
497
+ auto blockStorage = SGF.emitTemporaryAllocation (loc, blockStorageTy);
498
+ auto continuationAddr = SGF.B .createProjectBlockStorage (loc, blockStorage);
499
+ SGF.B .createStore (loc, continuation, continuationAddr,
500
+ StoreOwnershipQualifier::Trivial);
501
+
502
+ // Get the block invocation function for the given completion block type.
503
+ auto completionHandlerIndex = calleeTypeInfo.foreign .async
504
+ ->completionHandlerParamIndex ();
505
+ auto implTy = cast<SILFunctionType>(calleeTypeInfo.substFnType
506
+ ->getParameters ()[completionHandlerIndex]
507
+ .getInterfaceType ());
508
+ SILFunction *impl = SGF.SGM
509
+ .getOrCreateForeignAsyncCompletionHandlerImplFunction (implTy,
510
+ continuationTy,
511
+ *calleeTypeInfo.foreign .async );
512
+ auto implRef = SGF.B .createFunctionRef (loc, impl);
513
+
514
+ // Initialize the block object for the completion handler.
515
+ auto block = SGF.B .createInitBlockStorageHeader (loc, blockStorage, implRef,
516
+ SILType::getPrimitiveObjectType (implTy), {});
517
+ // We don't need to manage the block because it's still on the stack. We
518
+ // know we won't escape it locally so the callee can be responsible for
519
+ // _Block_copy-ing it.
520
+ return ManagedValue::forUnmanaged (block);
465
521
}
466
522
467
523
RValue finish (SILGenFunction &SGF, SILLocation loc, CanType substType,
468
524
ArrayRef<ManagedValue> &directResults) override {
469
525
// There should be no direct results from the call.
470
526
assert (directResults.empty ());
471
527
472
- // TODO: Get the actual result values from the awaited continuation.
473
- // For now, produce an undef RValue.
474
- return SGF.emitUndefRValue (loc, substType);
528
+ // Await the continuation we handed off to the completion handler.
529
+ SILBasicBlock *resumeBlock = SGF.createBasicBlock ();
530
+ SILBasicBlock *errorBlock = nullptr ;
531
+ auto errorParamIndex = calleeTypeInfo.foreign .async ->completionHandlerErrorParamIndex ();
532
+ if (errorParamIndex) {
533
+ errorBlock = SGF.createBasicBlock (FunctionSection::Postmatter);
534
+ }
535
+
536
+ SGF.B .createAwaitAsyncContinuation (loc, continuation, resumeBlock, errorBlock);
537
+
538
+ // Propagate an error if we have one.
539
+ if (errorBlock) {
540
+ SGF.B .emitBlock (errorBlock);
541
+
542
+ Scope errorScope (SGF, loc);
543
+
544
+ auto errorTy = SGF.getASTContext ().getErrorDecl ()->getDeclaredType ()
545
+ ->getCanonicalType ();
546
+ auto errorVal
547
+ = SGF.B .createOwnedPhiArgument (SILType::getPrimitiveObjectType (errorTy));
548
+
549
+ SGF.emitThrow (loc, errorVal, true );
550
+ }
551
+
552
+ SGF.B .emitBlock (resumeBlock);
553
+
554
+ // The incoming value is the maximally-abstracted result type of the
555
+ // continuation. Move it out of the resume buffer and reabstract it if
556
+ // necessary.
557
+ auto resumeResult = SGF.emitLoad (loc, resumeBuf,
558
+ calleeTypeInfo.origResultType
559
+ ? *calleeTypeInfo.origResultType
560
+ : AbstractionPattern (calleeTypeInfo.substResultType ),
561
+ calleeTypeInfo.substResultType ,
562
+ SGF.getTypeLowering (calleeTypeInfo.substResultType ),
563
+ SGFContext (), IsTake);
564
+
565
+ return RValue (SGF, loc, calleeTypeInfo.substResultType , resumeResult);
475
566
}
476
567
};
477
568
@@ -572,8 +663,7 @@ ResultPlanPtr ResultPlanBuilder::buildTopLevelResult(Initialization *init,
572
663
// Create a result plan that gets the result schema from the completion
573
664
// handler callback's arguments.
574
665
// completion handler.
575
- return ResultPlanPtr (new ForeignAsyncInitializationPlan (loc));
576
-
666
+ return ResultPlanPtr (new ForeignAsyncInitializationPlan (SGF, loc, calleeTypeInfo));
577
667
} else if (auto foreignError = calleeTypeInfo.foreign .error ) {
578
668
// Handle the foreign error first.
579
669
//
0 commit comments