Skip to content

Commit bc09cc9

Browse files
committed
[SILGen] Handled foreign funcs with async, error, and more.
In 1ae317d, all the machinery was added to enable calling ObjC functions that have both async and error conventions. The handling that was added for matching up arguments and parameters, however, failed to handle functions that had both foreign async and foreign error and other arguments. Here, that handling is fixed. The fix is in four parts: - Reverting to a single call to CallSite::emit to emit the formal params. At this point, the foreign async and/or error params will be claimed as well. - Separately counting the async and error parameters in ParamLowering::claimParams to ensure we get the right parameter slices. - Letting ArgEmitter::maybeEmitForeignArgument look for an error parameter even if it already found an async parameter. - Letting ArgEmitter::maybeEmitForeignArgument keep looking for foreign arguments after it finds one. rdar://80704984
1 parent 9415bec commit bc09cc9

File tree

4 files changed

+163
-33
lines changed

4 files changed

+163
-33
lines changed

lib/SILGen/SILGenApply.cpp

Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3299,26 +3299,33 @@ class ArgEmitter {
32993299
}
33003300

33013301
void maybeEmitForeignArgument() {
3302-
if (Foreign.async
3303-
&& Foreign.async->completionHandlerParamIndex() == Args.size()) {
3304-
SILParameterInfo param = claimNextParameters(1).front();
3305-
(void)param;
3306-
3307-
// Leave a placeholder in the position. We'll fill this in with a block
3308-
// capturing the current continuation right before we invoke the
3309-
// function.
3310-
// (We can't do this immediately, because evaluating other arguments
3311-
// may require suspending the async task, which is not allowed while its
3312-
// continuation is active.)
3313-
Args.push_back(ManagedValue::forInContext());
3314-
} else if (Foreign.error
3315-
&& Foreign.error->getErrorParameterIndex() == Args.size()) {
3316-
SILParameterInfo param = claimNextParameters(1).front();
3317-
assert(param.getConvention() == ParameterConvention::Direct_Unowned);
3318-
(void) param;
3319-
3320-
// Leave a placeholder in the position.
3321-
Args.push_back(ManagedValue::forInContext());
3302+
bool keepGoing = true;
3303+
while (keepGoing) {
3304+
keepGoing = false;
3305+
if (Foreign.async &&
3306+
Foreign.async->completionHandlerParamIndex() == Args.size()) {
3307+
SILParameterInfo param = claimNextParameters(1).front();
3308+
(void)param;
3309+
3310+
// Leave a placeholder in the position. We'll fill this in with a block
3311+
// capturing the current continuation right before we invoke the
3312+
// function.
3313+
// (We can't do this immediately, because evaluating other arguments
3314+
// may require suspending the async task, which is not allowed while its
3315+
// continuation is active.)
3316+
Args.push_back(ManagedValue::forInContext());
3317+
keepGoing = true;
3318+
}
3319+
if (Foreign.error &&
3320+
Foreign.error->getErrorParameterIndex() == Args.size()) {
3321+
SILParameterInfo param = claimNextParameters(1).front();
3322+
assert(param.getConvention() == ParameterConvention::Direct_Unowned);
3323+
(void)param;
3324+
3325+
// Leave a placeholder in the position.
3326+
Args.push_back(ManagedValue::forInContext());
3327+
keepGoing = true;
3328+
}
33223329
}
33233330
}
33243331

@@ -3541,7 +3548,9 @@ struct ParamLowering {
35413548
}
35423549
}
35433550

3544-
if (foreign.error || foreign.async)
3551+
if (foreign.error)
3552+
++count;
3553+
if (foreign.async)
35453554
++count;
35463555

