Skip to content

Commit 2ca7134

Browse files
authored
Merge pull request swiftlang#30053 from slavapestov/keypath-component-resilient-stored-generic
SILGen: Work around for stored property keypath components not supporting generic resilient classes
2 parents 2cfc2fa + 10c37c6 commit 2ca7134

File tree

3 files changed

+58
-2
lines changed

3 files changed

+58
-2
lines changed

lib/IRGen/GenKeyPath.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,7 @@ emitKeyPathComponent(IRGenModule &IGM,
794794

795795
switch (getClassFieldAccess(IGM, loweredBaseContextTy, property)) {
796796
case FieldAccess::ConstantDirect: {
797-
// Known constant fixed offset.
797+
// Known compile-time constant field offset.
798798
auto offset = tryEmitConstantClassFragilePhysicalMemberOffset(
799799
IGM, loweredClassTy, property);
800800
assert(offset && "no constant offset for ConstantDirect field?!");
@@ -804,6 +804,9 @@ emitKeyPathComponent(IRGenModule &IGM,
804804
case FieldAccess::NonConstantDirect: {
805805
// A constant offset that's determined at class realization time.
806806
// We have to load the offset from a global ivar.
807+
//
808+
// This means the field offset is constant at runtime, but is not known
809+
// at compile time.
807810
auto header = KeyPathComponentHeader
808811
::forClassComponentWithUnresolvedIndirectOffset(property->isLet());
809812
fields.addInt32(header.getData());
@@ -814,10 +817,15 @@ emitKeyPathComponent(IRGenModule &IGM,
814817
}
815818
case FieldAccess::ConstantIndirect: {
816819
// An offset that depends on the instance's generic parameterization,
817-
// but whose field offset is at a known vtable offset.
820+
// but whose field offset is at a known metadata offset.
818821
auto header = KeyPathComponentHeader
819822
::forClassComponentWithUnresolvedFieldOffset(property->isLet());
820823
fields.addInt32(header.getData());
824+
825+
// FIXME: This doesn't support classes with resilient ancestry, because
826+
// the offset into the metadata is itself not constant.
827+
//
828+
// SILGen emits the descriptor as a computed property in this case.
821829
auto fieldOffset = getClassFieldOffsetOffset(
822830
IGM, loweredClassTy.getClassOrBoundGenericClass(), property);
823831
fields.addInt32(fieldOffset.getValue());

lib/SILGen/SILGen.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,6 +1353,24 @@ SILGenModule::canStorageUseStoredKeyPathComponent(AbstractStorageDecl *decl,
13531353
// unowned properties.
13541354
if (decl->getInterfaceType()->is<ReferenceStorageType>())
13551355
return false;
1356+
1357+
// If the field offset depends on the generic instantiation, we have to
1358+
// load it from metadata when instantiating the keypath component.
1359+
//
1360+
// However the metadata offset itself will not be fixed if the superclass
1361+
// is resilient. Fall back to treating the property as computed in this
1362+
// case.
1363+
//
1364+
// See the call to getClassFieldOffsetOffset() inside
1365+
// emitKeyPathComponent().
1366+
if (auto *parentClass = dyn_cast<ClassDecl>(decl->getDeclContext())) {
1367+
if (parentClass->isGeneric()) {
1368+
auto ancestry = parentClass->checkAncestry();
1369+
if (ancestry.contains(AncestryFlags::ResilientOther))
1370+
return false;
1371+
}
1372+
}
1373+
13561374
// If the stored value would need to be reabstracted in fully opaque
13571375
// context, then we have to treat the component as computed.
13581376
auto componentObjTy = decl->getValueInterfaceType();
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module -enable-library-evolution -emit-module-path=%t/resilient_struct.swiftmodule -module-name=resilient_struct %S/../Inputs/resilient_struct.swift
3+
// RUN: %target-swift-frontend -emit-module -enable-library-evolution -emit-module-path=%t/resilient_class.swiftmodule -module-name=resilient_class -I %t %S/../Inputs/resilient_class.swift
4+
5+
// RUN: %target-swift-emit-silgen %s -I %t -enable-library-evolution | %FileCheck %s
6+
7+
import resilient_class
8+
9+
open class MySubclass<T> : ResilientOutsideParent {
10+
public final var storedProperty: T? = nil
11+
}
12+
13+
open class ConcreteSubclass : MySubclass<Int> {
14+
public final var anotherStoredProperty: Int? = nil
15+
}
16+
17+
// CHECK-LABEL: sil shared [thunk] [ossa] @$s26keypaths_resilient_generic10MySubclassC14storedPropertyxSgvplACyxGTK : $@convention(thin) <T> (@in_guaranteed MySubclass<T>) -> @out Optional<T> {
18+
19+
// CHECK-LABEL: sil shared [thunk] [ossa] @$s26keypaths_resilient_generic10MySubclassC14storedPropertyxSgvplACyxGTk : $@convention(thin) <T> (@in_guaranteed Optional<T>, @in_guaranteed MySubclass<T>) -> () {
20+
21+
// CHECK: sil_property #MySubclass.storedProperty<τ_0_0> (
22+
// CHECK-SAME: settable_property $Optional<τ_0_0>,
23+
// CHECK-SAME: id ##MySubclass.storedProperty,
24+
// CHECK-SAME: getter @$s26keypaths_resilient_generic10MySubclassC14storedPropertyxSgvplACyxGTK : $@convention(thin) <τ_0_0> (@in_guaranteed MySubclass<τ_0_0>) -> @out Optional<τ_0_0>,
25+
// CHECK-SAME: setter @$s26keypaths_resilient_generic10MySubclassC14storedPropertyxSgvplACyxGTk : $@convention(thin) <τ_0_0> (@in_guaranteed Optional<τ_0_0>, @in_guaranteed MySubclass<τ_0_0>) -> ()
26+
// CHECK-SAME: )
27+
28+
// CHECK: sil_property #ConcreteSubclass.anotherStoredProperty (
29+
// CHECK-SAME: stored_property #ConcreteSubclass.anotherStoredProperty : $Optional<Int>
30+
// CHECK-SAME: )

0 commit comments

Comments
 (0)