Skip to content

Commit fb199df

Browse files
committed
SILGen: Support overriding/conforming to ObjC APIs with async error flag arguments.
1 parent 4bb49ba commit fb199df

File tree

5 files changed

+92
-15
lines changed

5 files changed

+92
-15
lines changed

lib/SILGen/SILGenBridging.cpp

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1684,6 +1684,19 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
16841684
}
16851685
};
16861686

1687+
auto pushErrorFlag = [&](bool hasError,
1688+
SmallVectorImpl<SILValue> &completionHandlerArgs) {
1689+
bool errorFlagIsZeroOnError = foreignAsync->completionHandlerFlagIsErrorOnZero();
1690+
auto errorFlagIndex = foreignAsync->completionHandlerFlagParamIndex();
1691+
auto errorFlagTy = completionTy->getParameters()[*errorFlagIndex]
1692+
.getSILStorageInterfaceType();
1693+
1694+
auto errorFlag = emitWrapIntegerLiteral(loc, errorFlagTy,
1695+
hasError ^ errorFlagIsZeroOnError);
1696+
1697+
completionHandlerArgs.push_back(errorFlag);
1698+
};
1699+
16871700
// Helper function to pass a native async function's result as arguments to
16881701
// the ObjC completion handler block.
16891702
auto passResultToCompletionHandler = [&](SILValue result) -> SILValue {
@@ -1711,6 +1724,7 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
17111724
Scope completionArgDestructureScope(*this, loc);
17121725

17131726
auto errorParamIndex = foreignAsync->completionHandlerErrorParamIndex();
1727+
auto errorFlagIndex = foreignAsync->completionHandlerFlagParamIndex();
17141728
auto pushErrorPlaceholder = [&]{
17151729
auto errorArgTy = completionTy->getParameters()[*errorParamIndex]
17161730
.getSILStorageInterfaceType();
@@ -1721,18 +1735,22 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
17211735
};
17221736

17231737
unsigned numResults
1724-
= completionTy->getParameters().size() - errorParamIndex.hasValue();
1738+
= completionTy->getParameters().size() - errorParamIndex.hasValue()
1739+
- errorFlagIndex.hasValue();
17251740

17261741
if (numResults == 1) {
1727-
if (errorParamIndex && *errorParamIndex == 0) {
1728-
pushErrorPlaceholder();
1729-
}
1730-
pushArg(asyncResult,
1731-
nativeFormalResultType,
1732-
completionTy->getParameters()[completionHandlerArgs.size()]);
1733-
1734-
if (errorParamIndex && *errorParamIndex == 1) {
1735-
pushErrorPlaceholder();
1742+
for (unsigned i = 0; i < completionTy->getNumParameters(); ++i) {
1743+
if (errorParamIndex && *errorParamIndex == i) {
1744+
pushErrorPlaceholder();
1745+
continue;
1746+
}
1747+
if (errorFlagIndex && *errorFlagIndex == i) {
1748+
pushErrorFlag(/*has error*/ false, completionHandlerArgs);
1749+
continue;
1750+
}
1751+
pushArg(asyncResult,
1752+
nativeFormalResultType,
1753+
completionTy->getParameters()[i]);
17361754
}
17371755
} else {
17381756
// A tuple return maps to multiple completion handler parameters.
@@ -1743,7 +1761,12 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
17431761
pushErrorPlaceholder();
17441762
continue;
17451763
}
1746-
auto elementI = paramI - (errorParamIndex && paramI > *errorParamIndex);
1764+
if (errorFlagIndex && paramI == *errorFlagIndex) {
1765+
pushErrorFlag(/*has error*/ false, completionHandlerArgs);
1766+
continue;
1767+
}
1768+
auto elementI = paramI - (errorParamIndex && paramI > *errorParamIndex)
1769+
- (errorFlagIndex && paramI > *errorFlagIndex);
17471770
auto param = completionTy->getParameters()[paramI];
17481771
auto formalTy = formalTuple.getElementType(elementI);
17491772
auto argPiece = B.createTupleExtract(loc, asyncResult, elementI);
@@ -1845,6 +1868,7 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
18451868
SmallVector<SILValue, 2> completionHandlerArgs;
18461869
auto completionTy = completionBlock->getType().castTo<SILFunctionType>();
18471870
auto errorParamIndex = *foreignAsync->completionHandlerErrorParamIndex();
1871+
auto errorFlagIndex = foreignAsync->completionHandlerFlagParamIndex();
18481872
auto completionErrorTy = completionTy->getParameters()[errorParamIndex]
18491873
.getInterfaceType();
18501874
auto bridgedError = emitNativeToBridgedError(loc,
@@ -1860,6 +1884,11 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
18601884
continue;
18611885
}
18621886

1887+
if (errorFlagIndex && i == *errorFlagIndex) {
1888+
pushErrorFlag(/*has error*/ true, completionHandlerArgs);
1889+
continue;
1890+
}
1891+
18631892
// For non-error arguments, pass a placeholder.
18641893
// If the argument type is non-trivial, it must be Optional, and
18651894
// we pass nil.

lib/SILGen/SILGenFunction.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,3 +1071,22 @@ SILValue SILGenFunction::emitUnwrapIntegerResult(SILLocation loc,
10711071

10721072
return value;
10731073
}
1074+
1075+
SILValue SILGenFunction::emitWrapIntegerLiteral(SILLocation loc,
1076+
SILType ty,
1077+
unsigned value) {
1078+
// Create a builtin integer literal value.
1079+
if (auto intTy = ty.getAs<BuiltinIntegerType>()) {
1080+
return B.createIntegerLiteral(loc, ty, value);
1081+
}
1082+
1083+
// Or wrap a value in a struct, potentially multiple times to handle types
1084+
// that wrap integer types like ObjCBool (which may be Bool or Int8).
1085+
auto structDecl = ty.getStructOrBoundGenericStruct();
1086+
assert(structDecl && "value for error result wasn't of struct type!");
1087+
assert(structDecl->getStoredProperties().size() == 1);
1088+
auto property = structDecl->getStoredProperties()[0];
1089+
auto propertyTy = ty.getFieldType(property, SGM.Types, getTypeExpansionContext());
1090+
auto propertyValue = emitWrapIntegerLiteral(loc, propertyTy, value);
1091+
return B.createStruct(loc, ty, propertyValue);
1092+
}

lib/SILGen/SILGenFunction.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1477,7 +1477,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
14771477
SILType storageType);
14781478

14791479
SILValue emitUnwrapIntegerResult(SILLocation loc, SILValue value);
1480-
1480+
SILValue emitWrapIntegerLiteral(SILLocation loc, SILType ty,
1481+
unsigned value);
14811482
/// Load an r-value out of the given address. This does not handle
14821483
/// reabstraction or bridging. If that is needed, use the other emit load
14831484
/// entry point.

test/SILGen/objc_async.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,11 @@ func testSlowServer(slowServer: SlowServer) async throws {
4646
// CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[VOID_COMPLETION_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage UnsafeContinuation<(), Never>) -> ()
4747
await slowServer.serverRestart("somewhere")
4848

49-
// CHECK: function_ref @[[STRING_NONZERO_FLAG_THROW_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage UnsafeContinuation<String, Error>, ObjCBool, Optional<NSString>, Optional<NSError>) -> ()
49+
// CHECK: function_ref @[[STRING_NONZERO_FLAG_THROW_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage UnsafeContinuation<String, Error>, {{.*}}Bool, Optional<NSString>, Optional<NSError>) -> ()
5050
let _: String = try await slowServer.doSomethingFlaggy()
51-
// CHECK: function_ref @[[STRING_ZERO_FLAG_THROW_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage UnsafeContinuation<String, Error>, Optional<NSString>, ObjCBool, Optional<NSError>) -> ()
51+
// CHECK: function_ref @[[STRING_ZERO_FLAG_THROW_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage UnsafeContinuation<String, Error>, Optional<NSString>, {{.*}}Bool, Optional<NSError>) -> ()
5252
let _: String = try await slowServer.doSomethingZeroFlaggy()
53-
// CHECK: function_ref @[[STRING_STRING_ZERO_FLAG_THROW_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage UnsafeContinuation<(String, String), Error>, ObjCBool, Optional<NSString>, Optional<NSError>, Optional<NSString>) -> ()
53+
// CHECK: function_ref @[[STRING_STRING_ZERO_FLAG_THROW_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage UnsafeContinuation<(String, String), Error>, {{.*}}Bool, Optional<NSString>, Optional<NSError>, Optional<NSString>) -> ()
5454
let _: (String, String) = try await slowServer.doSomethingMultiResultFlaggy()
5555

5656
// CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[NSSTRING_INT_THROW_COMPLETION_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage UnsafeContinuation<(String, Int), Error>, Optional<NSString>, Int, Optional<NSError>) -> ()

test/SILGen/objc_async_from_swift.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,5 +78,33 @@ class SlowServerlet: SlowServer {
7878
override func doSomethingDangerousNullably(_ x: String) async throws -> String {
7979
return x
8080
}
81+
82+
// CHECK-LABEL: sil{{.*}}13SlowServerlet{{.*}}17doSomethingFlaggy{{.*}}To :
83+
// CHECK: try_apply{{.*}}, normal [[NORMAL_BB:bb[0-9]+]], error [[ERROR_BB:bb[0-9]+]]
84+
// CHECK: [[NORMAL_BB]]({{.*}}):
85+
// CHECK: integer_literal {{.*}}0
86+
// CHECK: [[ERROR_BB]]({{.*}}):
87+
// CHECK: integer_literal {{.*}}1
88+
override func doSomethingFlaggy() async throws -> String {
89+
return ""
90+
}
91+
// CHECK-LABEL: sil{{.*}}13SlowServerlet{{.*}}21doSomethingZeroFlaggy{{.*}}To :
92+
// CHECK: try_apply{{.*}}, normal [[NORMAL_BB:bb[0-9]+]], error [[ERROR_BB:bb[0-9]+]]
93+
// CHECK: [[NORMAL_BB]]({{.*}}):
94+
// CHECK: integer_literal {{.*}}1
95+
// CHECK: [[ERROR_BB]]({{.*}}):
96+
// CHECK: integer_literal {{.*}}0
97+
override func doSomethingZeroFlaggy() async throws -> String {
98+
return ""
99+
}
100+
// CHECK-LABEL: sil{{.*}}13SlowServerlet{{.*}}28doSomethingMultiResultFlaggy{{.*}}To :
101+
// CHECK: try_apply{{.*}}, normal [[NORMAL_BB:bb[0-9]+]], error [[ERROR_BB:bb[0-9]+]]
102+
// CHECK: [[NORMAL_BB]]({{.*}}):
103+
// CHECK: integer_literal {{.*}}1
104+
// CHECK: [[ERROR_BB]]({{.*}}):
105+
// CHECK: integer_literal {{.*}}0
106+
override func doSomethingMultiResultFlaggy() async throws -> (String, String) {
107+
return ("", "")
108+
}
81109
}
82110

0 commit comments

Comments
 (0)