35473556
if (foreign.self.isImportAsMember()) {
@@ -4202,18 +4211,12 @@ ApplyOptions CallEmission::emitArgumentsForNormalApply(
42024211

42034212
args.push_back({});
42044213

4205-
if (!foreign.async || (foreign.async && foreign.error)) {
4206-
// Claim the foreign error argument(s) with the method formal params.
4207-
auto siteForeignError = ForeignInfo{{}, foreign.error, {}};
4208-
std::move(*callSite).emit(SGF, origFormalType, substFnType, paramLowering,
4209-
args.back(), delayedArgs, siteForeignError);
4210-
}
4211-
if (foreign.async) {
4212-
// Claim the foreign async argument(s) with the method formal params.
4213-
auto siteForeignAsync = ForeignInfo{{}, {}, foreign.async};
4214-
std::move(*callSite).emit(SGF, origFormalType, substFnType, paramLowering,
4215-
args.back(), delayedArgs, siteForeignAsync);
4216-
}
4214+
// Claim the foreign error and/or async arguments when claiming the formal
4215+
// params.
4216+
auto siteForeignError = ForeignInfo{{}, foreign.error, foreign.async};
4217+
// Claim the method formal params.
4218+
std::move(*callSite).emit(SGF, origFormalType, substFnType, paramLowering,
4219+
args.back(), delayedArgs, siteForeignError);
42174220
}
42184221

42194222
uncurriedLoc = callSite->Loc;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#include <Foundation/Foundation.h>
2+
3+
#pragma clang assume_nonnull begin
4+
5+
typedef void (^CompletionHandler)(int status, NSInteger bytesTransferred);
6+
7+
@interface PFXObject : NSObject
8+
- (BOOL)enqueueFailingRequestWithData:(nullable NSMutableData *)data
9+
error:(NSError *_Nullable *)error
10+
completionHandler:
11+
(nullable CompletionHandler)completionHandler;
12+
- (BOOL)enqueuePassingRequestWithData:(nullable NSMutableData *)data
13+
error:(NSError *_Nullable *)error
14+
completionHandler:
15+
(nullable CompletionHandler)completionHandler;
16+
- (BOOL)enqueueFailingRequestWithData:(nullable NSMutableData *)data
17+
completionTimeout:(NSTimeInterval)completionTimeout
18+
error:(NSError *_Nullable *)error
19+
completionHandler:
20+
(nullable CompletionHandler)completionHandler;
21+
- (BOOL)enqueuePassingRequestWithData:(nullable NSMutableData *)data
22+
completionTimeout:(NSTimeInterval)completionTimeout
23+
error:(NSError *_Nullable *)error
24+
completionHandler:
25+
(nullable CompletionHandler)completionHandler;
26+
@end
27+
28+
#pragma clang assume_nonnull end
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#include "rdar80704984_3.h"
2+
3+
#pragma clang assume_nonnull begin
4+
5+
@implementation PFXObject
6+
7+
- (BOOL)enqueueFailingRequestWithData:(nullable NSMutableData *)data
8+
error:(NSError *_Nullable *)error
9+
completionHandler:
10+
(nullable CompletionHandler)completionHandler {
11+
*error = [[NSError alloc] initWithDomain:@"d" code:1 userInfo:nil];
12+
return NO;
13+
}
14+
- (BOOL)enqueuePassingRequestWithData:(nullable NSMutableData *)data
15+
error:(NSError *_Nullable *)error
16+
completionHandler:
17+
(nullable CompletionHandler)completionHandler {
18+
dispatch_async(dispatch_get_main_queue(), ^{
19+
completionHandler(0, 2);
20+
});
21+
return YES;
22+
}
23+
24+
- (BOOL)enqueueFailingRequestWithData:(nullable NSMutableData *)data
25+
completionTimeout:(NSTimeInterval)completionTimeout
26+
error:(NSError *_Nullable *)error
27+
completionHandler:
28+
(nullable CompletionHandler)completionHandler {
29+
*error = [[NSError alloc] initWithDomain:@"d" code:2 userInfo:nil];
30+
return NO;
31+
}
32+
- (BOOL)enqueuePassingRequestWithData:(nullable NSMutableData *)data
33+
completionTimeout:(NSTimeInterval)completionTimeout
34+
error:(NSError *_Nullable *)error
35+
completionHandler:
36+
(nullable CompletionHandler)completionHandler {
37+
dispatch_async(dispatch_get_main_queue(), ^{
38+
completionHandler(0, 3);
39+
});
40+
return YES;
41+
}
42+
43+
@end
44+
45+
#pragma clang assume_nonnull end
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-clang %S/Inputs/rdar80704984_3.m -I %S/Inputs -c -o %t/rdar80704984_3.o
3+
// RUN: %target-build-swift -Xfrontend -disable-availability-checking -import-objc-header %S/Inputs/rdar80704984_3.h -Xlinker %t/rdar80704984_3.o -parse-as-library %s -o %t/a.out
4+
// RUN: %target-codesign %t/a.out
5+
// RUN: %target-run %t/a.out | %FileCheck %s
6+
7+
// REQUIRES: executable_test
8+
// REQUIRES: objc_interop
9+
10+
// rdar://82123254
11+
// UNSUPPORTED: use_os_stdlib
12+
// UNSUPPORTED: back_deployment_runtime
13+
14+
func run1(on object: PFXObject) async throws {
15+
do {
16+
_ = try await object.enqueueFailingRequest(with: nil)
17+
}
18+
catch let error {
19+
// CHECK: Domain=d Code=1
20+
print(error)
21+
}
22+
}
23+
24+
func run2(on object: PFXObject) async throws {
25+
// CHECK: (0, 2)
26+
print(try await object.enqueuePassingRequest(with: nil))
27+
28+
}
29+
30+
func run3(on object: PFXObject) async throws {
31+
do {
32+
_ = try await object.enqueueFailingRequest(with: nil, completionTimeout: 57.0)
33+
}
34+
catch let error {
35+
// CHECK: Domain=d Code=2
36+
print(error)
37+
}
38+
}
39+
40+
func run4(on object: PFXObject) async throws {
41+
// CHECK: (0, 3)
42+
print(try await object.enqueuePassingRequest(with: nil, completionTimeout: 57.0))
43+
44+
}
45+
46+
@main struct Main {
47+
static func main() async throws {
48+
let object = PFXObject()
49+
try await run1(on: object)
50+
try await run2(on: object)
51+
try await run3(on: object)
52+
try await run4(on: object)
53+
}
54+
}

0 commit comments

Comments
 (0)