Skip to content

Commit 6eb4f2c

Browse files
committed
[SILGen] Handled transforming Bridged? -> Swift.
Previously, the function emitCBridgedToNativeValue handled three situations around optionals: - Bridged?, Native? - Bridged, Native? - Bridged, Native Here, handling for the fourth case - Bridged?, Native is added. To enable this, the number of Optional wrappings that the bridged type has that the native type does not is passed in to the function. Then, in the portions of the function where actual transformations are done, the values are unwrapped an appropriate number of times. Mostly that means force unwrapping N times before doing the transformation. In the case of types that conform to _ObjectiveCBridgeable, however, it means force unwrapping the value N-1 times after doing the transformation because _ObjectiveCBridgeable._unconditionallyBridgeFromObjectiveC performs one layer of unwrapping itself. rdar://81590807
1 parent 69bdaad commit 6eb4f2c

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)