Skip to content

Commit 99d0b79

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 8d59fd0 commit 99d0b79

File tree

9 files changed

+292
-35
lines changed

9 files changed

+292
-35
lines changed

lib/SILGen/SILGenBridging.cpp

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

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

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

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

10611069
// Bridge ObjCBool, DarwinBoolean, WindowsBool to Bool when requested.
10621070
if (nativeType == SGF.SGM.Types.getBoolType()) {
10631071
if (bridgedType == SGF.SGM.Types.getObjCBoolType()) {
1064-
return emitBridgeForeignBoolToBool(SGF, loc, v,
1072+
return emitBridgeForeignBoolToBool(SGF, loc, unwrapBridgedOptionals(v),
10651073
SGF.SGM.getObjCBoolToBoolFn());
10661074
}
10671075
if (bridgedType == SGF.SGM.Types.getDarwinBooleanType()) {
1068-
return emitBridgeForeignBoolToBool(SGF, loc, v,
1076+
return emitBridgeForeignBoolToBool(SGF, loc, unwrapBridgedOptionals(v),
10691077
SGF.SGM.getDarwinBooleanToBoolFn());
10701078
}
10711079
if (bridgedType == SGF.SGM.Types.getWindowsBoolType()) {
1072-
return emitBridgeForeignBoolToBool(SGF, loc, v,
1080+
return emitBridgeForeignBoolToBool(SGF, loc, unwrapBridgedOptionals(v),
10731081
SGF.SGM.getWindowsBoolToBoolFn());
10741082
}
10751083
}
@@ -1079,8 +1087,8 @@ static ManagedValue emitCBridgedToNativeValue(SILGenFunction &SGF,
10791087
auto bridgedMetaTy = cast<AnyMetatypeType>(bridgedType);
10801088
if (bridgedMetaTy->hasRepresentation() &&
10811089
bridgedMetaTy->getRepresentation() == MetatypeRepresentation::ObjC) {
1082-
SILValue native =
1083-
SGF.B.emitObjCToThickMetatype(loc, v.getValue(), loweredNativeTy);
1090+
SILValue native = SGF.B.emitObjCToThickMetatype(
1091+
loc, unwrapBridgedOptionals(v).getValue(), loweredNativeTy);
10841092
// *NOTE*: ObjCMetatypes are trivial types. They only gain ARC semantics
10851093
// when they are converted to an object via objc_metatype_to_object.
10861094
assert(!v.hasCleanup() && "Metatypes are trivial and should not have "
@@ -1096,7 +1104,8 @@ static ManagedValue emitCBridgedToNativeValue(SILGenFunction &SGF,
10961104
== AnyFunctionType::Representation::Block
10971105
&& nativeFTy->getRepresentation()
10981106
!= AnyFunctionType::Representation::Block) {
1099-
return SGF.emitBlockToFunc(loc, v, bridgedFTy, nativeFTy,
1107+
return SGF.emitBlockToFunc(loc, unwrapBridgedOptionals(v), bridgedFTy,
1108+
nativeFTy,
11001109
loweredNativeTy.castTo<SILFunctionType>());
11011110
}
11021111
}
@@ -1105,8 +1114,10 @@ static ManagedValue emitCBridgedToNativeValue(SILGenFunction &SGF,
11051114
if (auto conformance =
11061115
SGF.SGM.getConformanceToObjectiveCBridgeable(loc, nativeType)) {
11071116
if (auto result = emitBridgeObjectiveCToNative(SGF, loc, v, bridgedType,
1108-
conformance))
1109-
return *result;
1117+
conformance)) {
1118+
--bridgedOptionalsToUnwrap;
1119+
return unwrapBridgedOptionals(*result);
1120+
}
11101121

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

11231135
// Otherwise, we use more complicated logic that handles results that
@@ -1129,7 +1141,8 @@ static ManagedValue emitCBridgedToNativeValue(SILGenFunction &SGF,
11291141
CanType anyObjectTy =
11301142
SGF.getASTContext().getAnyObjectType()->getCanonicalType();
11311143
if (bridgedType != anyObjectTy) {
1132-
v = SGF.emitTransformedValue(loc, v, bridgedType, anyObjectTy);
1144+
v = SGF.emitTransformedValue(loc, unwrapBridgedOptionals(v), bridgedType,
1145+
anyObjectTy);
11331146
}
11341147

11351148
// TODO: Ever need to handle +0 values here?
@@ -1142,8 +1155,8 @@ static ManagedValue emitCBridgedToNativeValue(SILGenFunction &SGF,
11421155
// Bitcast to Optional. This provides a barrier to the optimizer to prevent
11431156
// it from attempting to eliminate null checks.
11441157
auto optionalBridgedTy = SILType::getOptionalType(loweredBridgedTy);
1145-
auto optionalMV =
1146-
SGF.B.createUncheckedBitCast(loc, v, optionalBridgedTy);
1158+
auto optionalMV = SGF.B.createUncheckedBitCast(
1159+
loc, unwrapBridgedOptionals(v), optionalBridgedTy);
11471160
return SGF.emitApplyOfLibraryIntrinsic(loc,
11481161
SGF.getASTContext().getBridgeAnyObjectToAny(),
11491162
SubstitutionMap(), optionalMV, C)
@@ -1152,9 +1165,9 @@ static ManagedValue emitCBridgedToNativeValue(SILGenFunction &SGF,
11521165

11531166
// Bridge NSError to Error.
11541167
if (bridgedType == SGF.SGM.Types.getNSErrorType())
1155-
return SGF.emitBridgedToNativeError(loc, v);
1168+
return SGF.emitBridgedToNativeError(loc, unwrapBridgedOptionals(v));
11561169

1157-
return v;
1170+
return unwrapBridgedOptionals(v);
11581171
}
11591172

11601173
ManagedValue SILGenFunction::emitBridgedToNativeValue(SILLocation loc,
@@ -1165,8 +1178,10 @@ ManagedValue SILGenFunction::emitBridgedToNativeValue(SILLocation loc,
11651178
SGFContext C,
11661179
bool isCallResult) {
11671180
loweredNativeTy = loweredNativeTy.getObjectType();
1168-
return emitCBridgedToNativeValue(*this, loc, v, bridgedType, nativeType,
1169-
loweredNativeTy, isCallResult, C);
1181+
SILType loweredBridgedTy = v.getType();
1182+
return emitCBridgedToNativeValue(
1183+
*this, loc, v, bridgedType, loweredBridgedTy, nativeType, loweredNativeTy,
1184+
/*bridgedOptionalsToUnwrap=*/0, isCallResult, C);
11701185
}
11711186

11721187
/// 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: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
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+
// Unsupported because the crash on continueIncorrect is just an illegal
9+
// instruction rather than a nice fatal error.
10+
// UNSUPPORTED: swift_test_mode_optimize
11+
// UNSUPPORTED: swift_test_mode_optimize_size
12+
13+
// REQUIRES: executable_test
14+
// REQUIRES: OS=macosx || OS=ios
15+
16+
func run(on object: PFXObject) async throws {
17+
// CHECK: passSync
18+
let cl1 = try await object.continuePassSync()
19+
cl1()
20+
// CHECK: passAsync
21+
let cl2 = try await object.continuePassAsync()
22+
cl2()
23+
do {
24+
let cl = try await object.continueFailSync()
25+
// CHECK-NOT: oh no failSync
26+
fputs("oh no failSync\n", stderr)
27+
}
28+
catch let error {
29+
// CHECK: Error Domain=failSync Code=1 "(null)"
30+
fputs("\(error)\n", stderr)
31+
}
32+
do {
33+
let cl = try await object.continueFailAsync()
34+
// CHECK-NOT: oh no failAsync
35+
fputs("oh no failAsync\n", stderr)
36+
}
37+
catch let error {
38+
// CHECK: Error Domain=failAsync Code=2 "(null)"
39+
fputs("\(error)\n", stderr)
40+
}
41+
// CHECK: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
42+
print(try await object.continueIncorrect())
43+
}
44+
45+
@main struct Main {
46+
static func main() async throws {
47+
let object = PFXObject()
48+
try await run(on: object)
49+
}
50+
}

0 commit comments

Comments
 (0)