Skip to content

Commit ad700c5

Browse files
authored
Merge pull request #10014 from jckarter/existential-keypath-base
SILGen: Handle existential keypath root types.
2 parents a5795e0 + 4fc0b7d commit ad700c5

File tree

7 files changed

+129
-44
lines changed

7 files changed

+129
-44
lines changed

include/swift/AST/Types.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,9 @@ class alignas(1 << TypeAlignInBits) TypeBase {
607607
/// bound.
608608
bool isClassExistentialType();
609609

610+
/// Opens an existential instance or meta-type and returns the opened type.
611+
Type openAnyExistentialType(ArchetypeType *&opened);
612+
610613
/// Break an existential down into a set of constraints.
611614
ExistentialLayout getExistentialLayout();
612615

lib/AST/Type.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4146,3 +4146,16 @@ getRecursivePropertiesFromSubstitutions(SubstitutionList Params) {
41464146
}
41474147
return props;
41484148
}
4149+
4150+
Type TypeBase::openAnyExistentialType(ArchetypeType *&opened) {
4151+
assert(isAnyExistentialType());
4152+
if (auto metaty = getAs<ExistentialMetatypeType>()) {
4153+
opened = ArchetypeType::getOpened(metaty->getInstanceType());
4154+
if (metaty->hasRepresentation())
4155+
return MetatypeType::get(opened, metaty->getRepresentation());
4156+
else
4157+
return MetatypeType::get(opened);
4158+
}
4159+
opened = ArchetypeType::getOpened(this);
4160+
return opened;
4161+
}

lib/SILGen/SILGenExpr.cpp

Lines changed: 55 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2415,6 +2415,44 @@ RValue RValueEmitter::visitObjCSelectorExpr(ObjCSelectorExpr *e, SGFContext C) {
24152415
return RValue(SGF, e, ManagedValue::forUnmanaged(selectorValue));
24162416
}
24172417

