Skip to content

Commit fa9889d

Browse files
authored
Merge pull request swiftlang#41535 from jckarter/objc-async-bridging-multi-result-with-any
SILGen: Handle objc async bridging when there is a combination of `Any` and other results.
2 parents 5473cec + 48a5089 commit fa9889d

File tree

3 files changed

+91
-21
lines changed

3 files changed

+91
-21
lines changed

lib/SILGen/SILGenBridging.cpp

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1593,13 +1593,17 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
15931593
}
15941594
}
15951595

1596-
// If we are bridging a Swift method with an Any return value, create a
1597-
// stack allocation to hold the result, since Any is address-only.
1596+
// If we are bridging a Swift method with Any return value(s), create a
1597+
// stack allocation to hold the result(s), since Any is address-only.
15981598
SmallVector<SILValue, 4> args;
1599-
16001599
if (substConv.hasIndirectSILResults()) {
1601-
args.push_back(emitTemporaryAllocation(
1602-
loc, substConv.getSingleSILResultType(getTypeExpansionContext())));
1600+
for (auto result : substConv.getResults()) {
1601+
if (!substConv.isSILIndirect(result)) {
1602+
continue;
1603+
}
1604+
args.push_back(emitTemporaryAllocation(
1605+
loc, substConv.getSILType(result, getTypeExpansionContext())));
1606+
}
16031607
}
16041608

