Skip to content

Commit 8d59fd0

Browse files
Merge pull request #38861 from nate-chandler/cherrypick/rdar80704984/release/5.5
[5.5] [SILGen] Handle foreign funcs with error and async conventions.
2 parents 20a4c14 + 5c06dac commit 8d59fd0

File tree

15 files changed

+549
-124
lines changed

15 files changed

+549
-124
lines changed

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1689,11 +1689,6 @@ class DestructureInputs {
16891689
}
16901690

16911691
bool maybeAddForeignErrorParameter() {
1692-
// A foreign async convention absorbs any error parameter, making it into
1693-
// an argument to the callback.
1694-
if (Foreign.Async)
1695-
return false;
1696-
16971692
if (!Foreign.Error ||
16981693
NextOrigParamIndex != Foreign.Error->getErrorParameterIndex())
16991694
return false;
@@ -1764,12 +1759,12 @@ void updateResultTypeForForeignInfo(
17641759
if (!foreignInfo.Async && !foreignInfo.Error) {
17651760
return;
17661761
}
1767-
1768-
// A foreign async convention means our lowered return type is Void, since
1769-
// the imported semantic return and/or error type map to the completion
1770-
// callback's argument(s).
1771-
auto &C = substFormalResultType->getASTContext();
1772-
if (auto async = foreignInfo.Async) {
1762+
1763+
// A foreign async convention without an error convention means our lowered
1764+
// return type is Void, since the imported semantic return map to the
1765+
// completion callback's argument(s).
1766+
if (!foreignInfo.Error) {
1767+
auto &C = substFormalResultType->getASTContext();
17731768
substFormalResultType = TupleType::getEmpty(C);
17741769
origResultType = AbstractionPattern(genericSig, substFormalResultType);
17751770
return;
@@ -1781,7 +1776,7 @@ void updateResultTypeForForeignInfo(
17811776
// These conventions replace the result type.
17821777
case ForeignErrorConvention::ZeroResult:
17831778
case ForeignErrorConvention::NonZeroResult:
1784-
assert(substFormalResultType->isVoid());
1779+
assert(substFormalResultType->isVoid() || foreignInfo.Async);
17851780
substFormalResultType = convention.getResultType();
17861781
origResultType = AbstractionPattern(genericSig, substFormalResultType);
17871782
return;

lib/SILGen/ResultPlan.cpp

Lines changed: 138 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ class InPlaceInitializationResultPlan final : public ResultPlan {
3737
InPlaceInitializationResultPlan(Initialization *init) : init(init) {}
3838

3939
RValue finish(SILGenFunction &SGF, SILLocation loc, CanType substType,
40-
ArrayRef<ManagedValue> &directResults) override {
40+
ArrayRef<ManagedValue> &directResults,
41+
SILValue bridgedForeignError) override {
4142
init->finishInitialization(SGF);
4243
return RValue::forInContext();
4344
}
@@ -169,7 +170,8 @@ class IndirectOpenedSelfResultPlan final : public ResultPlan {
169170
}
170171

171172
RValue finish(SILGenFunction &SGF, SILLocation loc, CanType substType,
172-
ArrayRef<ManagedValue> &directResults) override {
173+
ArrayRef<ManagedValue> &directResults,
174+
SILValue bridgedForeignError) override {
173175
assert(resultBox && "never emitted temporary?!");
174176

175177
// Lower the unabstracted result type.
@@ -209,7 +211,8 @@ class ScalarResultPlan final : public ResultPlan {
209211
rep(rep) {}
210212

211213
RValue finish(SILGenFunction &SGF, SILLocation loc, CanType substType,
212-
ArrayRef<ManagedValue> &directResults) override {
214+
ArrayRef<ManagedValue> &directResults,
215+
SILValue bridgedForeignError) override {
213216
// Lower the unabstracted result type.
214217
auto &substTL = SGF.getTypeLowering(substType);
215218

@@ -309,8 +312,10 @@ class InitValueFromTemporaryResultPlan final : public ResultPlan {
309312
temporary(std::move(temporary)) {}
310313

311314
RValue finish(SILGenFunction &SGF, SILLocation loc, CanType substType,
312-
ArrayRef<ManagedValue> &directResults) override {
313-
RValue subResult = subPlan->finish(SGF, loc, substType, directResults);
315+
ArrayRef<ManagedValue> &directResults,
316+
SILValue bridgedForeignError) override {
317+
RValue subResult = subPlan->finish(SGF, loc, substType, directResults,
318+
bridgedForeignError);
314319
assert(subResult.isInContext() && "sub-plan didn't emit into context?");
315320
(void)subResult;
316321

@@ -339,8 +344,10 @@ class InitValueFromRValueResultPlan final : public ResultPlan {
339344
: init(init), subPlan(std::move(subPlan)) {}
340345

341346
RValue finish(SILGenFunction &SGF, SILLocation loc, CanType substType,
342-
ArrayRef<ManagedValue> &directResults) override {
343-
RValue subResult = subPlan->finish(SGF, loc, substType, directResults);
347+
ArrayRef<ManagedValue> &directResults,
348+
SILValue bridgedForeignError) override {
349+
RValue subResult = subPlan->finish(SGF, loc, substType, directResults,
350+
bridgedForeignError);
344351
ManagedValue value = std::move(subResult).getAsSingleValue(SGF, loc);
345352

346353
init->copyOrInitValueInto(SGF, loc, value, /*init*/ true);
@@ -374,15 +381,17 @@ class TupleRValueResultPlan final : public ResultPlan {
374381
}
375382

376383
RValue finish(SILGenFunction &SGF, SILLocation loc, CanType substType,
377-
ArrayRef<ManagedValue> &directResults) override {
384+
ArrayRef<ManagedValue> &directResults,
385+
SILValue bridgedForeignError) override {
378386
RValue tupleRV(substType);
379387

380388
// Finish all the component tuples.
381389
auto substTupleType = cast<TupleType>(substType);
382390
assert(substTupleType.getElementTypes().size() == eltPlans.size());
383391
for (auto i : indices(substTupleType.getElementTypes())) {
384-
RValue eltRV = eltPlans[i]->finish(
385-
SGF, loc, substTupleType.getElementType(i), directResults);
392+
RValue eltRV =
393+
eltPlans[i]->finish(SGF, loc, substTupleType.getElementType(i),
394+
directResults, bridgedForeignError);
386395
tupleRV.addElement(std::move(eltRV));
387396
}
388397

@@ -428,12 +437,14 @@ class TupleInitializationResultPlan final : public ResultPlan {
428437
}
429438

430439
RValue finish(SILGenFunction &SGF, SILLocation loc, CanType substType,
431-
ArrayRef<ManagedValue> &directResults) override {
440+
ArrayRef<ManagedValue> &directResults,
441+
SILValue bridgedForeignError) override {
432442
auto substTupleType = cast<TupleType>(substType);
433443
assert(substTupleType.getElementTypes().size() == eltPlans.size());
434444
for (auto i : indices(substTupleType.getElementTypes())) {
435445
auto eltType = substTupleType.getElementType(i);
436-
RValue eltRV = eltPlans[i]->finish(SGF, loc, eltType, directResults);
446+
RValue eltRV = eltPlans[i]->finish(SGF, loc, eltType, directResults,
447+
bridgedForeignError);
437448
assert(eltRV.isInContext());
438449
(void)eltRV;
439450
}
@@ -482,9 +493,11 @@ class ForeignAsyncInitializationPlan final : public ResultPlan {
482493
AbstractionPattern origFormalType,
483494
SILLocation loc) override {
484495
// Get the current continuation for the task.
485-
bool throws = calleeTypeInfo.foreign.async
486-
->completionHandlerErrorParamIndex().hasValue();
487-
496+
bool throws =
497+
calleeTypeInfo.foreign.async->completionHandlerErrorParamIndex()
498+
.hasValue() ||
499+
calleeTypeInfo.foreign.error.hasValue();
500+
488501
continuation = SGF.B.createGetAsyncContinuationAddr(loc, resumeBuf,
489502
calleeTypeInfo.substResultType, throws);
490503

@@ -534,7 +547,8 @@ class ForeignAsyncInitializationPlan final : public ResultPlan {
534547
cast<SILFunctionType>(
535548
impFnTy->mapTypeOutOfContext()->getCanonicalType(sig)),
536549
continuationTy->mapTypeOutOfContext()->getCanonicalType(sig),
537-
origFormalType, sig, *calleeTypeInfo.foreign.async);
550+
origFormalType, sig, *calleeTypeInfo.foreign.async,
551+
calleeTypeInfo.foreign.error);
538552
auto impRef = SGF.B.createFunctionRef(loc, impl);
539553

540554
// Initialize the block object for the completion handler.
@@ -554,18 +568,95 @@ class ForeignAsyncInitializationPlan final : public ResultPlan {
554568
}
555569

556570
RValue finish(SILGenFunction &SGF, SILLocation loc, CanType substType,
557-
ArrayRef<ManagedValue> &directResults) override {
571+
ArrayRef<ManagedValue> &directResults,
572+
SILValue bridgedForeignError) override {
558573
// There should be no direct results from the call.
559574
assert(directResults.empty());
560575

561576
// Await the continuation we handed off to the completion handler.
562577
SILBasicBlock *resumeBlock = SGF.createBasicBlock();
563578
SILBasicBlock *errorBlock = nullptr;
564-
auto errorParamIndex = calleeTypeInfo.foreign.async->completionHandlerErrorParamIndex();
565-
if (errorParamIndex) {
579+
bool throws =
580+
calleeTypeInfo.foreign.async->completionHandlerErrorParamIndex()
581+
.hasValue() ||
582+
calleeTypeInfo.foreign.error.hasValue();
583+
if (throws) {
566584
errorBlock = SGF.createBasicBlock(FunctionSection::Postmatter);
567585
}
568-
586+
587+
auto *awaitBB = SGF.B.getInsertionBB();
588+
if (bridgedForeignError) {
589+
// Avoid a critical edge from the block which branches to the await and
590+
// foreign error blocks to the await block (to which the error block will
591+
// be made to branch in a moment) by introducing a trampoline which will
592+
// branch to the await block.
593+
awaitBB = SGF.createBasicBlock();
594+
SGF.B.createBranch(loc, awaitBB);
595+
596+
// Finish emitting the foreign error block:
597+
// (1) fulfill the unsafe continuation with the foreign error
598+
// (2) branch to the await block
599+
{
600+
// First, fulfill the unsafe continuation with the foreign error.
601+
// Currently, that block's code looks something like
602+
// %foreignError = ... : $*Optional<NSError>
603+
// %converter = function_ref _convertNSErrorToError(_:)
604+
// %error = apply %converter(%foreignError)
605+
// [... insert here ...]
606+
// destroy_value %error
607+
// destroy_value %foreignError
608+
// Insert code to fulfill it after the native %error is defined. That
609+
// code should structure the RawUnsafeContinuation (continuation) into
610+
// an appropriately typed UnsafeContinuation and then pass that together
611+
// with (a copy of) the error to
612+
// _resumeUnsafeThrowingContinuationWithError.
613+
// [foreign_error_block_with_foreign_async_convention]
614+
SGF.B.setInsertionPoint(
615+
++bridgedForeignError->getDefiningInstruction()->getIterator());
616+
617+
auto continuationDecl = SGF.getASTContext().getUnsafeContinuationDecl();
618+
619+
auto errorTy = SGF.getASTContext().getExceptionType();
620+
auto continuationBGT =
621+
BoundGenericType::get(continuationDecl, Type(),
622+
{calleeTypeInfo.substResultType, errorTy});
623+
auto env = SGF.F.getGenericEnvironment();
624+
auto sig = env ? env->getGenericSignature().getCanonicalSignature()
625+
: CanGenericSignature();
626+
auto mappedContinuationTy =
627+
continuationBGT->mapTypeOutOfContext()->getCanonicalType(sig);
628+
auto resumeType =
629+
cast<BoundGenericType>(mappedContinuationTy).getGenericArgs()[0];
630+
auto continuationTy = continuationBGT->getCanonicalType();
631+
632+
auto errorIntrinsic =
633+
SGF.SGM.getResumeUnsafeThrowingContinuationWithError();
634+
Type replacementTypes[] = {
635+
SGF.F.mapTypeIntoContext(resumeType)->getCanonicalType()};
636+
auto subs = SubstitutionMap::get(errorIntrinsic->getGenericSignature(),
637+
replacementTypes,
638+
ArrayRef<ProtocolConformanceRef>{});
639+
auto wrappedContinuation = SGF.B.createStruct(
640+
loc, SILType::getPrimitiveObjectType(continuationTy),
641+
{continuation});
642+
643+
auto continuationMV =
644+
ManagedValue::forUnmanaged(SILValue(wrappedContinuation));
645+
SGF.emitApplyOfLibraryIntrinsic(
646+
loc, errorIntrinsic, subs,
647+
{continuationMV,
648+
ManagedValue::forUnmanaged(bridgedForeignError).copy(SGF, loc)},
649+
SGFContext());
650+
651+
// Second, emit a branch from the end of the foreign error block to the
652+
// await block, to await the continuation which was just fulfilled.
653+
SGF.B.setInsertionPoint(
654+
bridgedForeignError->getDefiningInstruction()->getParent());
655+
SGF.B.createBranch(loc, awaitBB);
656+
}
657+
658+
SGF.B.emitBlock(awaitBB);
659+
}
569660
SGF.B.createAwaitAsyncContinuation(loc, continuation, resumeBlock, errorBlock);
570661

571662
// Propagate an error if we have one.
@@ -655,8 +746,10 @@ class ForeignErrorInitializationPlan final : public ResultPlan {
655746
}
656747

657748
RValue finish(SILGenFunction &SGF, SILLocation loc, CanType substType,
658-
ArrayRef<ManagedValue> &directResults) override {
659-
return subPlan->finish(SGF, loc, substType, directResults);
749+
ArrayRef<ManagedValue> &directResults,
750+
SILValue bridgedForeignError) override {
751+
return subPlan->finish(SGF, loc, substType, directResults,
752+
bridgedForeignError);
660753
}
661754

662755
void
@@ -665,6 +758,13 @@ class ForeignErrorInitializationPlan final : public ResultPlan {
665758
subPlan->gatherIndirectResultAddrs(SGF, loc, outList);
666759
}
667760

761+
ManagedValue
762+
emitForeignAsyncCompletionHandler(SILGenFunction &SGF,
763+
AbstractionPattern origFormalType,
764+
SILLocation loc) override {
765+
return subPlan->emitForeignAsyncCompletionHandler(SGF, origFormalType, loc);
766+
}
767+
668768
Optional<std::pair<ManagedValue, ManagedValue>>
669769
emitForeignErrorArgument(SILGenFunction &SGF, SILLocation loc) override {
670770
SILGenFunction::PointerAccessInfo pointerInfo = {
@@ -695,12 +795,7 @@ class ForeignErrorInitializationPlan final : public ResultPlan {
695795
ResultPlanPtr ResultPlanBuilder::buildTopLevelResult(Initialization *init,
696796
SILLocation loc) {
697797
// First check if we have a foreign error and/or async convention.
698-
if (auto foreignAsync = calleeTypeInfo.foreign.async) {
699-
// Create a result plan that gets the result schema from the completion
700-
// handler callback's arguments.
701-
// completion handler.
702-
return ResultPlanPtr(new ForeignAsyncInitializationPlan(SGF, loc, calleeTypeInfo));
703-
} else if (auto foreignError = calleeTypeInfo.foreign.error) {
798+
if (auto foreignError = calleeTypeInfo.foreign.error) {
704799
// Handle the foreign error first.
705800
//
706801
// The plan needs to be built using the formal result type after foreign-error
@@ -709,7 +804,8 @@ ResultPlanPtr ResultPlanBuilder::buildTopLevelResult(Initialization *init,
709804
// These conventions make the formal result type ().
710805
case ForeignErrorConvention::ZeroResult:
711806
case ForeignErrorConvention::NonZeroResult:
712-
assert(calleeTypeInfo.substResultType->isVoid());
807+
assert(calleeTypeInfo.substResultType->isVoid() ||
808+
calleeTypeInfo.foreign.async);
713809
allResults.clear();
714810
break;
715811

@@ -734,10 +830,21 @@ ResultPlanPtr ResultPlanBuilder::buildTopLevelResult(Initialization *init,
734830
}
735831
}
736832

737-
ResultPlanPtr subPlan = build(init, calleeTypeInfo.origResultType.getValue(),
738-
calleeTypeInfo.substResultType);
833+
ResultPlanPtr subPlan;
834+
if (auto foreignAsync = calleeTypeInfo.foreign.async) {
835+
subPlan = ResultPlanPtr(
836+
new ForeignAsyncInitializationPlan(SGF, loc, calleeTypeInfo));
837+
} else {
838+
subPlan = build(init, calleeTypeInfo.origResultType.getValue(),
839+
calleeTypeInfo.substResultType);
840+
}
739841
return ResultPlanPtr(new ForeignErrorInitializationPlan(
740842
SGF, loc, calleeTypeInfo, std::move(subPlan)));
843+
} else if (auto foreignAsync = calleeTypeInfo.foreign.async) {
844+
// Create a result plan that gets the result schema from the completion
845+
// handler callback's arguments.
846+
return ResultPlanPtr(
847+
new ForeignAsyncInitializationPlan(SGF, loc, calleeTypeInfo));
741848
} else {
742849
// Otherwise, we can just call build.
743850
return build(init, calleeTypeInfo.origResultType.getValue(),

lib/SILGen/ResultPlan.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ class CalleeTypeInfo;
3838
class ResultPlan {
3939
public:
4040
virtual RValue finish(SILGenFunction &SGF, SILLocation loc, CanType substType,
41-
ArrayRef<ManagedValue> &directResults) = 0;
41+
ArrayRef<ManagedValue> &directResults,
42+
SILValue bridgedForeignError) = 0;
4243
virtual ~ResultPlan() = default;
4344

4445
virtual void

lib/SILGen/SILGen.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
187187
SILFunction *getOrCreateForeignAsyncCompletionHandlerImplFunction(
188188
CanSILFunctionType blockType, CanType continuationTy,
189189
AbstractionPattern origFormalType, CanGenericSignature sig,
190-
ForeignAsyncConvention convention);
190+
ForeignAsyncConvention convention,
191+
Optional<ForeignErrorConvention> foreignError);
191192

192193
/// Determine whether the given class has any instance variables that
193194
/// need to be destroyed.

0 commit comments

Comments
 (0)