2418+
static ManagedValue
2419+
emitKeyPathRValueBase(SILGenFunction &subSGF,
2420+
VarDecl *property,
2421+
SILLocation loc,
2422+
SILValue paramArg,
2423+
CanType &baseType) {
2424+
auto paramOrigValue = subSGF.emitManagedRValueWithCleanup(paramArg);
2425+
auto paramSubstValue = subSGF.emitOrigToSubstValue(loc, paramOrigValue,
2426+
AbstractionPattern::getOpaque(),
2427+
baseType);
2428+
2429+
// Upcast a class instance to the property's declared type if necessary.
2430+
if (auto propertyClass = dyn_cast<ClassDecl>(property->getDeclContext())) {
2431+
if (baseType->getClassOrBoundGenericClass() != propertyClass) {
2432+
baseType = baseType->getSuperclassForDecl(propertyClass)
2433+
->getCanonicalType();
2434+
paramSubstValue = subSGF.B.createUpcast(loc, paramSubstValue,
2435+
SILType::getPrimitiveObjectType(baseType));
2436+
}
2437+
}
2438+
// …or pop open an existential container.
2439+
else if (baseType->isAnyExistentialType()) {
2440+
ArchetypeType *opened;
2441+
baseType = baseType->openAnyExistentialType(opened)->getCanonicalType();
2442+
auto openedOpaqueValue = subSGF.emitOpenExistential(loc, paramSubstValue,
2443+
opened, subSGF.SGM.getLoweredType(baseType),
2444+
AccessKind::Read);
2445+
// Maybe we could peephole this if we know the property load can borrow the
2446+
// base value…
2447+
if (!openedOpaqueValue.IsConsumable) {
2448+
paramSubstValue = openedOpaqueValue.Value.copyUnmanaged(subSGF, loc);
2449+
} else {
2450+
paramSubstValue = openedOpaqueValue.Value;
2451+
}
2452+
}
2453+
return paramSubstValue;
2454+
}
2455+
24182456
static SILFunction *getOrCreateKeyPathGetter(SILGenFunction &SGF,
24192457
SILLocation loc,
24202458
VarDecl *property,
@@ -2482,22 +2520,10 @@ static SILFunction *getOrCreateKeyPathGetter(SILGenFunction &SGF,
24822520

24832521
Scope scope(subSGF, loc);
24842522

2485-
auto paramOrigValue = subSGF.emitManagedRValueWithCleanup(paramArg);
2486-
auto paramSubstValue = subSGF.emitOrigToSubstValue(loc, paramOrigValue,
2487-
AbstractionPattern::getOpaque(),
2488-
baseType);
2489-
2490-
// Upcast a class instance to the property's declared type if necessary.
2491-
if (auto propertyClass = dyn_cast<ClassDecl>(property->getDeclContext())) {
2492-
if (baseType->getClassOrBoundGenericClass() != propertyClass) {
2493-
do {
2494-
baseType = baseType->getSuperclass()->getCanonicalType();
2495-
} while (baseType->getClassOrBoundGenericClass() != propertyClass);
2496-
paramSubstValue = subSGF.B.createUpcast(loc, paramSubstValue,
2497-
SILType::getPrimitiveObjectType(baseType));
2498-
}
2499-
}
2500-
2523+
auto paramSubstValue = emitKeyPathRValueBase(subSGF, property,
2524+
loc, paramArg,
2525+
baseType);
2526+
25012527
auto subs = baseType->getContextSubstitutionMap(subSGF.SGM.M.getSwiftModule(),
25022528
property->getInnermostDeclContext()->getInnermostTypeContext());
25032529
SmallVector<Substitution, 4> subsList;
@@ -2602,27 +2628,26 @@ SILFunction *getOrCreateKeyPathSetter(SILGenFunction &SGF,
26022628

26032629
LValue lv;
26042630
if (property->isSetterNonMutating()) {
2605-
auto baseOrig = subSGF.emitManagedRValueWithCleanup(baseArg);
2606-
auto baseSubst = subSGF.emitOrigToSubstValue(loc, baseOrig,
2607-
AbstractionPattern::getOpaque(),
2608-
baseType);
2609-
// Upcast a class instance to the property's declared type if necessary.
2610-
if (auto propertyClass = dyn_cast<ClassDecl>(property->getDeclContext())) {
2611-
if (baseType->getClassOrBoundGenericClass() != propertyClass) {
2612-
do {
2613-
baseType = baseType->getSuperclass()->getCanonicalType();
2614-
} while (baseType->getClassOrBoundGenericClass() != propertyClass);
2615-
baseSubst = subSGF.B.createUpcast(loc, baseSubst,
2616-
SILType::getPrimitiveObjectType(baseType));
2617-
}
2618-
}
2631+
auto baseSubst = emitKeyPathRValueBase(subSGF, property,
2632+
loc, baseArg,
2633+
baseType);
26192634

26202635
lv = LValue::forValue(baseSubst, baseType);
26212636
} else {
26222637
auto baseOrig = ManagedValue::forLValue(baseArg);
26232638
lv = LValue::forAddress(baseOrig, None,
26242639
AbstractionPattern::getOpaque(),
26252640
baseType);
2641+
2642+
// Open an existential lvalue, if necessary.
2643+
if (baseType->isAnyExistentialType()) {
2644+
ArchetypeType *opened;
2645+
baseType = baseType->openAnyExistentialType(opened)->getCanonicalType();
2646+
lv = subSGF.emitOpenExistentialLValue(loc, std::move(lv),
2647+
CanArchetypeType(opened),
2648+
baseType,
2649+
AccessKind::ReadWrite);
2650+
}
26262651
}
26272652

26282653
auto subs = baseType->getContextSubstitutionMap(subSGF.SGM.M.getSwiftModule(),

lib/SILGen/SILGenLValue.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1751,13 +1751,20 @@ namespace {
17511751

17521752
LValue LValue::forValue(ManagedValue value,
17531753
CanType substFormalType) {
1754-
assert(value.getType().isObject());
1755-
LValueTypeData typeData = getValueTypeData(substFormalType,
1756-
value.getValue());
1754+
if (value.getType().isObject()) {
1755+
LValueTypeData typeData = getValueTypeData(substFormalType,
1756+
value.getValue());
17571757

1758-
LValue lv;
1759-
lv.add<ValueComponent>(value, None, typeData, /*isRValue=*/true);
1760-
return lv;
1758+
LValue lv;
1759+
lv.add<ValueComponent>(value, None, typeData, /*isRValue=*/true);
1760+
return lv;
1761+
} else {
1762+
// Treat an address-only value as an lvalue we only read from.
1763+
if (!value.isLValue())
1764+
value = ManagedValue::forLValue(value.getValue());
1765+
return forAddress(value, None, AbstractionPattern(substFormalType),
1766+
substFormalType);
1767+
}
17611768
}
17621769

17631770
LValue LValue::forAddress(ManagedValue address,

lib/SILGen/SILGenMaterializeForSet.cpp

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -431,13 +431,7 @@ struct MaterializeForSetEmitter {
431431
// Metatypes and bases of non-mutating setters on value types
432432
// are always rvalues.
433433
if (!SubstSelfType->getRValueInstanceType()->mayHaveSuperclass()) {
434-
if (self.getType().isObject())
435-
return LValue::forValue(self, SubstSelfType);
436-
else {
437-
if (!self.isLValue())
438-
self = ManagedValue::forLValue(self.getValue());
439-
return LValue::forAddress(self, None, selfPattern, SubstSelfType);
440-
}
434+
return LValue::forValue(self, SubstSelfType);
441435
}
442436

443437
CanType witnessSelfType =

test/SILGen/keypaths.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ extension P {
3131
var z: String {
3232
return y
3333
}
34+
var w: String {
35+
get { return "" }
36+
nonmutating set { }
37+
}
3438
}
3539

3640
// CHECK-LABEL: sil hidden @{{.*}}storedProperties
@@ -171,3 +175,10 @@ class BB<U, V>: AA<V> {
171175
func keyPathForInheritedMember() {
172176
_ = \BB<Int, String>.a
173177
}
178+
179+
func keyPathForExistentialMember() {
180+
_ = \P.x
181+
_ = \P.y
182+
_ = \P.z
183+
_ = \P.w
184+
}

test/stdlib/KeyPath.swift

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,12 +279,18 @@ keyPath.test("computed properties") {
279279

280280
class AB {
281281
}
282-
class ABC: AB {
282+
class ABC: AB, ABCProtocol {
283283
var a = LifetimeTracked(1)
284284
var b = LifetimeTracked(2)
285285
var c = LifetimeTracked(3)
286286
}
287287

288+
protocol ABCProtocol {
289+
var a: LifetimeTracked { get }
290+
var b: LifetimeTracked { get set }
291+
var c: LifetimeTracked { get nonmutating set }
292+
}
293+
288294
keyPath.test("dynamically-typed application") {
289295
let cPaths = [\ABC.a, \ABC.b, \ABC.c]
290296

@@ -312,6 +318,32 @@ keyPath.test("dynamically-typed application") {
312318
expectTrue(wrongFields[1] == nil)
313319
expectTrue(wrongFields[2] == nil)
314320
}
321+
322+
var protoErasedSubject: ABCProtocol = subject
323+
let protoErasedPathA = \ABCProtocol.a
324+
let protoErasedPathB = \ABCProtocol.b
325+
let protoErasedPathC = \ABCProtocol.c
326+
327+
do {
328+
expectTrue(protoErasedSubject.a ===
329+
protoErasedSubject[keyPath: protoErasedPathA])
330+
331+
let newB = LifetimeTracked(4)
332+
expectTrue(protoErasedSubject.b ===
333+
protoErasedSubject[keyPath: protoErasedPathB])
334+
protoErasedSubject[keyPath: protoErasedPathB] = newB
335+
expectTrue(protoErasedSubject.b ===
336+
protoErasedSubject[keyPath: protoErasedPathB])
337+
expectTrue(protoErasedSubject.b === newB)
338+
339+
let newC = LifetimeTracked(5)
340+
expectTrue(protoErasedSubject.c ===
341+
protoErasedSubject[keyPath: protoErasedPathC])
342+
protoErasedSubject[keyPath: protoErasedPathC] = newC
343+
expectTrue(protoErasedSubject.c ===
344+
protoErasedSubject[keyPath: protoErasedPathC])
345+
expectTrue(protoErasedSubject.c === newC)
346+
}
315347
}
316348

317349
runAllTests()

0 commit comments

Comments
 (0)