Skip to content

Commit 77265ed

Browse files
committed
[SIL] Move type fixups into SILBuilder::getPartialApplyResultType.
We do clever tricks to avoid having to serialize the full type of a partial_apply instruction, but those conflicted with our clever tricks for handling unusual return conventions. Make sure we do all type calculations for partial_apply in one place. (Credit to Slava for both introducing the problem and immediately seeing how to fix it.) This should allow re-application of e6a519f and 86dcce1.
1 parent e56e0f6 commit 77265ed

File tree

4 files changed

+76
-32
lines changed

4 files changed

+76
-32
lines changed

lib/SIL/SILBuilder.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,29 @@ SILType SILBuilder::getPartialApplyResultType(SILType origTy, unsigned argCount,
4343
auto extInfo = SILFunctionType::ExtInfo(
4444
SILFunctionType::Representation::Thick,
4545
/*noreturn*/ FTI->isNoReturn());
46-
46+
47+
// If the original method has an @unowned_inner_pointer return, the partial
48+
// application thunk will lifetime-extend 'self' for us, converting the
49+
// return value to @unowned.
50+
//
51+
// If the original method has an @autoreleased return, the partial application
52+
// thunk will retain it for us, converting the return value to @owned.
53+
SmallVector<SILResultInfo, 4> results;
54+
results.append(FTI->getAllResults().begin(), FTI->getAllResults().end());
55+
for (auto &result : results) {
56+
if (result.getConvention() == ResultConvention::UnownedInnerPointer)
57+
result = SILResultInfo(result.getType(), ResultConvention::Unowned);
58+
else if (result.getConvention() == ResultConvention::Autoreleased)
59+
result = SILResultInfo(result.getType(), ResultConvention::Owned);
60+
}
61+
4762
auto appliedFnType = SILFunctionType::get(nullptr, extInfo,
4863
ParameterConvention::Direct_Owned,
4964
newParams,
50-
FTI->getAllResults(),
65+
results,
5166
FTI->getOptionalErrorResult(),
5267
M.getASTContext());
68+
5369
return SILType::getPrimitiveObjectType(appliedFnType);
5470
}
5571

lib/SILGen/SILGenApply.cpp