16051609
// If the '@objc' was inferred due to deprecated rules,
@@ -1792,14 +1796,29 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
17921796
pushErrorFlag(/*has error*/ false, completionHandlerArgs);
17931797
continue;
17941798
}
1795-
pushArg(asyncResult,
1796-
nativeFormalResultType,
1797-
completionTy->getParameters()[i]);
1799+
1800+
// Use the indirect return argument if the result is indirect.
1801+
if (substConv.hasIndirectSILResults()) {
1802+
pushArg(emitManagedRValueWithCleanup(args[0]),
1803+
nativeFormalResultType,
1804+
completionTy->getParameters()[i]);
1805+
} else {
1806+
pushArg(asyncResult,
1807+
nativeFormalResultType,
1808+
completionTy->getParameters()[i]);
1809+
}
17981810
}
17991811
} else {
18001812
// A tuple return maps to multiple completion handler parameters.
18011813
auto formalTuple = cast<TupleType>(nativeFormalResultType);
18021814

1815+
unsigned indirectResultI = 0;
1816+
unsigned directResultI = 0;
1817+
1818+
auto directResults = substConv.getDirectSILResults();
1819+
auto hasMultipleDirectResults
1820+
= std::next(directResults.begin()) != directResults.end();
1821+
18031822
for (unsigned paramI : indices(completionTy->getParameters())) {
18041823
if (errorParamIndex && paramI == *errorParamIndex) {
18051824
pushErrorPlaceholder();
@@ -1813,7 +1832,21 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
18131832
- (errorFlagIndex && paramI > *errorFlagIndex);
18141833
auto param = completionTy->getParameters()[paramI];
18151834
auto formalTy = formalTuple.getElementType(elementI);
1816-
auto argPiece = B.createTupleExtract(loc, asyncResult, elementI);
1835+
ManagedValue argPiece;
1836+
1837+
auto result = substConv.getResults()[elementI];
1838+
if (substConv.isSILIndirect(result)) {
1839+
// Take the arg piece from the indirect return arguments.
1840+
argPiece = emitManagedRValueWithCleanup(args[indirectResultI++]);
1841+
} else if (hasMultipleDirectResults) {
1842+
// Take the arg piece from one of the tuple elements of the direct
1843+
// result tuple from the apply.
1844+
argPiece = B.createTupleExtract(loc, asyncResult, directResultI++);
1845+
} else {
1846+
// Take the entire direct result from the apply as the arg piece.
1847+
argPiece = asyncResult;
1848+
}
1849+
18171850
pushArg(argPiece, formalTy, param);
18181851
}
18191852
}
@@ -1829,16 +1862,11 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
18291862
// The immediate function result is an empty tuple.
18301863
return SILUndef::get(SGM.Types.getEmptyTupleType(), F);
18311864
};
1832-
1865+
18331866
if (!substTy->hasErrorResult()) {
18341867
// Create the apply.
18351868
result = B.createApply(loc, nativeFn, subs, args);
1836-
1837-
if (substConv.hasIndirectSILResults()) {
1838-
assert(substTy->getNumResults() == 1);
1839-
result = args[0];
1840-
}
1841-
1869+
18421870
// Leave the argument cleanup scope immediately. This isn't really
18431871
// necessary; it just limits lifetimes a little bit more.
18441872
argScope.pop();
@@ -1849,6 +1877,10 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
18491877
if (foreignAsync) {
18501878
result = passResultToCompletionHandler(result);
18511879
} else {
1880+
if (substConv.hasIndirectSILResults()) {
1881+
assert(substTy->getNumResults() == 1);
1882+
result = args[0];
1883+
}
18521884
result = emitBridgeReturnValue(*this, loc, result, nativeFormalResultType,
18531885
bridgedFormalResultType, objcResultTy);
18541886
}
@@ -1864,17 +1896,16 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
18641896
SILValue nativeResult =
18651897
normalBB->createPhiArgument(swiftResultTy, OwnershipKind::Owned);
18661898

1867-
if (substConv.hasIndirectSILResults()) {
1868-
assert(substTy->getNumResults() == 1);
1869-
nativeResult = args[0];
1870-
}
1871-
18721899
if (foreignAsync) {
18731900
// If the function is async, pass the results as the success argument(s)
18741901
// to the completion handler, with a nil error.
18751902
passResultToCompletionHandler(nativeResult);
18761903
B.createBranch(loc, contBB);
18771904
} else {
1905+
if (substConv.hasIndirectSILResults()) {
1906+
assert(substTy->getNumResults() == 1);
1907+
nativeResult = args[0];
1908+
}
18781909
// In this branch, the eventual return value is mostly created
18791910
// by bridging the native return value, but we may need to
18801911
// adjust it slightly.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#import <Foundation.h>
2+
3+
#pragma clang assume_nonnull begin
4+
5+
@protocol NSButz
6+
7+
- (void)idString:(NSObject *)x replyHandler:(void (^)(id _Nullable reply, NSString *_Nullable errorMessage))replyHandler __attribute__((swift_async(not_swift_private, 2)));
8+
- (void)idStringID:(NSObject *)x replyHandler:(void (^)(id _Nullable reply, NSString *_Nullable errorMessage, id _Nullable reply2))replyHandler __attribute__((swift_async(not_swift_private, 2)));
9+
- (void)stringIDString:(NSObject *)x replyHandler:(void (^)(NSString *_Nullable errorMessage, id _Nullable reply, NSString *_Nullable errorMessage2))replyHandler __attribute__((swift_async(not_swift_private, 2)));
10+
- (void)idStringIDString:(NSObject *)x replyHandler:(void (^)(id _Nullable reply, NSString *_Nullable errorMessage, id _Nullable reply2, NSString *_Nullable errorMessage2))replyHandler __attribute__((swift_async(not_swift_private, 2)));
11+
12+
@end
13+
14+
#pragma clang assume_nonnull end
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-silgen -I %S/Inputs/custom-modules -import-objc-header %S/Inputs/objc_async_tuple_88949633.h -disable-availability-checking %s -verify
2+
// REQUIRES: concurrency
3+
// REQUIRES: objc_interop
4+
5+
// rdar://88949633
6+
7+
import Foundation
8+
import ObjCConcurrency
9+
10+
class Foo: NSObject, NSButz {
11+
func idString(_: NSObject) async -> (Any?, String?) {
12+
return (nil, nil)
13+
}
14+
func idStringID(_: NSObject) async -> (Any?, String?, Any?) {
15+
return (nil, nil, nil)
16+
}
17+
func stringIDString(_: NSObject) async -> (String?, Any?, String?) {
18+
return (nil, nil, nil)
19+
}
20+
func idStringIDString(_: NSObject) async -> (Any?, String?, Any?, String?) {
21+
return (nil, nil, nil, nil)
22+
}
23+
}
24+
25+

0 commit comments

Comments
 (0)