SILGen: Handle existential keypath root types.

SR-4917|rdar://problem/32254554
This commit is contained in:
Joe Groff
2017-05-31 16:01:02 -07:00
parent 1ce8753796
commit 4fc0b7df96
7 changed files with 129 additions and 44 deletions

View File

@@ -589,6 +589,9 @@ public:
/// bound. /// bound.
bool isClassExistentialType(); 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. /// Break an existential down into a set of constraints.
ExistentialLayout getExistentialLayout(); ExistentialLayout getExistentialLayout();

View File

@@ -4146,3 +4146,16 @@ getRecursivePropertiesFromSubstitutions(SubstitutionList Params) {
} }
return props; 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;
}

View File

@@ -2415,6 +2415,44 @@ RValue RValueEmitter::visitObjCSelectorExpr(ObjCSelectorExpr *e, SGFContext C) {
return RValue(SGF, e, ManagedValue::forUnmanaged(selectorValue)); 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, static SILFunction *getOrCreateKeyPathGetter(SILGenFunction &SGF,
SILLocation loc, SILLocation loc,
VarDecl *property, VarDecl *property,
@@ -2482,22 +2520,10 @@ static SILFunction *getOrCreateKeyPathGetter(SILGenFunction &SGF,
Scope scope(subSGF, loc); Scope scope(subSGF, loc);
auto paramOrigValue = subSGF.emitManagedRValueWithCleanup(paramArg); auto paramSubstValue = emitKeyPathRValueBase(subSGF, property,
auto paramSubstValue = subSGF.emitOrigToSubstValue(loc, paramOrigValue, loc, paramArg,
AbstractionPattern::getOpaque(), baseType);
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 subs = baseType->getContextSubstitutionMap(subSGF.SGM.M.getSwiftModule(), auto subs = baseType->getContextSubstitutionMap(subSGF.SGM.M.getSwiftModule(),
property->getInnermostDeclContext()->getInnermostTypeContext()); property->getInnermostDeclContext()->getInnermostTypeContext());
SmallVector<Substitution, 4> subsList; SmallVector<Substitution, 4> subsList;
@@ -2602,20 +2628,9 @@ SILFunction *getOrCreateKeyPathSetter(SILGenFunction &SGF,
LValue lv; LValue lv;
if (property->isSetterNonMutating()) { if (property->isSetterNonMutating()) {
auto baseOrig = subSGF.emitManagedRValueWithCleanup(baseArg); auto baseSubst = emitKeyPathRValueBase(subSGF, property,
auto baseSubst = subSGF.emitOrigToSubstValue(loc, baseOrig, loc, baseArg,
AbstractionPattern::getOpaque(), baseType);
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));
}
}
lv = LValue::forValue(baseSubst, baseType); lv = LValue::forValue(baseSubst, baseType);
} else { } else {
@@ -2623,6 +2638,16 @@ SILFunction *getOrCreateKeyPathSetter(SILGenFunction &SGF,
lv = LValue::forAddress(baseOrig, None, lv = LValue::forAddress(baseOrig, None,
AbstractionPattern::getOpaque(), AbstractionPattern::getOpaque(),
baseType); 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(), auto subs = baseType->getContextSubstitutionMap(subSGF.SGM.M.getSwiftModule(),

View File

@@ -1751,13 +1751,20 @@ namespace {
LValue LValue::forValue(ManagedValue value, LValue LValue::forValue(ManagedValue value,
CanType substFormalType) { CanType substFormalType) {
assert(value.getType().isObject()); if (value.getType().isObject()) {
LValueTypeData typeData = getValueTypeData(substFormalType, LValueTypeData typeData = getValueTypeData(substFormalType,
value.getValue()); value.getValue());
LValue lv; LValue lv;
lv.add<ValueComponent>(value, None, typeData, /*isRValue=*/true); lv.add<ValueComponent>(value, None, typeData, /*isRValue=*/true);
return lv; 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, LValue LValue::forAddress(ManagedValue address,

View File

@@ -431,13 +431,7 @@ public:
// Metatypes and bases of non-mutating setters on value types // Metatypes and bases of non-mutating setters on value types
// are always rvalues. // are always rvalues.
if (!SubstSelfType->getRValueInstanceType()->mayHaveSuperclass()) { if (!SubstSelfType->getRValueInstanceType()->mayHaveSuperclass()) {
if (self.getType().isObject()) return LValue::forValue(self, SubstSelfType);
return LValue::forValue(self, SubstSelfType);
else {
if (!self.isLValue())
self = ManagedValue::forLValue(self.getValue());
return LValue::forAddress(self, None, selfPattern, SubstSelfType);
}
} }
CanType witnessSelfType = CanType witnessSelfType =

View File

@@ -31,6 +31,10 @@ extension P {
var z: String { var z: String {
return y return y
} }
var w: String {
get { return "" }
nonmutating set { }
}
} }
// CHECK-LABEL: sil hidden @{{.*}}storedProperties // CHECK-LABEL: sil hidden @{{.*}}storedProperties
@@ -171,3 +175,10 @@ class BB<U, V>: AA<V> {
func keyPathForInheritedMember() { func keyPathForInheritedMember() {
_ = \BB<Int, String>.a _ = \BB<Int, String>.a
} }
func keyPathForExistentialMember() {
_ = \P.x
_ = \P.y
_ = \P.z
_ = \P.w
}

View File

@@ -279,12 +279,18 @@ keyPath.test("computed properties") {
class AB { class AB {
} }
class ABC: AB { class ABC: AB, ABCProtocol {
var a = LifetimeTracked(1) var a = LifetimeTracked(1)
var b = LifetimeTracked(2) var b = LifetimeTracked(2)
var c = LifetimeTracked(3) 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") { keyPath.test("dynamically-typed application") {
let cPaths = [\ABC.a, \ABC.b, \ABC.c] let cPaths = [\ABC.a, \ABC.b, \ABC.c]
@@ -312,6 +318,32 @@ keyPath.test("dynamically-typed application") {
expectTrue(wrongFields[1] == nil) expectTrue(wrongFields[1] == nil)
expectTrue(wrongFields[2] == 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() runAllTests()