Lines changed: 6 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4577,34 +4577,10 @@ static SILValue emitDynamicPartialApply(SILGenFunction &gen,
45774577
SILValue method,
45784578
SILValue self,
45794579
CanFunctionType methodTy) {
4580-
// Pop the self type off of the function type.
4581-
// Just to be weird, partially applying an objc method produces a native
4582-
// function (?!)
4583-
auto fnTy = method->getType().castTo<SILFunctionType>();
4584-
4585-
// If the original method has an @unowned_inner_pointer return, the partial
4586-
// application thunk will lifetime-extend 'self' for us, converting the
4587-
// return value to @unowned.
4588-
//
4589-
// If the original method has an @autoreleased return, the partial application
4590-
// thunk will retain it for us, converting the return value to @owned.
4591-
SmallVector<SILResultInfo, 4> results;
4592-
results.append(fnTy->getAllResults().begin(), fnTy->getAllResults().end());
4593-
for (auto &result : results) {
4594-
if (result.getConvention() == ResultConvention::UnownedInnerPointer)
4595-
result = SILResultInfo(result.getType(), ResultConvention::Unowned);
4596-
else if (result.getConvention() == ResultConvention::Autoreleased)
4597-
result = SILResultInfo(result.getType(), ResultConvention::Owned);
4598-
}
4599-
4600-
auto partialApplyTy = SILFunctionType::get(fnTy->getGenericSignature(),
4601-
fnTy->getExtInfo()
4602-
.withRepresentation(SILFunctionType::Representation::Thick),
4603-
ParameterConvention::Direct_Owned,
4604-
fnTy->getParameters()
4605-
.slice(0, fnTy->getParameters().size() - 1),
4606-
results, fnTy->getOptionalErrorResult(),
4607-
gen.getASTContext());
4580+
auto partialApplyTy = SILBuilder::getPartialApplyResultType(method->getType(),
4581+
/*argCount*/1,
4582+
gen.SGM.M,
4583+
/*subs*/{});
46084584

46094585
// Retain 'self' because the partial apply will take ownership.
46104586
// We can't simply forward 'self' because the partial apply is conditional.
@@ -4618,11 +4594,11 @@ static SILValue emitDynamicPartialApply(SILGenFunction &gen,
46184594
#endif
46194595

46204596
SILValue result = gen.B.createPartialApply(loc, method, method->getType(), {},
4621-
self, SILType::getPrimitiveObjectType(partialApplyTy));
4597+
self, partialApplyTy);
46224598
// If necessary, thunk to the native ownership conventions and bridged types.
46234599
auto nativeTy = gen.getLoweredLoadableType(methodTy).castTo<SILFunctionType>();
46244600

4625-
if (nativeTy != partialApplyTy) {
4601+
if (nativeTy != partialApplyTy.getSwiftRValueType()) {
46264602
result = gen.emitBlockToFunc(loc, ManagedValue::forUnmanaged(result),
46274603
nativeTy).forward(gen);
46284604
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
@protocol Test
2+
@optional
3+
- (nonnull id)normalObject;
4+
- (nonnull void *)innerPointer __attribute__((objc_returns_inner_pointer));
5+
@property (nonnull) id normalObjectProp;
6+
@property (nonnull) void *innerPointerProp __attribute__((objc_returns_inner_pointer));
7+
@end
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: rm -rf %t && mkdir -p %t
2+
// RUN: %target-swift-frontend -emit-module-path %t/Test.swiftmodule -emit-sil -o /dev/null -module-name Test %s -sdk "" -import-objc-header %S/Inputs/serialization-sil.h
3+
// RUN: %target-sil-extract %t/Test.swiftmodule -func=_TF4Test16testPartialApplyFPSo4Test_T_ -o - | FileCheck %s
4+
5+
// REQUIRES: objc_interop
6+
7+
// @_transparent to force serialization.
8+
@_transparent
9+
public func testPartialApply(obj: Test) {
10+
// CHECK-LABEL: @_TF4Test16testPartialApplyFPSo4Test_T_ : $@convention(thin) (@owned Test) -> () {
11+
if let curried1 = obj.normalObject {
12+
// CHECK: dynamic_method_br [[CURRIED1_OBJ:%.+]] : $@opened([[CURRIED1_EXISTENTIAL:.+]]) Test, #Test.normalObject!1.foreign, [[CURRIED1_TRUE:[^,]+]], [[CURRIED1_FALSE:[^,]+]]
13+
// CHECK: [[CURRIED1_TRUE]]([[CURRIED1_METHOD:%.+]] : $@convention(objc_method) (@opened([[CURRIED1_EXISTENTIAL]]) Test) -> @autoreleased AnyObject):
14+
// CHECK: [[CURRIED1_PARTIAL:%.+]] = partial_apply [[CURRIED1_METHOD]]([[CURRIED1_OBJ]]) : $@convention(objc_method) (@opened([[CURRIED1_EXISTENTIAL]]) Test) -> @autoreleased AnyObject
15+
// CHECK: [[CURRIED1_THUNK:%.+]] = function_ref @_TTRXFo__oPs9AnyObject__XFo_iT__iPS___ : $@convention(thin) (@in (), @owned @callee_owned () -> @owned AnyObject) -> @out AnyObject
16+
// CHECK: = partial_apply [[CURRIED1_THUNK]]([[CURRIED1_PARTIAL]]) : $@convention(thin) (@in (), @owned @callee_owned () -> @owned AnyObject) -> @out AnyObject
17+
// CHECK: [[CURRIED1_FALSE]]:
18+
curried1()
19+
}
20+
if let curried2 = obj.innerPointer {
21+
// CHECK: dynamic_method_br [[CURRIED2_OBJ:%.+]] : $@opened([[CURRIED2_EXISTENTIAL:.+]]) Test, #Test.innerPointer!1.foreign, [[CURRIED2_TRUE:[^,]+]], [[CURRIED2_FALSE:[^,]+]]
22+
// CHECK: [[CURRIED2_TRUE]]([[CURRIED2_METHOD:%.+]] : $@convention(objc_method) (@opened([[CURRIED2_EXISTENTIAL]]) Test) -> @unowned_inner_pointer UnsafeMutablePointer<()>):
23+
// CHECK: [[CURRIED2_PARTIAL:%.+]] = partial_apply [[CURRIED2_METHOD]]([[CURRIED2_OBJ]]) : $@convention(objc_method) (@opened([[CURRIED2_EXISTENTIAL]]) Test) -> @unowned_inner_pointer UnsafeMutablePointer<()>
24+
// CHECK: [[CURRIED2_THUNK:%.+]] = function_ref @_TTRXFo__dGSpT___XFo_iT__iGSpT___ : $@convention(thin) (@in (), @owned @callee_owned () -> UnsafeMutablePointer<()>) -> @out UnsafeMutablePointer<()>
25+
// CHECK: = partial_apply [[CURRIED2_THUNK]]([[CURRIED2_PARTIAL]]) : $@convention(thin) (@in (), @owned @callee_owned () -> UnsafeMutablePointer<()>) -> @out UnsafeMutablePointer<()>
26+
// CHECK: [[CURRIED2_FALSE]]:
27+
curried2()
28+
}
29+
if let prop1 = obj.normalObjectProp {
30+
// CHECK: dynamic_method_br [[PROP1_OBJ:%.+]] : $@opened([[PROP1_EXISTENTIAL:.+]]) Test, #Test.normalObjectProp!getter.1.foreign, [[PROP1_TRUE:[^,]+]], [[PROP1_FALSE:[^,]+]]
31+
// CHECK: [[PROP1_TRUE]]([[PROP1_METHOD:%.+]] : $@convention(objc_method) (@opened([[PROP1_EXISTENTIAL]]) Test) -> @autoreleased AnyObject):
32+
// CHECK: [[PROP1_PARTIAL:%.+]] = partial_apply [[PROP1_METHOD]]([[PROP1_OBJ]]) : $@convention(objc_method) (@opened([[PROP1_EXISTENTIAL]]) Test) -> @autoreleased AnyObject
33+
// CHECK: = apply [[PROP1_PARTIAL]]() : $@callee_owned () -> @owned AnyObject
34+
// CHECK: [[PROP1_FALSE]]:
35+
_ = prop1
36+
}
37+
if let prop2 = obj.innerPointerProp {
38+
// CHECK: dynamic_method_br [[PROP2_OBJ:%.+]] : $@opened([[PROP2_EXISTENTIAL:.+]]) Test, #Test.innerPointerProp!getter.1.foreign, [[PROP2_TRUE:[^,]+]], [[PROP2_FALSE:[^,]+]]
39+
// CHECK: [[PROP2_TRUE]]([[PROP2_METHOD:%.+]] : $@convention(objc_method) (@opened([[PROP2_EXISTENTIAL]]) Test) -> @unowned_inner_pointer UnsafeMutablePointer<()>):
40+
// CHECK: [[PROP2_PARTIAL:%.+]] = partial_apply [[PROP2_METHOD]]([[PROP2_OBJ]]) : $@convention(objc_method) (@opened([[PROP2_EXISTENTIAL]]) Test) -> @unowned_inner_pointer UnsafeMutablePointer<()>
41+
// CHECK: = apply [[PROP2_PARTIAL]]() : $@callee_owned () -> UnsafeMutablePointer<()>
42+
// CHECK: [[PROP2_FALSE]]:
43+
_ = prop2
44+
}
45+
} // CHECK: {{^}$}}

0 commit comments

Comments
 (0)