Skip to content

Commit 8345174

Browse files
Merge pull request swiftlang#38370 from nate-chandler/rdar79383990
[SILGen] Used formal type when bridging completion handler arguments.
2 parents 41a1761 + c493632 commit 8345174

File tree

14 files changed

+132
-63
lines changed

14 files changed

+132
-63
lines changed

include/swift/SIL/AbstractionPattern.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,6 +1378,13 @@ class AbstractionPattern {
13781378
/// Swift type.
13791379
AbstractionPattern getObjCMethodAsyncCompletionHandlerType(
13801380
CanType swiftCompletionHandlerType) const;
1381+
1382+
/// If this pattern refers to a foreign ObjC method that was imported as
1383+
/// async, return the bridged-back-to-ObjC completion handler type.
1384+
CanType getObjCMethodAsyncCompletionHandlerForeignType(
1385+
ForeignAsyncConvention convention,
1386+
Lowering::TypeConverter &TC
1387+
) const;
13811388

13821389
void dump() const LLVM_ATTRIBUTE_USED;
13831390
void print(raw_ostream &OS) const;

lib/SIL/IR/AbstractionPattern.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,30 @@ AbstractionPattern::getObjCMethodAsyncCompletionHandlerType(
662662
llvm_unreachable("covered switch");
663663
}
664664

665+
666+
CanType AbstractionPattern::getObjCMethodAsyncCompletionHandlerForeignType(
667+
ForeignAsyncConvention convention,
668+
Lowering::TypeConverter &TC
669+
) const {
670+
auto nativeCHTy = convention.completionHandlerType();
671+
672+
// Use the abstraction pattern we're lowering against in order to lower
673+
// the completion handler type, so we can preserve C/ObjC distinctions that
674+
// normally get abstracted away by the importer.
675+
auto completionHandlerNativeOrigTy = getObjCMethodAsyncCompletionHandlerType(nativeCHTy);
676+
677+
// Bridge the Swift completion handler type back to its
678+
// foreign representation.
679+
auto foreignCHTy = TC.getLoweredBridgedType(completionHandlerNativeOrigTy,
680+
nativeCHTy,
681+
Bridgeability::Full,
682+
SILFunctionTypeRepresentation::ObjCMethod,
683+
TypeConverter::ForArgument)
684+
->getCanonicalType();
685+
686+
return foreignCHTy;
687+
}
688+
665689
AbstractionPattern
666690
AbstractionPattern::getFunctionParamType(unsigned index) const {
667691
switch (getKind()) {

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1674,25 +1674,9 @@ class DestructureInputs {
16741674
|| NextOrigParamIndex != Foreign.Async->completionHandlerParamIndex())
16751675
return false;
16761676

1677-
auto nativeCHTy = Foreign.Async->completionHandlerType();
1678-
1679-
// Use the abstraction pattern we're lowering against in order to lower
1680-
// the completion handler type, so we can preserve C/ObjC distinctions that
1681-
// normally get abstracted away by the importer.
1682-
auto completionHandlerNativeOrigTy = TopLevelOrigType
1683-
.getObjCMethodAsyncCompletionHandlerType(nativeCHTy);
1684-
1685-
// Bridge the Swift completion handler type back to its
1686-
// foreign representation.
1687-
auto foreignCHTy = TC.getLoweredBridgedType(completionHandlerNativeOrigTy,
1688-
nativeCHTy,
1689-
Bridgeability::Full,
1690-
SILFunctionTypeRepresentation::ObjCMethod,
1691-
TypeConverter::ForArgument)
1692-
->getCanonicalType();
1693-
1694-
auto completionHandlerOrigTy = TopLevelOrigType
1695-
.getObjCMethodAsyncCompletionHandlerType(foreignCHTy);
1677+
CanType foreignCHTy = TopLevelOrigType
1678+
.getObjCMethodAsyncCompletionHandlerForeignType(Foreign.Async.getValue(), TC);
1679+
auto completionHandlerOrigTy = TopLevelOrigType.getObjCMethodAsyncCompletionHandlerType(foreignCHTy);
16961680
auto completionHandlerTy = TC.getLoweredType(completionHandlerOrigTy,
16971681
foreignCHTy, expansion)
16981682
.getASTType();

lib/SIL/IR/SILInstructions.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2822,7 +2822,7 @@ SILType GetAsyncContinuationInstBase::getLoweredResumeType() const {
28222822
auto formalType = getFormalResumeType();
28232823
auto &M = getFunction()->getModule();
28242824
auto c = getFunction()->getTypeExpansionContext();
2825-
return M.Types.getLoweredType(AbstractionPattern::getOpaque(), formalType, c);
2825+
return M.Types.getLoweredType(AbstractionPattern(formalType), formalType, c);
28262826
}
28272827

28282828
ReturnInst::ReturnInst(SILFunction &func, SILDebugLocation debugLoc,

lib/SILGen/Callee.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ namespace Lowering {
2323

2424
class CalleeTypeInfo {
2525
public:
26+
Optional<AbstractionPattern> origFormalType;
2627
CanSILFunctionType substFnType;
2728
Optional<AbstractionPattern> origResultType;
2829
CanType substResultType;
@@ -45,17 +46,18 @@ class CalleeTypeInfo {
4546
const Optional<ForeignAsyncConvention> &foreignAsync,
4647
ImportAsMemberStatus foreignSelf,
4748
Optional<SILFunctionTypeRepresentation> overrideRep = None)
48-
: substFnType(substFnType), origResultType(origResultType),
49-
substResultType(substResultType),
50-
foreign{foreignError, foreignAsync, foreignSelf},
49+
: origFormalType(llvm::None), substFnType(substFnType),
50+
origResultType(origResultType),
51+
substResultType(substResultType), foreign{foreignError, foreignAsync,
52+
foreignSelf},
5153
overrideRep(overrideRep) {}
5254

5355
CalleeTypeInfo(CanSILFunctionType substFnType,
5456
AbstractionPattern origResultType, CanType substResultType,
5557
Optional<SILFunctionTypeRepresentation> overrideRep = None)
56-
: substFnType(substFnType), origResultType(origResultType),
57-
substResultType(substResultType), foreign(),
58-
overrideRep(overrideRep) {}
58+
: origFormalType(llvm::None), substFnType(substFnType),
59+
origResultType(origResultType), substResultType(substResultType),
60+
foreign(), overrideRep(overrideRep) {}
5961

6062
SILFunctionTypeRepresentation getOverrideRep() const {
6163
return overrideRep.getValueOr(substFnType->getRepresentation());

lib/SILGen/ResultPlan.cpp

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -465,8 +465,9 @@ class ForeignAsyncInitializationPlan final : public ResultPlan {
465465
{
466466
// Allocate space to receive the resume value when the continuation is
467467
// resumed.
468-
opaqueResumeType = SGF.getLoweredType(AbstractionPattern::getOpaque(),
469-
calleeTypeInfo.substResultType);
468+
opaqueResumeType =
469+
SGF.getLoweredType(AbstractionPattern(calleeTypeInfo.substResultType),
470+
calleeTypeInfo.substResultType);
470471
resumeBuf = SGF.emitTemporaryAllocation(loc, opaqueResumeType);
471472
}
472473

@@ -475,10 +476,11 @@ class ForeignAsyncInitializationPlan final : public ResultPlan {
475476
SmallVectorImpl<SILValue> &outList) const override {
476477
// A foreign async function shouldn't have any indirect results.
477478
}
478-
479+
479480
ManagedValue
480-
emitForeignAsyncCompletionHandler(SILGenFunction &SGF, SILLocation loc)
481-
override {
481+
emitForeignAsyncCompletionHandler(SILGenFunction &SGF,
482+
AbstractionPattern origFormalType,
483+
SILLocation loc) override {
482484
// Get the current continuation for the task.
483485
bool throws = calleeTypeInfo.foreign.async
484486
->completionHandlerErrorParamIndex().hasValue();
@@ -527,13 +529,12 @@ class ForeignAsyncInitializationPlan final : public ResultPlan {
527529
auto env = SGF.F.getGenericEnvironment();
528530
auto sig = env ? env->getGenericSignature().getCanonicalSignature()
529531
: CanGenericSignature();
530-
SILFunction *impl = SGF.SGM
531-
.getOrCreateForeignAsyncCompletionHandlerImplFunction(
532-
cast<SILFunctionType>(impFnTy->mapTypeOutOfContext()
533-
->getCanonicalType(sig)),
534-
continuationTy->mapTypeOutOfContext()->getCanonicalType(sig),
535-
sig,
536-
*calleeTypeInfo.foreign.async);
532+
SILFunction *impl =
533+
SGF.SGM.getOrCreateForeignAsyncCompletionHandlerImplFunction(
534+
cast<SILFunctionType>(
535+
impFnTy->mapTypeOutOfContext()->getCanonicalType(sig)),
536+
continuationTy->mapTypeOutOfContext()->getCanonicalType(sig),
537+
origFormalType, sig, *calleeTypeInfo.foreign.async);
537538
auto impRef = SGF.B.createFunctionRef(loc, impl);
538539

539540
// Initialize the block object for the completion handler.
@@ -551,7 +552,7 @@ class ForeignAsyncInitializationPlan final : public ResultPlan {
551552
// _Block_copy-ing it.
552553
return ManagedValue::forUnmanaged(block);
553554
}
554-
555+
555556
RValue finish(SILGenFunction &SGF, SILLocation loc, CanType substType,
556557
ArrayRef<ManagedValue> &directResults) override {
557558
// There should be no direct results from the call.

lib/SILGen/ResultPlan.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ class ResultPlan {
4949
emitForeignErrorArgument(SILGenFunction &SGF, SILLocation loc) {
5050
return None;
5151
}
52-
53-
virtual ManagedValue
54-
emitForeignAsyncCompletionHandler(SILGenFunction &SGF, SILLocation loc) {
52+
53+
virtual ManagedValue emitForeignAsyncCompletionHandler(
54+
SILGenFunction &SGF, AbstractionPattern origFormalType, SILLocation loc) {
5555
return {};
5656
}
5757
};

lib/SILGen/SILGen.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -182,10 +182,9 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
182182
/// implementation function for an ObjC API that was imported
183183
/// as `async` in Swift.
184184
SILFunction *getOrCreateForeignAsyncCompletionHandlerImplFunction(
185-
CanSILFunctionType blockType,
186-
CanType continuationTy,
187-
CanGenericSignature sig,
188-
ForeignAsyncConvention convention);
185+
CanSILFunctionType blockType, CanType continuationTy,
186+
AbstractionPattern origFormalType, CanGenericSignature sig,
187+
ForeignAsyncConvention convention);
189188

190189
/// Determine whether the given class has any instance variables that
191190
/// need to be destroyed.

lib/SILGen/SILGenApply.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3894,6 +3894,8 @@ RValue CallEmission::applyNormalCall(SGFContext C) {
38943894
// Get the callee type information.
38953895
auto calleeTypeInfo = callee.getTypeInfo(SGF);
38963896

3897+
calleeTypeInfo.origFormalType = origFormalType;
3898+
38973899
// In C language modes, substitute the type of the AbstractionPattern
38983900
// so that we won't see type parameters down when we try to form bridging
38993901
// conversions.
@@ -3911,6 +3913,8 @@ RValue CallEmission::applyNormalCall(SGFContext C) {
39113913
calleeTypeInfo.substResultType = formalType.getResult();
39123914

39133915
if (selfArg.hasValue() && callSite.hasValue()) {
3916+
calleeTypeInfo.origFormalType =
3917+
calleeTypeInfo.origFormalType->getFunctionResultType();
39143918
calleeTypeInfo.origResultType =
39153919
calleeTypeInfo.origResultType->getFunctionResultType();
39163920
calleeTypeInfo.substResultType =
@@ -4401,7 +4405,9 @@ RValue SILGenFunction::emitApply(
44014405
// we left during the first pass.
44024406
auto &completionArgSlot = const_cast<ManagedValue &>(args[completionIndex]);
44034407

4404-
completionArgSlot = resultPlan->emitForeignAsyncCompletionHandler(*this, loc);
4408+
auto origFormalType = *calleeTypeInfo.origFormalType;
4409+
completionArgSlot = resultPlan->emitForeignAsyncCompletionHandler(
4410+
*this, origFormalType, loc);
44054411

44064412
} else if (auto foreignError = calleeTypeInfo.foreign.error) {
44074413
unsigned errorParamIndex =

lib/SILGen/SILGenBridging.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2389,6 +2389,8 @@ void SILGenFunction::emitForeignToNativeThunk(SILDeclRef thunk) {
23892389
foreignError,
23902390
foreignAsync,
23912391
ImportAsMemberStatus());
2392+
calleeTypeInfo.origFormalType =
2393+
foreignCI.FormalPattern.getFunctionResultType();
23922394

23932395
auto init = indirectResult
23942396
? useBufferAsTemporary(indirectResult,

lib/SILGen/SILGenThunk.cpp

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -188,15 +188,28 @@ static const clang::Type *prependParameterType(
188188
return clangCtx.getPointerType(newFnTy).getTypePtr();
189189
}
190190

191-
SILFunction *
192-
SILGenModule::getOrCreateForeignAsyncCompletionHandlerImplFunction(
193-
CanSILFunctionType blockType,
194-
CanType continuationTy,
195-
CanGenericSignature sig,
196-
ForeignAsyncConvention convention) {
191+
SILFunction *SILGenModule::getOrCreateForeignAsyncCompletionHandlerImplFunction(
192+
CanSILFunctionType blockType, CanType continuationTy,
193+
AbstractionPattern origFormalType, CanGenericSignature sig,
194+
ForeignAsyncConvention convention) {
197195
// Extract the result and error types from the continuation type.
198196
auto resumeType = cast<BoundGenericType>(continuationTy).getGenericArgs()[0];
199197

198+
CanAnyFunctionType completionHandlerOrigTy = [&]() {
199+
auto completionHandlerOrigTy =
200+
origFormalType.getObjCMethodAsyncCompletionHandlerForeignType(convention, Types);
201+
Optional<CanAnyFunctionType> maybeCompletionHandlerOrigTy;
202+
if (auto fnTy =
203+
dyn_cast<AnyFunctionType>(completionHandlerOrigTy)) {
204+
maybeCompletionHandlerOrigTy = fnTy;
205+
} else {
206+
maybeCompletionHandlerOrigTy = cast<AnyFunctionType>(
207+
completionHandlerOrigTy.getOptionalObjectType());
208+
}
209+
return maybeCompletionHandlerOrigTy.getValue();
210+
}();
211+
auto blockParams = completionHandlerOrigTy.getParams();
212+
200213
// Build up the implementation function type, which matches the
201214
// block signature with an added block storage argument that points at the
202215
// block buffer. The block storage holds the continuation we feed the
@@ -214,7 +227,7 @@ SILGenModule::getOrCreateForeignAsyncCompletionHandlerImplFunction(
214227
getASTContext(),
215228
blockType->getClangTypeInfo().getType(),
216229
getASTContext().getClangTypeForIRGen(blockStorageTy));
217-
230+
218231
auto implTy = SILFunctionType::get(sig,
219232
blockType->getExtInfo().intoBuilder()
220233
.withRepresentation(SILFunctionTypeRepresentation::CFunctionPointer)
@@ -361,15 +374,13 @@ SILGenModule::getOrCreateForeignAsyncCompletionHandlerImplFunction(
361374
auto resumeArgBuf = SGF.emitTemporaryAllocation(loc,
362375
loweredResumeTy.getAddressType());
363376

364-
auto prepareArgument = [&](SILValue destBuf, ManagedValue arg) {
377+
auto prepareArgument = [&](SILValue destBuf, CanType destFormalType,
378+
ManagedValue arg, CanType argFormalType) {
365379
// Convert the ObjC argument to the bridged Swift representation we
366380
// want.
367-
ManagedValue bridgedArg = SGF.emitBridgedToNativeValue(loc,
368-
arg.copy(SGF, loc),
369-
arg.getType().getASTType(),
370-
// FIXME: pass down formal type
371-
destBuf->getType().getASTType(),
372-
destBuf->getType().getObjectType());
381+
ManagedValue bridgedArg = SGF.emitBridgedToNativeValue(
382+
loc, arg.copy(SGF, loc), argFormalType, destFormalType,
383+
destBuf->getType().getObjectType());
373384
// Force-unwrap an argument that comes to us as Optional if it's
374385
// formally non-optional in the return.
375386
if (bridgedArg.getType().getOptionalObjectType()
@@ -400,12 +411,22 @@ SILGenModule::getOrCreateForeignAsyncCompletionHandlerImplFunction(
400411
for (unsigned i : indices(resumeTuple.getElementTypes())) {
401412
auto resumeEltBuf = SGF.B.createTupleElementAddr(loc,
402413
resumeArgBuf, i);
403-
prepareArgument(resumeEltBuf, params[paramIndices[i]]);
414+
prepareArgument(
415+
/*destBuf*/ resumeEltBuf,
416+
/*destFormalType*/
417+
F->mapTypeIntoContext(resumeTuple.getElementTypes()[i])
418+
->getCanonicalType(),
419+
/*arg*/ params[paramIndices[i]],
420+
/*argFormalType*/ blockParams[i].getParameterType());
404421
}
405422
} else {
406423
assert(paramIndices.size() == 1);
407424
assert(params.size() == 2 + (bool)errorIndex + (bool)flagIndex);
408-
prepareArgument(resumeArgBuf, params[paramIndices[0]]);
425+
prepareArgument(/*destBuf*/ resumeArgBuf,
426+
/*destFormalType*/
427+
F->mapTypeIntoContext(resumeType)->getCanonicalType(),
428+
/*arg*/ params[paramIndices[0]],
429+
/*argFormalType*/ blockParams[0].getParameterType());
409430
}
410431

411432
// Resume the continuation with the composed bridged result.

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ typedef void (^CompletionHandler)(NSString * _Nullable, NSString * _Nullable_res
5757
// rdar://73798726
5858
- (void)getSomeObjectWithCompletionHandler:(nullable void (^)(NSObject *_Nullable x, NSError *_Nullable error))handler;
5959

60+
- (void)performVoid2VoidWithCompletion:(void (^ _Nonnull)(void (^ _Nonnull)(void)))completion;
61+
- (void)performId2VoidWithCompletion:(void (^ _Nonnull)(void (^ _Nonnull)(id _Nonnull)))completion;
62+
- (void)performId2IdWithCompletion:(void (^ _Nonnull)(id _Nonnull (^ _Nonnull)(id _Nonnull)))completion;
63+
- (void)performNSString2NSStringWithCompletion:(void (^ _Nonnull)(NSString * _Nonnull (^ _Nonnull)(NSString * _Nonnull)))completion;
64+
- (void)performNSString2NSStringNSStringWithCompletion:(void (^ _Nonnull)(NSString * _Nonnull (^ _Nonnull)(NSString * _Nonnull), NSString * _Nonnull))completion;
65+
- (void)performId2VoidId2VoidWithCompletion:(void (^ _Nonnull)(void (^ _Nonnull)(id _Nonnull), void (^ _Nonnull)(id _Nonnull)))completion;
66+
6067
-(void)oldAPIWithCompletionHandler:(void (^ _Nonnull)(NSString *_Nullable, NSError *_Nullable))handler __attribute__((availability(macosx, deprecated=10.14)));
6168

6269
-(void)someAsyncMethodWithBlock:(void (^ _Nonnull)(NSString *_Nullable, NSError *_Nullable))completionHandler;

test/SILGen/objc_async.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ func testSlowServer(slowServer: SlowServer) async throws {
7676
let _: NSObject? = try await slowServer.stopRecording()
7777
let _: NSObject = try await slowServer.someObject()
7878

79+
let _: () -> Void = await slowServer.performVoid2Void()
80+
let _: (Any) -> Void = await slowServer.performId2Void()
81+
let _: (Any) -> Any = await slowServer.performId2Id()
82+
let _: (String) -> String = await slowServer.performNSString2NSString()
83+
84+
let _: ((String) -> String, String) = await slowServer.performNSString2NSStringNSString()
85+
let _: ((Any) -> Void, (Any) -> Void) = await slowServer.performId2VoidId2Void()
7986
}
8087

8188
func testGeneric<T: AnyObject>(x: GenericObject<T>) async throws {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %target-swift-frontend %s -emit-silgen -disable-availability-checking
2+
// REQUIRES: objc_interop
3+
// REQUIRES: OS=macosx
4+
5+
import Foundation
6+
7+
func test(s: NSBackgroundActivityScheduler) async {
8+
_ = await s.schedule()
9+
}

0 commit comments

Comments
 (0)