diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 694f584ac69..51ae86fc1d2 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -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(); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index eff1302ffe9..dc254fe43df 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -4146,3 +4146,16 @@ getRecursivePropertiesFromSubstitutions(SubstitutionList Params) { } return props; } + +Type TypeBase::openAnyExistentialType(ArchetypeType *&opened) { + assert(isAnyExistentialType()); + if (auto metaty = getAs()) { + 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; +} diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 8dc49375cfc..8df13631287 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -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(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(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 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(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(), diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp index b5132b114af..71d7fff2237 100644 --- a/lib/SILGen/SILGenLValue.cpp +++ b/lib/SILGen/SILGenLValue.cpp @@ -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(value, None, typeData, /*isRValue=*/true); - return lv; + LValue lv; + lv.add(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, diff --git a/lib/SILGen/SILGenMaterializeForSet.cpp b/lib/SILGen/SILGenMaterializeForSet.cpp index dbcbc630c95..752aa0db542 100644 --- a/lib/SILGen/SILGenMaterializeForSet.cpp +++ b/lib/SILGen/SILGenMaterializeForSet.cpp @@ -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 = diff --git a/test/SILGen/keypaths.swift b/test/SILGen/keypaths.swift index f1f1775c4aa..3bc845e0519 100644 --- a/test/SILGen/keypaths.swift +++ b/test/SILGen/keypaths.swift @@ -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: AA { func keyPathForInheritedMember() { _ = \BB.a } + +func keyPathForExistentialMember() { + _ = \P.x + _ = \P.y + _ = \P.z + _ = \P.w +} diff --git a/test/stdlib/KeyPath.swift b/test/stdlib/KeyPath.swift index f4b8a756be2..6218b837a79 100644 --- a/test/stdlib/KeyPath.swift +++ b/test/stdlib/KeyPath.swift @@ -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()