Skip to content

Commit 86bd7c8

Browse files
Merge pull request #38773 from nate-chandler/rdar81590807
[SILGen] Handled transforming Bridged? -> Swift.
2 parents 5b738fa + 6eb4f2c commit 86bd7c8

File tree

9 files changed

+287
-35
lines changed

9 files changed

+287
-35
lines changed

lib/SILGen/SILGenBridging.cpp

Lines changed: 50 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,16 +1020,11 @@ SILGenFunction::emitBlockToFunc(SILLocation loc,
10201020
loc, thunkedFn, SILType::getPrimitiveObjectType(loweredFuncTy));
10211021
}
10221022

1023-
static ManagedValue emitCBridgedToNativeValue(SILGenFunction &SGF,
1024-
SILLocation loc,
1025-
ManagedValue v,
1026-
CanType bridgedType,
1027-
CanType nativeType,
1028-
SILType loweredNativeTy,
1029-
bool isCallResult,
1030-
SGFContext C) {
1023+
static ManagedValue emitCBridgedToNativeValue(
1024+
SILGenFunction &SGF, SILLocation loc, ManagedValue v, CanType bridgedType,
1025+
SILType loweredBridgedTy, CanType nativeType, SILType loweredNativeTy,
1026+
int bridgedOptionalsToUnwrap, bool isCallResult, SGFContext C) {
10311027
assert(loweredNativeTy.isObject());
1032-
SILType loweredBridgedTy = v.getType();
10331028
if (loweredNativeTy == loweredBridgedTy.getObjectType())
10341029
return v;
10351030

@@ -1040,37 +1035,50 @@ static ManagedValue emitCBridgedToNativeValue(SILGenFunction &SGF,
10401035
if (!bridgedObjectType) {
10411036
auto helper = [&](SILGenFunction &SGF, SILLocation loc, SGFContext C) {
10421037
auto loweredNativeObjectTy = loweredNativeTy.getOptionalObjectType();
1043-
return emitCBridgedToNativeValue(SGF, loc, v, bridgedType,
1044-
nativeObjectType,
1045-
loweredNativeObjectTy,
1046-
isCallResult, C);
1038+
return emitCBridgedToNativeValue(
1039+
SGF, loc, v, bridgedType, loweredBridgedTy, nativeObjectType,
1040+
loweredNativeObjectTy, bridgedOptionalsToUnwrap, isCallResult, C);
10471041
};
10481042
return SGF.emitOptionalSome(loc, loweredNativeTy, helper, C);
10491043
}
10501044

10511045
// Optional-to-optional.
1052-
auto helper =
1053-
[=](SILGenFunction &SGF, SILLocation loc, ManagedValue v,
1054-
SILType loweredNativeObjectTy, SGFContext C) {
1055-
return emitCBridgedToNativeValue(SGF, loc, v, bridgedObjectType,
1056-
nativeObjectType, loweredNativeObjectTy,
1057-
isCallResult, C);
1046+
auto helper = [=](SILGenFunction &SGF, SILLocation loc, ManagedValue v,
1047+
SILType loweredNativeObjectTy, SGFContext C) {
1048+
return emitCBridgedToNativeValue(
1049+
SGF, loc, v, bridgedObjectType,
1050+
loweredBridgedTy.getOptionalObjectType(), nativeObjectType,
1051+
loweredNativeObjectTy, bridgedOptionalsToUnwrap, isCallResult, C);
10581052
};
10591053
return SGF.emitOptionalToOptional(loc, v, loweredNativeTy, helper, C);
10601054
}
1055+
if (auto bridgedObjectType = bridgedType.getOptionalObjectType()) {
1056+
return emitCBridgedToNativeValue(
1057+
SGF, loc, v, bridgedObjectType,
1058+
loweredBridgedTy.getOptionalObjectType(), nativeType, loweredNativeTy,
1059+
bridgedOptionalsToUnwrap + 1, isCallResult, C);
1060+
}
1061+
1062+
auto unwrapBridgedOptionals = [&](ManagedValue v) {
1063+
for (int i = 0; i < bridgedOptionalsToUnwrap; ++i) {
1064+
v = SGF.emitPreconditionOptionalHasValue(loc, v,
1065+
/*implicit*/ true);
1066+
};
1067+
return v;
1068+
};
10611069

10621070
// Bridge ObjCBool, DarwinBoolean, WindowsBool to Bool when requested.
10631071
if (nativeType == SGF.SGM.Types.getBoolType()) {
10641072
if (bridgedType == SGF.SGM.Types.getObjCBoolType()) {
1065-
return emitBridgeForeignBoolToBool(SGF, loc, v,
1073+
return emitBridgeForeignBoolToBool(SGF, loc, unwrapBridgedOptionals(v),
10661074
SGF.SGM.getObjCBoolToBoolFn());
10671075
}
10681076
if (bridgedType == SGF.SGM.Types.getDarwinBooleanType()) {
1069-
return emitBridgeForeignBoolToBool(SGF, loc, v,
1077+
return emitBridgeForeignBoolToBool(SGF, loc, unwrapBridgedOptionals(v),
10701078
SGF.SGM.getDarwinBooleanToBoolFn());
10711079
}
10721080
if (bridgedType == SGF.SGM.Types.getWindowsBoolType()) {
1073-
return emitBridgeForeignBoolToBool(SGF, loc, v,
1081+
return emitBridgeForeignBoolToBool(SGF, loc, unwrapBridgedOptionals(v),
10741082
SGF.SGM.getWindowsBoolToBoolFn());
10751083
}
10761084
}
@@ -1080,8 +1088,8 @@ static ManagedValue emitCBridgedToNativeValue(SILGenFunction &SGF,
10801088
auto bridgedMetaTy = cast<AnyMetatypeType>(bridgedType);
10811089
if (bridgedMetaTy->hasRepresentation() &&
10821090
bridgedMetaTy->getRepresentation() == MetatypeRepresentation::ObjC) {
1083-
SILValue native =
1084-
SGF.B.emitObjCToThickMetatype(loc, v.getValue(), loweredNativeTy);
1091+
SILValue native = SGF.B.emitObjCToThickMetatype(
1092+
loc, unwrapBridgedOptionals(v).getValue(), loweredNativeTy);
10851093
// *NOTE*: ObjCMetatypes are trivial types. They only gain ARC semantics
10861094
// when they are converted to an object via objc_metatype_to_object.
10871095
assert(!v.hasCleanup() && "Metatypes are trivial and should not have "
@@ -1097,7 +1105,8 @@ static ManagedValue emitCBridgedToNativeValue(SILGenFunction &SGF,
10971105
== AnyFunctionType::Representation::Block
10981106
&& nativeFTy->getRepresentation()
10991107
!= AnyFunctionType::Representation::Block) {
1100-
return SGF.emitBlockToFunc(loc, v, bridgedFTy, nativeFTy,
1108+
return SGF.emitBlockToFunc(loc, unwrapBridgedOptionals(v), bridgedFTy,
1109+
nativeFTy,
11011110
loweredNativeTy.castTo<SILFunctionType>());
11021111
}
11031112
}
@@ -1106,8 +1115,10 @@ static ManagedValue emitCBridgedToNativeValue(SILGenFunction &SGF,
11061115
if (auto conformance =
11071116
SGF.SGM.getConformanceToObjectiveCBridgeable(loc, nativeType)) {
11081117
if (auto result = emitBridgeObjectiveCToNative(SGF, loc, v, bridgedType,
1109-
conformance))
1110-
return *result;
1118+
conformance)) {
1119+
--bridgedOptionalsToUnwrap;
1120+
return unwrapBridgedOptionals(*result);
1121+
}
11111122

11121123
assert(SGF.SGM.getASTContext().Diags.hadAnyError() &&
11131124
"Bridging code should have complained");
@@ -1118,7 +1129,8 @@ static ManagedValue emitCBridgedToNativeValue(SILGenFunction &SGF,
11181129
if (nativeType->isAny()) {
11191130
// If this is not a call result, use the normal erasure logic.
11201131
if (!isCallResult) {
1121-
return SGF.emitTransformedValue(loc, v, bridgedType, nativeType, C);
1132+
return SGF.emitTransformedValue(loc, unwrapBridgedOptionals(v),
1133+
bridgedType, nativeType, C);
11221134
}
11231135

11241136
// Otherwise, we use more complicated logic that handles results that
@@ -1130,7 +1142,8 @@ static ManagedValue emitCBridgedToNativeValue(SILGenFunction &SGF,
11301142
CanType anyObjectTy =
11311143
SGF.getASTContext().getAnyObjectType()->getCanonicalType();
11321144
if (bridgedType != anyObjectTy) {
1133-
v = SGF.emitTransformedValue(loc, v, bridgedType, anyObjectTy);
1145+
v = SGF.emitTransformedValue(loc, unwrapBridgedOptionals(v), bridgedType,
1146+
anyObjectTy);
11341147
}
11351148

11361149
// TODO: Ever need to handle +0 values here?
@@ -1143,8 +1156,8 @@ static ManagedValue emitCBridgedToNativeValue(SILGenFunction &SGF,
11431156
// Bitcast to Optional. This provides a barrier to the optimizer to prevent
11441157
// it from attempting to eliminate null checks.
11451158
auto optionalBridgedTy = SILType::getOptionalType(loweredBridgedTy);
1146-
auto optionalMV =
1147-
SGF.B.createUncheckedBitCast(loc, v, optionalBridgedTy);
1159+
auto optionalMV = SGF.B.createUncheckedBitCast(
1160+
loc, unwrapBridgedOptionals(v), optionalBridgedTy);
11481161
return SGF.emitApplyOfLibraryIntrinsic(loc,
11491162
SGF.getASTContext().getBridgeAnyObjectToAny(),
11501163
SubstitutionMap(), optionalMV, C)
@@ -1153,9 +1166,9 @@ static ManagedValue emitCBridgedToNativeValue(SILGenFunction &SGF,
11531166

11541167
// Bridge NSError to Error.
11551168
if (bridgedType == SGF.SGM.Types.getNSErrorType())
1156-
return SGF.emitBridgedToNativeError(loc, v);
1169+
return SGF.emitBridgedToNativeError(loc, unwrapBridgedOptionals(v));
11571170

1158-
return v;
1171+
return unwrapBridgedOptionals(v);
11591172
}
11601173

11611174
ManagedValue SILGenFunction::emitBridgedToNativeValue(SILLocation loc,
@@ -1166,8 +1179,10 @@ ManagedValue SILGenFunction::emitBridgedToNativeValue(SILLocation loc,
11661179
SGFContext C,
11671180
bool isCallResult) {
11681181
loweredNativeTy = loweredNativeTy.getObjectType();
1169-
return emitCBridgedToNativeValue(*this, loc, v, bridgedType, nativeType,
1170-
loweredNativeTy, isCallResult, C);
1182+
SILType loweredBridgedTy = v.getType();
1183+
return emitCBridgedToNativeValue(
1184+
*this, loc, v, bridgedType, loweredBridgedTy, nativeType, loweredNativeTy,
1185+
/*bridgedOptionalsToUnwrap=*/0, isCallResult, C);
11711186
}
11721187

11731188
/// Bridge a possibly-optional foreign error type to Error.

test/Inputs/clang-importer-sdk/usr/include/ObjCConcurrency.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ typedef void (^CompletionHandler)(NSString * _Nullable, NSString * _Nullable_res
8484
-(void)asyncImportSame:(NSString *)operation replyTo:(void (^)(NSInteger))handler __attribute__((swift_async(none)));
8585

8686
-(void)overridableButRunsOnMainThreadWithCompletionHandler:(MAIN_ACTOR_UNSAFE void (^ _Nullable)(NSString *))completion;
87+
- (void)obtainClosureWithCompletionHandler:(void (^)(void (^_Nullable)(void),
88+
NSError *_Nullable,
89+
BOOL))completionHandler
90+
__attribute__((swift_async_error(zero_argument, 3)));
8791
@end
8892

8993
@protocol RefrigeratorDelegate<NSObject>

test/SILGen/objc_async.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ func testSlowServer(slowServer: SlowServer) async throws {
8585
let _: ((Any) -> Void, (Any) -> Void) = await slowServer.performId2VoidId2Void()
8686

8787
let _: String = try await slowServer.findAnswerFailingly()
88+
89+
let _: () -> Void = try await slowServer.obtainClosure()
8890
}
8991

9092
func testGeneric<T: AnyObject>(x: GenericObject<T>) async throws {
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#include <Foundation/Foundation.h>
2+
3+
#pragma clang assume_nonnull begin
4+
5+
@interface PFXObject : NSObject {
6+
}
7+
- (void)continuePassSyncWithCompletionHandler:(void (^)(void (^_Nullable)(void),
8+
NSError *_Nullable,
9+
BOOL))completionHandler
10+
__attribute__((swift_async_error(zero_argument, 3)));
11+
- (void)continuePassAsyncWithCompletionHandler:
12+
(void (^)(void (^_Nullable)(void), NSError *_Nullable,
13+
BOOL))completionHandler
14+
__attribute__((swift_async_error(zero_argument, 3)));
15+
- (void)continueFailSyncWithCompletionHandler:(void (^)(void (^_Nullable)(void),
16+
NSError *_Nullable,
17+
BOOL))completionHandler
18+
__attribute__((swift_async_error(zero_argument, 3)));
19+
- (void)continueFailAsyncWithCompletionHandler:
20+
(void (^)(void (^_Nullable)(void), NSError *_Nullable,
21+
BOOL))completionHandler
22+
__attribute__((swift_async_error(zero_argument, 3)));
23+
- (void)continueIncorrectWithCompletionHandler:
24+
(void (^)(void (^_Nullable)(void), NSError *_Nullable,
25+
BOOL))completionHandler
26+
__attribute__((swift_async_error(zero_argument, 3)));
27+
@end
28+
29+
#pragma clang assume_nonnull end
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#include "rdar81590807.h"
2+
3+
#pragma clang assume_nonnull begin
4+
5+
@implementation PFXObject
6+
- (void)continuePassSyncWithCompletionHandler:(void (^)(void (^_Nullable)(void),
7+
NSError *_Nullable,
8+
BOOL))completionHandler
9+
__attribute__((swift_async_error(zero_argument, 3))) {
10+
completionHandler(
11+
^{
12+
NSLog(@"passSync");
13+
},
14+
NULL, YES);
15+
}
16+
- (void)continuePassAsyncWithCompletionHandler:
17+
(void (^)(void (^_Nullable)(void), NSError *_Nullable,
18+
BOOL))completionHandler
19+
__attribute__((swift_async_error(zero_argument, 3))) {
20+
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
21+
completionHandler(
22+
^{
23+
NSLog(@"passAsync");
24+
},
25+
NULL, YES);
26+
});
27+
}
28+
- (void)continueFailSyncWithCompletionHandler:(void (^)(void (^_Nullable)(void),
29+
NSError *_Nullable,
30+
BOOL))completionHandler
31+
__attribute__((swift_async_error(zero_argument, 3))) {
32+
completionHandler(
33+
NULL, [NSError errorWithDomain:@"failSync" code:1 userInfo:nil], NO);
34+
}
35+
- (void)continueFailAsyncWithCompletionHandler:
36+
(void (^)(void (^_Nullable)(void), NSError *_Nullable,
37+
BOOL))completionHandler
38+
__attribute__((swift_async_error(zero_argument, 3))) {
39+
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
40+
completionHandler(
41+
NULL, [NSError errorWithDomain:@"failAsync" code:2 userInfo:nil], NO);
42+
});
43+
}
44+
- (void)continueIncorrectWithCompletionHandler:
45+
(void (^)(void (^_Nullable)(void), NSError *_Nullable,
46+
BOOL))completionHandler
47+
__attribute__((swift_async_error(zero_argument, 3))) {
48+
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
49+
completionHandler(NULL, NULL, NO);
50+
});
51+
}
52+
@end
53+
54+
#pragma clang assume_nonnull end
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include <Foundation/Foundation.h>
2+
3+
#pragma clang assume_nonnull begin
4+
5+
@interface PFXObject : NSObject {
6+
}
7+
- (void)findAnswerSyncSuccessAsynchronously:
8+
(void (^)(NSString *_Nullable, NSError *_Nullable))handler
9+
__attribute__((swift_name("findAnswerSyncSuccess(completionHandler:)")));
10+
- (void)findAnswerAsyncSuccessAsynchronously:
11+
(void (^)(NSString *_Nullable, NSError *_Nullable))handler
12+
__attribute__((swift_name("findAnswerAsyncSuccess(completionHandler:)")));
13+
- (void)findAnswerSyncFailAsynchronously:
14+
(void (^)(NSString *_Nullable, NSError *_Nullable))handler
15+
__attribute__((swift_name("findAnswerSyncFail(completionHandler:)")));
16+
- (void)findAnswerAsyncFailAsynchronously:
17+
(void (^)(NSString *_Nullable, NSError *_Nullable))handler
18+
__attribute__((swift_name("findAnswerAsyncFail(completionHandler:)")));
19+
- (void)findAnswerIncorrectAsynchronously:
20+
(void (^)(NSString *_Nullable, NSError *_Nullable))handler
21+
__attribute__((swift_name("findAnswerIncorrect(completionHandler:)")));
22+
@end
23+
24+
#pragma clang assume_nonnull end
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#include "rdar81590807_2.h"
2+
3+
#pragma clang assume_nonnull begin
4+
5+
@implementation PFXObject
6+
- (void)findAnswerSyncSuccessAsynchronously:
7+
(void (^)(NSString *_Nullable, NSError *_Nullable))handler
8+
__attribute__((swift_name("findAnswerSyncSuccess(completionHandler:)"))) {
9+
handler(@"syncSuccess", NULL);
10+
}
11+
- (void)findAnswerAsyncSuccessAsynchronously:
12+
(void (^)(NSString *_Nullable, NSError *_Nullable))handler
13+
__attribute__((swift_name("findAnswerAsyncSuccess(completionHandler:)"))) {
14+
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
15+
handler(@"asyncSuccess", NULL);
16+
});
17+
}
18+
- (void)findAnswerSyncFailAsynchronously:
19+
(void (^)(NSString *_Nullable, NSError *_Nullable))handler
20+
__attribute__((swift_name("findAnswerSyncFail(completionHandler:)"))) {
21+
handler(NULL, [NSError errorWithDomain:@"syncFail" code:1 userInfo:nil]);
22+
}
23+
- (void)findAnswerAsyncFailAsynchronously:
24+
(void (^)(NSString *_Nullable, NSError *_Nullable))handler
25+
__attribute__((swift_name("findAnswerAsyncFail(completionHandler:)"))) {
26+
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
27+
handler(NULL, [NSError errorWithDomain:@"asyncFail" code:2 userInfo:nil]);
28+
});
29+
}
30+
- (void)findAnswerIncorrectAsynchronously:
31+
(void (^)(NSString *_Nullable, NSError *_Nullable))handler
32+
__attribute__((swift_name("findAnswerIncorrect(completionHandler:)"))) {
33+
handler(NULL, NULL);
34+
}
35+
@end
36+
37+
#pragma clang assume_nonnull end
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-clang %S/Inputs/rdar81590807.m -I %S/Inputs -c -o %t/rdar81590807.o
3+
// RUN: %target-build-swift -Xfrontend -disable-availability-checking -import-objc-header %S/Inputs/rdar81590807.h -Xlinker %t/rdar81590807.o -parse-as-library %s -o %t/main
4+
// RUN: %target-codesign %t/main
5+
// RUN: %target-run %t/main > %t/log 2>&1 || true
6+
// RUN: %FileCheck %s < %t/log
7+
8+
// REQUIRES: executable_test
9+
// REQUIRES: OS=macosx || OS=ios
10+
11+
func run(on object: PFXObject) async throws {
12+
// CHECK: passSync
13+
let cl1 = try await object.continuePassSync()
14+
cl1()
15+
// CHECK: passAsync
16+
let cl2 = try await object.continuePassAsync()
17+
cl2()
18+
do {
19+
let cl = try await object.continueFailSync()
20+
// CHECK-NOT: oh no failSync
21+
fputs("oh no failSync\n", stderr)
22+
}
23+
catch let error {
24+
// CHECK: Error Domain=failSync Code=1 "(null)"
25+
fputs("\(error)\n", stderr)
26+
}
27+
do {
28+
let cl = try await object.continueFailAsync()
29+
// CHECK-NOT: oh no failAsync
30+
fputs("oh no failAsync\n", stderr)
31+
}
32+
catch let error {
33+
// CHECK: Error Domain=failAsync Code=2 "(null)"
34+
fputs("\(error)\n", stderr)
35+
}
36+
// CHECK: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
37+
print(try await object.continueIncorrect())
38+
}
39+
40+
@main struct Main {
41+
static func main() async throws {
42+
let object = PFXObject()
43+
try await run(on: object)
44+
}
45+
}

0 commit comments

Comments
 (0)