Skip to content

Commit 2d194e7

Browse files
authored
Merge pull request swiftlang#15034 from jckarter/keypath-resilience-silgen
SILGen: Emit property descriptors for (some) decls that need them.
2 parents e61c895 + a8e3c4f commit 2d194e7

File tree

7 files changed

+213
-37
lines changed

7 files changed

+213
-37
lines changed

include/swift/SIL/SILInstruction.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2353,9 +2353,6 @@ class KeyPathPatternComponent {
23532353
Indices(indices),
23542354
IndexEquality{indicesEqual, indicesHash},
23552355
ComponentType(ComponentType) {
2356-
assert(indices.empty() == !indicesEqual
2357-
&& indices.empty() == !indicesHash
2358-
&& "must have equals/hash functions iff there are indices");
23592356
}
23602357

23612358
KeyPathPatternComponent(AbstractStorageDecl *externalStorage,

lib/SILGen/SILGen.cpp

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "Scope.h"
1616
#include "swift/Strings.h"
1717
#include "swift/AST/DiagnosticsSIL.h"
18+
#include "swift/AST/GenericEnvironment.h"
1819
#include "swift/AST/NameLookup.h"
1920
#include "swift/AST/ParameterList.h"
2021
#include "swift/AST/PrettyStackTrace.h"
@@ -1204,7 +1205,69 @@ static bool doesPropertyNeedDescriptor(AbstractStorageDecl *decl) {
12041205
}
12051206

12061207
void SILGenModule::tryEmitPropertyDescriptor(AbstractStorageDecl *decl) {
1207-
// TODO
1208+
// TODO: Key path code emission doesn't handle opaque values properly yet.
1209+
if (!SILModuleConventions(M).useLoweredAddresses())
1210+
return;
1211+
1212+
if (!doesPropertyNeedDescriptor(decl))
1213+
return;
1214+
1215+
auto genericEnv = decl->getInnermostDeclContext()
1216+
->getGenericEnvironmentOfContext();
1217+
unsigned baseOperand = 0;
1218+
bool needsGenericContext = true;
1219+
1220+
Type baseTy;
1221+
if (decl->getDeclContext()->isTypeContext()) {
1222+
baseTy = decl->getDeclContext()->getSelfInterfaceType();
1223+
if (decl->isStatic()) {
1224+
// TODO: Static properties should eventually be referenceable as
1225+
// keypaths from T.Type -> Element
1226+
//baseTy = MetatypeType::get(baseTy);
1227+
return;
1228+
}
1229+
} else {
1230+
// TODO: Global variables should eventually be referenceable as
1231+
// key paths from ()
1232+
//baseTy = TupleType::getEmpty(getASTContext());
1233+
return;
1234+
}
1235+
1236+
SubstitutionList subs = {};
1237+
if (genericEnv)
1238+
subs = genericEnv->getForwardingSubstitutions();
1239+
1240+
// TODO: The hashable conformances for the indices need to be provided by the
1241+
// client, since they may be post-hoc conformances, or a generic subscript
1242+
// may be invoked with hashable substitutions. We may eventually allow for
1243+
// non-hashable keypaths as well.
1244+
SmallVector<ProtocolConformanceRef, 4> indexHashables;
1245+
if (auto sub = dyn_cast<SubscriptDecl>(decl)) {
1246+
auto hashable = getASTContext().getProtocol(KnownProtocolKind::Hashable);
1247+
for (auto *index : *sub->getIndices()) {
1248+
if (index->isInOut())
1249+
return;
1250+
auto indexTy = index->getInterfaceType();
1251+
if (genericEnv)
1252+
indexTy = genericEnv->mapTypeIntoContext(indexTy);
1253+
1254+
auto conformance = sub->getModuleContext()
1255+
->lookupConformance(indexTy, hashable);
1256+
if (!conformance)
1257+
return;
1258+
if (!conformance->getConditionalRequirements().empty())
1259+
return;
1260+
indexHashables.push_back(*conformance);
1261+
}
1262+
}
1263+
1264+
auto component = emitKeyPathComponentForDecl(SILLocation(decl),
1265+
genericEnv,
1266+
baseOperand, needsGenericContext,
1267+
subs, decl, indexHashables,
1268+
baseTy->getCanonicalType());
1269+
1270+
(void)SILProperty::create(M, /*serialized*/ false, decl, component);
12081271
}
12091272

12101273
void SILGenModule::emitPropertyBehavior(VarDecl *vd) {

lib/SILGen/SILGen.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,16 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
339339
AccessKind accessKind);
340340
SILDeclRef getMaterializeForSetDeclRef(AbstractStorageDecl *decl);
341341

342+
KeyPathPatternComponent
343+
emitKeyPathComponentForDecl(SILLocation loc,
344+
GenericEnvironment *genericEnv,
345+
unsigned &baseOperand,
346+
bool &needsGenericContext,
347+
SubstitutionList subs,
348+
AbstractStorageDecl *storage,
349+
ArrayRef<ProtocolConformanceRef> indexHashables,
350+
CanType baseTy);
351+
342352
/// Known functions for bridging.
343353
SILDeclRef getStringToNSStringFn();
344354
SILDeclRef getNSStringToStringFn();

lib/SILGen/SILGenApply.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5013,6 +5013,9 @@ ArgumentSource SILGenFunction::prepareAccessorBaseArg(SILLocation loc,
50135013
ManagedValue base,
50145014
CanType baseFormalType,
50155015
SILDeclRef accessor) {
5016+
if (!base)
5017+
return ArgumentSource();
5018+
50165019
AccessorBaseArgPreparer Preparer(*this, loc, base, baseFormalType, accessor);
50175020
return Preparer.prepare();
50185021
}

lib/SILGen/SILGenExpr.cpp

Lines changed: 54 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2983,6 +2983,11 @@ emitKeyPathRValueBase(SILGenFunction &subSGF,
29832983
CanType &baseType,
29842984
SubstitutionList &subs,
29852985
SmallVectorImpl<Substitution> &subsBuf) {
2986+
// If the storage is at global scope, then the base value () is a formality.
2987+
// There no real argument to pass to the underlying accessors.
2988+
if (!storage->getDeclContext()->isTypeContext())
2989+
return ManagedValue();
2990+
29862991
auto paramOrigValue = subSGF.emitManagedRValueWithCleanup(paramArg);
29872992
auto paramSubstValue = subSGF.emitOrigToSubstValue(loc, paramOrigValue,
29882993
AbstractionPattern::getOpaque(),
@@ -3147,15 +3152,15 @@ static SILFunction *getOrCreateKeyPathGetter(SILGenModule &SGM,
31473152

31483153
SmallVector<Substitution, 2> subsBuf;
31493154

3150-
auto paramSubstValue = emitKeyPathRValueBase(subSGF, property,
3155+
auto baseSubstValue = emitKeyPathRValueBase(subSGF, property,
31513156
loc, baseArg,
31523157
baseType, subs, subsBuf);
31533158

31543159
RValue indexValue = loadIndexValuesForKeyPathComponent(subSGF, loc,
31553160
indexes,
31563161
indexPtrArg);
31573162

3158-
auto resultSubst = subSGF.emitRValueForStorageLoad(loc, paramSubstValue,
3163+
auto resultSubst = subSGF.emitRValueForStorageLoad(loc, baseSubstValue,
31593164
baseType, /*super*/false,
31603165
property, std::move(indexValue),
31613166
subs, AccessSemantics::Ordinary,
@@ -3448,6 +3453,11 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM,
34483453
auto equatable = *subMap
34493454
.lookupConformance(CanType(hashableSig->getGenericParams()[0]),
34503455
equatableProtocol);
3456+
3457+
assert(equatable.isAbstract() == hashable.isAbstract());
3458+
if (equatable.isConcrete())
3459+
assert(equatable.getConcrete()->getType()->isEqual(
3460+
hashable.getConcrete()->getType()));
34513461
auto equatableSub = Substitution(formalTy,
34523462
C.AllocateCopy(ArrayRef<ProtocolConformanceRef>(equatable)));
34533463

@@ -3690,15 +3700,21 @@ lowerKeyPathSubscriptIndexPatterns(
36903700
bool &needsGenericContext) {
36913701
// Capturing an index value dependent on the generic context means we
36923702
// need the generic context captured in the key path.
3693-
auto subMap =
3694-
subscript->getGenericSignature()->getSubstitutionMap(subscriptSubs);
3695-
auto subscriptSubstTy = subscript->getInterfaceType().subst(subMap);
3703+
auto subscriptSubstTy = subscript->getInterfaceType();
3704+
SubstitutionMap subMap;
3705+
auto sig = subscript->getGenericSignature();
3706+
if (sig) {
3707+
subMap = sig->getSubstitutionMap(subscriptSubs);
3708+
subscriptSubstTy = subscriptSubstTy.subst(subMap);
3709+
}
36963710
needsGenericContext |= subscriptSubstTy->hasArchetype();
36973711

36983712
unsigned i = 0;
36993713
for (auto *index : *subscript->getIndices()) {
3700-
auto indexTy = index->getInterfaceType().subst(subMap)
3701-
->getCanonicalType();
3714+
auto indexTy = index->getInterfaceType();
3715+
if (sig) {
3716+
indexTy = indexTy.subst(subMap);
3717+
}
37023718
auto hashable = indexHashables[i++];
37033719
assert(hashable.isAbstract() ||
37043720
hashable.getConcrete()->getType()->isEqual(indexTy));
@@ -3718,20 +3734,24 @@ lowerKeyPathSubscriptIndexPatterns(
37183734
}
37193735
};
37203736

3721-
static KeyPathPatternComponent
3722-
emitKeyPathComponentForDecl(SILGenModule &SGM,
3723-
SILLocation loc,
3724-
GenericEnvironment *genericEnv,
3725-
unsigned &baseOperand,
3726-
bool &needsGenericContext,
3727-
SubstitutionList subs,
3728-
AbstractStorageDecl *storage,
3729-
ArrayRef<ProtocolConformanceRef> indexHashables,
3730-
CanType baseTy) {
3737+
KeyPathPatternComponent
3738+
SILGenModule::emitKeyPathComponentForDecl(SILLocation loc,
3739+
GenericEnvironment *genericEnv,
3740+
unsigned &baseOperand,
3741+
bool &needsGenericContext,
3742+
SubstitutionList subs,
3743+
AbstractStorageDecl *storage,
3744+
ArrayRef<ProtocolConformanceRef> indexHashables,
3745+
CanType baseTy) {
37313746
if (auto var = dyn_cast<VarDecl>(storage)) {
3732-
auto componentTy = baseTy->getTypeOfMember(SGM.SwiftModule, var)
3733-
->getReferenceStorageReferent()
3734-
->getCanonicalType();
3747+
CanType componentTy;
3748+
if (!var->getDeclContext()->isTypeContext()) {
3749+
componentTy = storage->getStorageInterfaceType()->getCanonicalType();
3750+
} else {
3751+
componentTy = baseTy->getTypeOfMember(SwiftModule, var)
3752+
->getReferenceStorageReferent()
3753+
->getCanonicalType();
3754+
}
37353755

37363756
switch (auto strategy = var->getAccessStrategy(AccessSemantics::Ordinary,
37373757
AccessKind::ReadWrite)) {
@@ -3741,9 +3761,9 @@ emitKeyPathComponentForDecl(SILGenModule &SGM,
37413761
auto componentObjTy = componentTy->getWithoutSpecifierType();
37423762
if (genericEnv)
37433763
componentObjTy = genericEnv->mapTypeIntoContext(componentObjTy);
3744-
auto storageTy = SGM.Types.getSubstitutedStorageType(var,
3764+
auto storageTy = Types.getSubstitutedStorageType(var,
37453765
componentObjTy);
3746-
auto opaqueTy = SGM.Types
3766+
auto opaqueTy = Types
37473767
.getLoweredType(AbstractionPattern::getOpaque(), componentObjTy);
37483768

37493769
if (storageTy.getAddressType() == opaqueTy.getAddressType()) {
@@ -3756,17 +3776,17 @@ emitKeyPathComponentForDecl(SILGenModule &SGM,
37563776
case AccessStrategy::DispatchToAccessor: {
37573777
// We need thunks to bring the getter and setter to the right signature
37583778
// expected by the key path runtime.
3759-
auto id = getIdForKeyPathComponentComputedProperty(SGM, var,
3779+
auto id = getIdForKeyPathComponentComputedProperty(*this, var,
37603780
strategy);
3761-
auto getter = getOrCreateKeyPathGetter(SGM, loc,
3781+
auto getter = getOrCreateKeyPathGetter(*this, loc,
37623782
var, subs,
37633783
strategy,
37643784
needsGenericContext ? genericEnv : nullptr,
37653785
{},
37663786
baseTy, componentTy);
37673787

37683788
if (var->isSettable(var->getDeclContext())) {
3769-
auto setter = getOrCreateKeyPathSetter(SGM, loc,
3789+
auto setter = getOrCreateKeyPathSetter(*this, loc,
37703790
var, subs,
37713791
strategy,
37723792
needsGenericContext ? genericEnv : nullptr,
@@ -3796,28 +3816,30 @@ emitKeyPathComponentForDecl(SILGenModule &SGM,
37963816
auto componentTy = baseSubscriptInterfaceTy.getResult();
37973817

37983818
SmallVector<KeyPathPatternComponent::Index, 4> indexPatterns;
3799-
lowerKeyPathSubscriptIndexPatterns(SGM, indexPatterns,
3819+
lowerKeyPathSubscriptIndexPatterns(*this, indexPatterns,
38003820
decl, subs, indexHashables,
38013821
baseOperand,
38023822
needsGenericContext);
38033823

38043824
SILFunction *indexEquals = nullptr, *indexHash = nullptr;
3805-
getOrCreateKeyPathEqualsAndHash(SGM, loc,
3825+
// TODO: Property descriptors for external key paths should get their
3826+
// equality and hashing from the client.
3827+
getOrCreateKeyPathEqualsAndHash(*this, loc,
38063828
needsGenericContext ? genericEnv : nullptr,
38073829
indexPatterns,
38083830
indexEquals, indexHash);
38093831

3810-
auto id = getIdForKeyPathComponentComputedProperty(SGM, decl, strategy);
3811-
auto getter = getOrCreateKeyPathGetter(SGM, loc,
3832+
auto id = getIdForKeyPathComponentComputedProperty(*this, decl, strategy);
3833+
auto getter = getOrCreateKeyPathGetter(*this, loc,
38123834
decl, subs,
38133835
strategy,
38143836
needsGenericContext ? genericEnv : nullptr,
38153837
indexPatterns,
38163838
baseTy, componentTy);
38173839

3818-
auto indexPatternsCopy = SGM.getASTContext().AllocateCopy(indexPatterns);
3840+
auto indexPatternsCopy = getASTContext().AllocateCopy(indexPatterns);
38193841
if (decl->isSettable()) {
3820-
auto setter = getOrCreateKeyPathSetter(SGM, loc,
3842+
auto setter = getOrCreateKeyPathSetter(*this, loc,
38213843
decl, subs,
38223844
strategy,
38233845
needsGenericContext ? genericEnv : nullptr,
@@ -3952,7 +3974,7 @@ RValue RValueEmitter::visitKeyPathExpr(KeyPathExpr *E, SGFContext C) {
39523974
} else {
39533975
unsigned numOperands = operands.size();
39543976
loweredComponents.push_back(
3955-
emitKeyPathComponentForDecl(SGF.SGM, SILLocation(E),
3977+
SGF.SGM.emitKeyPathComponentForDecl(SILLocation(E),
39563978
SGF.F.getGenericEnvironment(),
39573979
numOperands,
39583980
needsGenericContext,

lib/Serialization/DeserializeSIL.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2607,7 +2607,8 @@ SILVTable *SILDeserializer::readVTable(DeclID VId) {
26072607
// Another SIL_VTABLE record means the end of this VTable.
26082608
while (kind != SIL_VTABLE && kind != SIL_WITNESS_TABLE &&
26092609
kind != SIL_DEFAULT_WITNESS_TABLE &&
2610-
kind != SIL_FUNCTION) {
2610+
kind != SIL_FUNCTION &&
2611+
kind != SIL_PROPERTY) {
26112612
assert(kind == SIL_VTABLE_ENTRY &&
26122613
"Content of Vtable should be in SIL_VTABLE_ENTRY.");
26132614
ArrayRef<uint64_t> ListOfValues;
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// RUN: %target-swift-frontend -emit-silgen %s | %FileCheck %s
2+
3+
// TODO: globals should get descriptors
4+
public var a: Int = 0
5+
6+
@_inlineable
7+
public var b: Int { return 0 }
8+
9+
@_versioned
10+
internal var c: Int = 0
11+
12+
// no descriptor
13+
// CHECK-NOT: sil_property #d
14+
internal var d: Int = 0
15+
// CHECK-NOT: sil_property #e
16+
private var e: Int = 0
17+
18+
public struct A {
19+
// CHECK-LABEL: sil_property #A.a
20+
public var a: Int = 0
21+
22+
// CHECK-LABEL: sil_property #A.b
23+
@_inlineable
24+
public var b: Int { return 0 }
25+
26+
// CHECK-LABEL: sil_property #A.c
27+
@_versioned
28+
internal var c: Int = 0
29+
30+
// no descriptor
31+
// CHECK-NOT: sil_property #A.d
32+
internal var d: Int = 0
33+
// CHECK-NOT: sil_property #A.e
34+
fileprivate var e: Int = 0
35+
// CHECK-NOT: sil_property #A.f
36+
private var f: Int = 0
37+
38+
// TODO: static vars should get descriptors
39+
public static var a: Int = 0
40+
@_inlineable
41+
public static var b: Int { return 0 }
42+
@_versioned
43+
internal static var c: Int = 0
44+
45+
// no descriptor
46+
// CHECK-NOT: sil_property #A.d
47+
internal static var d: Int = 0
48+
// CHECK-NOT: sil_property #A.e
49+
fileprivate static var e: Int = 0
50+
// CHECK-NOT: sil_property #A.f
51+
private static var f: Int = 0
52+
53+
// CHECK-LABEL: sil_property #A.subscript
54+
public subscript(a x: Int) -> Int { return x }
55+
// CHECK-LABEL: sil_property #A.subscript
56+
@_inlineable
57+
public subscript(b x: Int) -> Int { return x }
58+
// CHECK-LABEL: sil_property #A.subscript
59+
@_versioned
60+
internal subscript(c x: Int) -> Int { return x }
61+
62+
// no descriptor
63+
// CHECK-NOT: sil_property #A.subscript
64+
internal subscript(d x: Int) -> Int { return x }
65+
fileprivate subscript(e x: Int) -> Int { return x }
66+
private subscript(f x: Int) -> Int { return x }
67+
68+
// TODO: Subscripts with non-hashable subscripts should get descriptors
69+
public subscript<T>(a x: T) -> T { return x }
70+
@_inlineable
71+
public subscript<T>(b x: T) -> T { return x }
72+
@_versioned
73+
internal subscript<T>(c x: T) -> T { return x }
74+
75+
// no descriptor
76+
internal subscript<T>(d x: T) -> T { return x }
77+
fileprivate subscript<T>(e x: T) -> T { return x }
78+
private subscript<T>(f x: T) -> T { return x }
79+
}
80+

0 commit comments

Comments
 (0)