mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
SILGen: Handle existential keypath root types.
SR-4917|rdar://problem/32254554
This commit is contained in:
@@ -589,6 +589,9 @@ public:
|
||||
/// bound.
|
||||
bool isClassExistentialType();
|
||||
|
||||
/// Opens an existential instance or meta-type and returns the opened type.
|
||||
Type openAnyExistentialType(ArchetypeType *&opened);
|
||||
|
||||
/// Break an existential down into a set of constraints.
|
||||
ExistentialLayout getExistentialLayout();
|
||||
|
||||
|
||||
@@ -4146,3 +4146,16 @@ getRecursivePropertiesFromSubstitutions(SubstitutionList Params) {
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
Type TypeBase::openAnyExistentialType(ArchetypeType *&opened) {
|
||||
assert(isAnyExistentialType());
|
||||
if (auto metaty = getAs<ExistentialMetatypeType>()) {
|
||||
opened = ArchetypeType::getOpened(metaty->getInstanceType());
|
||||
if (metaty->hasRepresentation())
|
||||
return MetatypeType::get(opened, metaty->getRepresentation());
|
||||
else
|
||||
return MetatypeType::get(opened);
|
||||
}
|
||||
opened = ArchetypeType::getOpened(this);
|
||||
return opened;
|
||||
}
|
||||
|
||||
@@ -2415,6 +2415,44 @@ RValue RValueEmitter::visitObjCSelectorExpr(ObjCSelectorExpr *e, SGFContext C) {
|
||||
return RValue(SGF, e, ManagedValue::forUnmanaged(selectorValue));
|
||||
}
|
||||
|
||||
static ManagedValue
|
||||
emitKeyPathRValueBase(SILGenFunction &subSGF,
|
||||
VarDecl *property,
|
||||
SILLocation loc,
|
||||
SILValue paramArg,
|
||||
CanType &baseType) {
|
||||
auto paramOrigValue = subSGF.emitManagedRValueWithCleanup(paramArg);
|
||||
auto paramSubstValue = subSGF.emitOrigToSubstValue(loc, paramOrigValue,
|
||||
AbstractionPattern::getOpaque(),
|
||||
baseType);
|
||||
|
||||
// Upcast a class instance to the property's declared type if necessary.
|
||||
if (auto propertyClass = dyn_cast<ClassDecl>(property->getDeclContext())) {
|
||||
if (baseType->getClassOrBoundGenericClass() != propertyClass) {
|
||||
baseType = baseType->getSuperclassForDecl(propertyClass)
|
||||
->getCanonicalType();
|
||||
paramSubstValue = subSGF.B.createUpcast(loc, paramSubstValue,
|
||||
SILType::getPrimitiveObjectType(baseType));
|
||||
}
|
||||
}
|
||||
// …or pop open an existential container.
|
||||
else if (baseType->isAnyExistentialType()) {
|
||||
ArchetypeType *opened;
|
||||
baseType = baseType->openAnyExistentialType(opened)->getCanonicalType();
|
||||
auto openedOpaqueValue = subSGF.emitOpenExistential(loc, paramSubstValue,
|
||||
opened, subSGF.SGM.getLoweredType(baseType),
|
||||
AccessKind::Read);
|
||||
// Maybe we could peephole this if we know the property load can borrow the
|
||||
// base value…
|
||||
if (!openedOpaqueValue.IsConsumable) {
|
||||
paramSubstValue = openedOpaqueValue.Value.copyUnmanaged(subSGF, loc);
|
||||
} else {
|
||||
paramSubstValue = openedOpaqueValue.Value;
|
||||
}
|
||||
}
|
||||
return paramSubstValue;
|
||||
}
|
||||
|
||||
static SILFunction *getOrCreateKeyPathGetter(SILGenFunction &SGF,
|
||||
SILLocation loc,
|
||||
VarDecl *property,
|
||||
@@ -2482,22 +2520,10 @@ static SILFunction *getOrCreateKeyPathGetter(SILGenFunction &SGF,
|
||||
|
||||
Scope scope(subSGF, loc);
|
||||
|
||||
auto paramOrigValue = subSGF.emitManagedRValueWithCleanup(paramArg);
|
||||
auto paramSubstValue = subSGF.emitOrigToSubstValue(loc, paramOrigValue,
|
||||
AbstractionPattern::getOpaque(),
|
||||
baseType);
|
||||
|
||||
// Upcast a class instance to the property's declared type if necessary.
|
||||
if (auto propertyClass = dyn_cast<ClassDecl>(property->getDeclContext())) {
|
||||
if (baseType->getClassOrBoundGenericClass() != propertyClass) {
|
||||
do {
|
||||
baseType = baseType->getSuperclass()->getCanonicalType();
|
||||
} while (baseType->getClassOrBoundGenericClass() != propertyClass);
|
||||
paramSubstValue = subSGF.B.createUpcast(loc, paramSubstValue,
|
||||
SILType::getPrimitiveObjectType(baseType));
|
||||
}
|
||||
}
|
||||
|
||||
auto paramSubstValue = emitKeyPathRValueBase(subSGF, property,
|
||||
loc, paramArg,
|
||||
baseType);
|
||||
|
||||
auto subs = baseType->getContextSubstitutionMap(subSGF.SGM.M.getSwiftModule(),
|
||||
property->getInnermostDeclContext()->getInnermostTypeContext());
|
||||
SmallVector<Substitution, 4> subsList;
|
||||
@@ -2602,20 +2628,9 @@ SILFunction *getOrCreateKeyPathSetter(SILGenFunction &SGF,
|
||||
|
||||
LValue lv;
|
||||
if (property->isSetterNonMutating()) {
|
||||
auto baseOrig = subSGF.emitManagedRValueWithCleanup(baseArg);
|
||||
auto baseSubst = subSGF.emitOrigToSubstValue(loc, baseOrig,
|
||||
AbstractionPattern::getOpaque(),
|
||||
baseType);
|
||||
// Upcast a class instance to the property's declared type if necessary.
|
||||
if (auto propertyClass = dyn_cast<ClassDecl>(property->getDeclContext())) {
|
||||
if (baseType->getClassOrBoundGenericClass() != propertyClass) {
|
||||
do {
|
||||
baseType = baseType->getSuperclass()->getCanonicalType();
|
||||
} while (baseType->getClassOrBoundGenericClass() != propertyClass);
|
||||
baseSubst = subSGF.B.createUpcast(loc, baseSubst,
|
||||
SILType::getPrimitiveObjectType(baseType));
|
||||
}
|
||||
}
|
||||
auto baseSubst = emitKeyPathRValueBase(subSGF, property,
|
||||
loc, baseArg,
|
||||
baseType);
|
||||
|
||||
lv = LValue::forValue(baseSubst, baseType);
|
||||
} else {
|
||||
@@ -2623,6 +2638,16 @@ SILFunction *getOrCreateKeyPathSetter(SILGenFunction &SGF,
|
||||
lv = LValue::forAddress(baseOrig, None,
|
||||
AbstractionPattern::getOpaque(),
|
||||
baseType);
|
||||
|
||||
// Open an existential lvalue, if necessary.
|
||||
if (baseType->isAnyExistentialType()) {
|
||||
ArchetypeType *opened;
|
||||
baseType = baseType->openAnyExistentialType(opened)->getCanonicalType();
|
||||
lv = subSGF.emitOpenExistentialLValue(loc, std::move(lv),
|
||||
CanArchetypeType(opened),
|
||||
baseType,
|
||||
AccessKind::ReadWrite);
|
||||
}
|
||||
}
|
||||
|
||||
auto subs = baseType->getContextSubstitutionMap(subSGF.SGM.M.getSwiftModule(),
|
||||
|
||||
@@ -1751,13 +1751,20 @@ namespace {
|
||||
|
||||
LValue LValue::forValue(ManagedValue value,
|
||||
CanType substFormalType) {
|
||||
assert(value.getType().isObject());
|
||||
LValueTypeData typeData = getValueTypeData(substFormalType,
|
||||
value.getValue());
|
||||
if (value.getType().isObject()) {
|
||||
LValueTypeData typeData = getValueTypeData(substFormalType,
|
||||
value.getValue());
|
||||
|
||||
LValue lv;
|
||||
lv.add<ValueComponent>(value, None, typeData, /*isRValue=*/true);
|
||||
return lv;
|
||||
LValue lv;
|
||||
lv.add<ValueComponent>(value, None, typeData, /*isRValue=*/true);
|
||||
return lv;
|
||||
} else {
|
||||
// Treat an address-only value as an lvalue we only read from.
|
||||
if (!value.isLValue())
|
||||
value = ManagedValue::forLValue(value.getValue());
|
||||
return forAddress(value, None, AbstractionPattern(substFormalType),
|
||||
substFormalType);
|
||||
}
|
||||
}
|
||||
|
||||
LValue LValue::forAddress(ManagedValue address,
|
||||
|
||||
@@ -431,13 +431,7 @@ public:
|
||||
// Metatypes and bases of non-mutating setters on value types
|
||||
// are always rvalues.
|
||||
if (!SubstSelfType->getRValueInstanceType()->mayHaveSuperclass()) {
|
||||
if (self.getType().isObject())
|
||||
return LValue::forValue(self, SubstSelfType);
|
||||
else {
|
||||
if (!self.isLValue())
|
||||
self = ManagedValue::forLValue(self.getValue());
|
||||
return LValue::forAddress(self, None, selfPattern, SubstSelfType);
|
||||
}
|
||||
return LValue::forValue(self, SubstSelfType);
|
||||
}
|
||||
|
||||
CanType witnessSelfType =
|
||||
|
||||
@@ -31,6 +31,10 @@ extension P {
|
||||
var z: String {
|
||||
return y
|
||||
}
|
||||
var w: String {
|
||||
get { return "" }
|
||||
nonmutating set { }
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil hidden @{{.*}}storedProperties
|
||||
@@ -171,3 +175,10 @@ class BB<U, V>: AA<V> {
|
||||
func keyPathForInheritedMember() {
|
||||
_ = \BB<Int, String>.a
|
||||
}
|
||||
|
||||
func keyPathForExistentialMember() {
|
||||
_ = \P.x
|
||||
_ = \P.y
|
||||
_ = \P.z
|
||||
_ = \P.w
|
||||
}
|
||||
|
||||
@@ -279,12 +279,18 @@ keyPath.test("computed properties") {
|
||||
|
||||
class AB {
|
||||
}
|
||||
class ABC: AB {
|
||||
class ABC: AB, ABCProtocol {
|
||||
var a = LifetimeTracked(1)
|
||||
var b = LifetimeTracked(2)
|
||||
var c = LifetimeTracked(3)
|
||||
}
|
||||
|
||||
protocol ABCProtocol {
|
||||
var a: LifetimeTracked { get }
|
||||
var b: LifetimeTracked { get set }
|
||||
var c: LifetimeTracked { get nonmutating set }
|
||||
}
|
||||
|
||||
keyPath.test("dynamically-typed application") {
|
||||
let cPaths = [\ABC.a, \ABC.b, \ABC.c]
|
||||
|
||||
@@ -312,6 +318,32 @@ keyPath.test("dynamically-typed application") {
|
||||
expectTrue(wrongFields[1] == nil)
|
||||
expectTrue(wrongFields[2] == nil)
|
||||
}
|
||||
|
||||
var protoErasedSubject: ABCProtocol = subject
|
||||
let protoErasedPathA = \ABCProtocol.a
|
||||
let protoErasedPathB = \ABCProtocol.b
|
||||
let protoErasedPathC = \ABCProtocol.c
|
||||
|
||||
do {
|
||||
expectTrue(protoErasedSubject.a ===
|
||||
protoErasedSubject[keyPath: protoErasedPathA])
|
||||
|
||||
let newB = LifetimeTracked(4)
|
||||
expectTrue(protoErasedSubject.b ===
|
||||
protoErasedSubject[keyPath: protoErasedPathB])
|
||||
protoErasedSubject[keyPath: protoErasedPathB] = newB
|
||||
expectTrue(protoErasedSubject.b ===
|
||||
protoErasedSubject[keyPath: protoErasedPathB])
|
||||
expectTrue(protoErasedSubject.b === newB)
|
||||
|
||||
let newC = LifetimeTracked(5)
|
||||
expectTrue(protoErasedSubject.c ===
|
||||
protoErasedSubject[keyPath: protoErasedPathC])
|
||||
protoErasedSubject[keyPath: protoErasedPathC] = newC
|
||||
expectTrue(protoErasedSubject.c ===
|
||||
protoErasedSubject[keyPath: protoErasedPathC])
|
||||
expectTrue(protoErasedSubject.c === newC)
|
||||
}
|
||||
}
|
||||
|
||||
runAllTests()
|
||||
|
||||
Reference in New Issue
Block a user