Skip to content

Commit 2a59ad7

Browse files
committed
SIL: Add support for capturing the dynamic Self metatype
If a closure captures the dynamic 'Self' type, but no value of type 'Self' (for example, it is possible to have a weak capture of 'self'; if the weak reference becomes nil, there's no way for the closure to get the dynamic 'Self' type from the value). In this case, add a hidden argument of type $Self.Type, and pass in the Self metatype. Fixes <https://bugs.swift.org/browse/SR-1558> / <rdar://problem/22299905>.
1 parent b246d09 commit 2a59ad7

File tree

8 files changed

+211
-12
lines changed

8 files changed

+211
-12
lines changed

lib/SIL/SILFunctionType.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,18 @@ static CanSILFunctionType getSILFunctionType(SILModule &M,
735735
auto loweredCaptures = Types.getLoweredLocalCaptures(*function);
736736

737737
for (auto capture : loweredCaptures.getCaptures()) {
738+
if (capture.isDynamicSelfMetadata()) {
739+
ParameterConvention convention = ParameterConvention::Direct_Unowned;
740+
auto selfMetatype = MetatypeType::get(
741+
loweredCaptures.getDynamicSelfType()->getSelfType(),
742+
MetatypeRepresentation::Thick)
743+
->getCanonicalType();
744+
SILParameterInfo param(selfMetatype, convention);
745+
inputs.push_back(param);
746+
747+
continue;
748+
}
749+
738750
auto *VD = capture.getDecl();
739751
auto type = VD->getType()->getCanonicalType();
740752

lib/SIL/SILVerifier.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,6 +1326,23 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
13261326
if (auto dynamicSelf = dyn_cast<DynamicSelfType>(formalType))
13271327
formalType = CanType(dynamicSelf->getSelfType());
13281328

1329+
// Optional of dynamic self has the same lowering as its contained type.
1330+
OptionalTypeKind loweredOptionalKind;
1331+
OptionalTypeKind formalOptionalKind;
1332+
1333+
CanType loweredObjectType = loweredType.getSwiftRValueType()
1334+
.getAnyOptionalObjectType(loweredOptionalKind);
1335+
CanType formalObjectType = formalType
1336+
.getAnyOptionalObjectType(formalOptionalKind);
1337+
1338+
if (loweredOptionalKind != OTK_None) {
1339+
if (auto dynamicSelf = dyn_cast<DynamicSelfType>(formalObjectType)) {
1340+
formalObjectType = dynamicSelf->getSelfType()->getCanonicalType();
1341+
}
1342+
return ((loweredOptionalKind == formalOptionalKind) &&
1343+
loweredObjectType == formalObjectType);
1344+
}
1345+
13291346
// Metatypes preserve their instance type through lowering.
13301347
if (auto loweredMT = loweredType.getAs<MetatypeType>()) {
13311348
if (auto formalMT = dyn_cast<MetatypeType>(formalType)) {

lib/SIL/TypeLowering.cpp

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2082,8 +2082,6 @@ TypeConverter::getLoweredLocalCaptures(AnyFunctionRef fn) {
20822082
return info;
20832083
};
20842084

2085-
assert(fn.getAsDeclContext()->getParent()->isLocalContext());
2086-
20872085
// See if we've cached the lowered capture list for this function.
20882086
auto found = LoweredCaptures.find(fn);
20892087
if (found != LoweredCaptures.end())
@@ -2092,8 +2090,13 @@ TypeConverter::getLoweredLocalCaptures(AnyFunctionRef fn) {
20922090
// Recursively collect transitive captures from captured local functions.
20932091
llvm::DenseSet<AnyFunctionRef> visitedFunctions;
20942092
llvm::SetVector<CapturedValue> captures;
2093+
2094+
// If there is a capture of 'self' with dynamic 'Self' type, it goes last so
2095+
// that IRGen can pass dynamic 'Self' metadata.
2096+
Optional<CapturedValue> selfCapture;
2097+
20952098
bool capturesGenericParams = false;
2096-
DynamicSelfType *capturesDynamicSelf;
2099+
DynamicSelfType *capturesDynamicSelf = nullptr;
20972100

20982101
std::function<void (AnyFunctionRef)> collectFunctionCaptures
20992102
= [&](AnyFunctionRef curFn) {
@@ -2144,10 +2147,27 @@ TypeConverter::getLoweredLocalCaptures(AnyFunctionRef fn) {
21442147
continue;
21452148
}
21462149

2147-
case VarDecl::Stored:
2150+
case VarDecl::Stored: {
21482151
// We can always capture the storage in these cases.
2152+
Type captureType;
2153+
if (auto *selfType = capturedVar->getType()->getAs<DynamicSelfType>()) {
2154+
captureType = selfType->getSelfType();
2155+
if (auto *metatypeType = captureType->getAs<MetatypeType>())
2156+
captureType = metatypeType->getInstanceType();
2157+
2158+
// We're capturing a 'self' value with dynamic 'Self' type;
2159+
// handle it specially.
2160+
if (!selfCapture &&
2161+
captureType->getClassOrBoundGenericClass()) {
2162+
selfCapture = capture;
2163+
continue;
2164+
}
2165+
}
2166+
2167+
// Otherwise just fall through.
21492168
goto capture_value;
21502169
}
2170+
}
21512171
}
21522172

21532173
capture_value:
@@ -2156,7 +2176,17 @@ TypeConverter::getLoweredLocalCaptures(AnyFunctionRef fn) {
21562176
}
21572177
};
21582178
collectFunctionCaptures(fn);
2159-
2179+
2180+
// If we captured the dynamic 'Self' type and we have a 'self' value also,
2181+
// add it as the final capture. Otherwise, add a fake hidden capture for
2182+
// the dynamic 'Self' metatype.
2183+
if (selfCapture.hasValue()) {
2184+
captures.insert(*selfCapture);
2185+
} else if (capturesDynamicSelf) {
2186+
selfCapture = CapturedValue::getDynamicSelfMetadata();
2187+
captures.insert(*selfCapture);
2188+
}
2189+
21602190
// Cache the uniqued set of transitive captures.
21612191
auto inserted = LoweredCaptures.insert({fn, CaptureInfo()});
21622192
assert(inserted.second && "already in map?!");

lib/SILGen/SILGenFunction.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,28 @@ void SILGenFunction::emitCaptures(SILLocation loc,
232232
canGuarantee = false;
233233

234234
for (auto capture : captureInfo.getCaptures()) {
235+
if (capture.isDynamicSelfMetadata()) {
236+
// The parameter type is the static Self type, but the value we
237+
// want to pass is the dynamic Self type, so upcast it.
238+
auto dynamicSelfMetatype = MetatypeType::get(
239+
captureInfo.getDynamicSelfType(),
240+
MetatypeRepresentation::Thick)
241+
->getCanonicalType();
242+
auto staticSelfMetatype = MetatypeType::get(
243+
captureInfo.getDynamicSelfType()->getSelfType(),
244+
MetatypeRepresentation::Thick)
245+
->getCanonicalType();
246+
SILType dynamicSILType = SILType::getPrimitiveObjectType(
247+
dynamicSelfMetatype);
248+
SILType staticSILType = SILType::getPrimitiveObjectType(
249+
staticSelfMetatype);
250+
251+
SILValue value = B.createMetatype(loc, dynamicSILType);
252+
value = B.createUpcast(loc, value, staticSILType);
253+
capturedArgs.push_back(ManagedValue::forUnmanaged(value));
254+
continue;
255+
}
256+
235257
auto *vd = capture.getDecl();
236258

237259
switch (SGM.Types.getDeclCaptureKind(capture)) {

lib/SILGen/SILGenProlog.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ void SILGenFunction::bindParametersForForwarding(const ParameterList *params,
357357

358358
static void emitCaptureArguments(SILGenFunction &gen, CapturedValue capture,
359359
unsigned ArgNo) {
360+
360361
auto *VD = capture.getDecl();
361362
auto type = VD->getType();
362363
SILLocation Loc(VD);
@@ -428,8 +429,21 @@ void SILGenFunction::emitProlog(AnyFunctionRef TheClosure,
428429
// Emit the capture argument variables. These are placed last because they
429430
// become the first curry level of the SIL function.
430431
auto captureInfo = SGM.Types.getLoweredLocalCaptures(TheClosure);
431-
for (auto capture : captureInfo.getCaptures())
432+
for (auto capture : captureInfo.getCaptures()) {
433+
if (capture.isDynamicSelfMetadata()) {
434+
auto selfMetatype = MetatypeType::get(
435+
captureInfo.getDynamicSelfType()->getSelfType(),
436+
MetatypeRepresentation::Thick)
437+
->getCanonicalType();
438+
SILType ty = SILType::getPrimitiveObjectType(selfMetatype);
439+
SILValue val = new (SGM.M) SILArgument(F.begin(), ty);
440+
(void) val;
441+
442+
return;
443+
}
444+
432445
emitCaptureArguments(*this, capture, ++ArgNo);
446+
}
433447
}
434448

435449
static void emitIndirectResultParameters(SILGenFunction &gen, Type resultType,

test/Interpreter/dynamic_self.swift

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,5 +94,44 @@ print("C() as class existential")
9494
// CHECK-NEXT: Destroying C
9595
callDynamicSelfClassExistential(C())
9696

97+
print("-------------------------------")
98+
99+
class Z {
100+
let name: String
101+
102+
init(name: String) {
103+
self.name = name
104+
}
105+
106+
func testCaptures(x: Int) -> Self {
107+
let fn1 = {
108+
print("First: \(self.name)")
109+
}
110+
fn1()
111+
112+
let fn2 = { [weak self] in
113+
if let strongSelf = self {
114+
print("Second: \(strongSelf.name)")
115+
}
116+
}
117+
fn2()
118+
119+
let fn3 = {
120+
print("Third: \(self.name)")
121+
print("Third: \(x)")
122+
}
123+
fn3()
124+
125+
return self
126+
}
127+
128+
}
129+
130+
// CHECK: First: Leeloo
131+
// CHECK-NEXT: Second: Leeloo
132+
// CHECK-NEXT: Third: Leeloo
133+
// CHECK-NEXT: Third: 42
134+
Z(name: "Leeloo").testCaptures(x: 42)
135+
97136
// CHECK-NEXT: Done
98137
print("Done")

test/SILGen/dynamic_self.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,51 @@ func testOptionalResult(v : OptionalResultInheritor) {
152152
// CHECK-NEXT: [[T4:%.*]] = unchecked_ref_cast [[T1]] : $OptionalResult to $OptionalResultInheritor
153153
// CHECK-NEXT: enum $Optional<OptionalResultInheritor>, #Optional.some!enumelt.1, [[T4]]
154154

155+
class Z {
156+
157+
// CHECK-LABEL: sil hidden @_TFC12dynamic_self1Z23testDynamicSelfCapturesfT1xSi_DS0_
158+
func testDynamicSelfCaptures(x: Int) -> Self {
159+
160+
// Single capture of 'self' type
161+
162+
// CHECK: [[FN:%.*]] = function_ref @_TFFC12dynamic_self1Z23testDynamicSelfCapturesFT1xSi_DS0_U_FT_T_ : $@convention(thin) (@owned Z) -> ()
163+
// CHECK-NEXT: strong_retain %1 : $Z
164+
// CHECK-NEXT: partial_apply [[FN]](%1)
165+
let fn1 = { _ = self }
166+
fn1()
167+
168+
// Capturing 'self', but it's not the last capture. Make sure it ends
169+
// up at the end of the list anyway
170+
171+
// CHECK: [[FN:%.*]] = function_ref @_TFFC12dynamic_self1Z23testDynamicSelfCapturesFT1xSi_DS0_U0_FT_T_ : $@convention(thin) (Int, @owned Z) -> ()
172+
// CHECK-NEXT: strong_retain %1 : $Z
173+
// CHECK-NEXT: partial_apply [[FN]](%0, %1)
174+
let fn2 = {
175+
_ = self
176+
_ = x
177+
}
178+
fn2()
179+
180+
// Capturing 'self' weak, so we have to pass in a metatype explicitly
181+
// so that IRGen can recover metadata.
182+
183+
// CHECK: [[WEAK_SELF:%.*]] = alloc_box $@sil_weak Optional<Z>
184+
// CHECK: [[FN:%.*]] = function_ref @_TFFC12dynamic_self1Z23testDynamicSelfCapturesFT1xSi_DS0_U1_FT_T_ : $@convention(thin) (@owned @box @sil_weak Optional<Z>, @thick Z.Type) -> ()
185+
// CHECK: strong_retain [[WEAK_SELF]] : $@box @sil_weak Optional<Z>
186+
// CHECK-NEXT: [[DYNAMIC_SELF:%.*]] = metatype $@thick Self.Type
187+
// CHECK-NEXT: [[STATIC_SELF:%.*]] = upcast [[DYNAMIC_SELF]] : $@thick Self.Type to $@thick Z.Type
188+
// CHECK: partial_apply [[FN]]([[WEAK_SELF]], [[STATIC_SELF]]) : $@convention(thin) (@owned @box @sil_weak Optional<Z>, @thick Z.Type) -> ()
189+
let fn3 = {
190+
[weak self] in
191+
_ = self
192+
}
193+
fn3()
194+
195+
return self
196+
}
197+
198+
}
199+
155200
// CHECK-LABEL: sil_witness_table hidden X: P module dynamic_self {
156201
// CHECK: method #P.f!1: @_TTWC12dynamic_self1XS_1PS_FS1_1f
157202

test/SILOptimizer/inline_self.swift

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
//
33
// This is a .swift test because the SIL parser does not support Self.
44

5+
// Do not inline C.factory into main. Doing so would lose the ability
6+
// to materialize local Self metadata.
57
class C {
68
required init() {}
79
}
@@ -22,14 +24,32 @@ extension C {
2224
}
2325
}
2426

25-
// Do not inline C.factory into main. Doing so would lose the ability
26-
// to materialize local Self metadata.
27-
//
27+
// Call the function so it can be inlined.
28+
var x = C()
29+
var x2 = C.factory(1)
30+
31+
@inline(never)
32+
func callIt(fn: () -> ()) {
33+
fn()
34+
}
35+
36+
// Do not inline C.capturesSelf() into main either.
37+
class Z {
38+
func capturesSelf() -> Self {
39+
let fn = { [weak self] in _ = self }
40+
callIt(fn: fn)
41+
return self
42+
}
43+
}
44+
45+
_ = Z().capturesSelf()
46+
2847
// CHECK-LABEL: sil @main : $@convention(c)
2948
// CHECK: function_ref static inline_self.C.factory (Swift.Int) -> Self
3049
// CHECK: [[F:%[0-9]+]] = function_ref @_TZFC11inline_self1C7factory{{.*}} : $@convention(method) (Int, @thick C.Type) -> @owned C
3150
// CHECK: apply [[F]](%{{.+}}, %{{.+}}) : $@convention(method) (Int, @thick C.Type) -> @owned C
3251

33-
// Call the function so it can be inlined.
34-
var x = C()
35-
var x2 = C.factory(1)
52+
// CHECK: [[Z:%.*]] = alloc_ref $Z
53+
// CHECK: function_ref inline_self.Z.capturesSelf () -> Self
54+
// CHECK: [[F:%[0-9]+]] = function_ref @_TFC11inline_self1Z12capturesSelffT_DS0_ : $@convention(method) (@guaranteed Z) -> @owned Z
55+
// CHECK: apply [[F]]([[Z]]) : $@convention(method) (@guaranteed Z) -> @owned Z

0 commit comments

Comments
 (0)