Merge pull request #14893 from jckarter/keypath-resilience-silgen-refactor
SILGen: Refactor key path component lowering.
diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h
index f005fb5..0e38da3 100644
--- a/include/swift/AST/Expr.h
+++ b/include/swift/AST/Expr.h
@@ -4909,7 +4909,7 @@
case Kind::OptionalForce:
case Kind::UnresolvedProperty:
case Kind::Property:
- llvm_unreachable("no index expr for this kind");
+ return nullptr;
}
}
@@ -4942,7 +4942,7 @@
case Kind::OptionalForce:
case Kind::UnresolvedProperty:
case Kind::Property:
- llvm_unreachable("no hashable conformances for this kind");
+ return {};
}
}
diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp
index e3be135..088b97b 100644
--- a/lib/SILGen/SILGen.cpp
+++ b/lib/SILGen/SILGen.cpp
@@ -1158,6 +1158,53 @@
if (auto setter = vd->getSetter())
emitFunction(setter);
}
+
+ tryEmitPropertyDescriptor(vd);
+}
+
+static bool doesPropertyNeedDescriptor(AbstractStorageDecl *decl) {
+ // The storage needs a descriptor if it sits at a module's ABI boundary,
+ // meaning it has public linkage.
+
+ // Any property that's potentially resilient should have accessors
+ // synthesized.
+ if (!decl->getGetter())
+ return false;
+
+ // TODO: If previous versions of an ABI-stable binary needed the descriptor,
+ // then we still do.
+
+ auto getter = SILDeclRef(decl->getGetter());
+ auto getterLinkage = getter.getLinkage(ForDefinition);
+
+ switch (getterLinkage) {
+ case SILLinkage::Public:
+ case SILLinkage::PublicNonABI:
+ // We may need a descriptor.
+ break;
+
+ case SILLinkage::Shared:
+ case SILLinkage::Private:
+ case SILLinkage::Hidden:
+ // Don't need a public descriptor.
+ return false;
+
+ case SILLinkage::HiddenExternal:
+ case SILLinkage::PrivateExternal:
+ case SILLinkage::PublicExternal:
+ case SILLinkage::SharedExternal:
+ llvm_unreachable("should be definition linkage?");
+ }
+
+ // TODO: We might be able to avoid a descriptor if the property is committed
+ // to being implemented a certain way, such as if it's promised to remain
+ // stored, or is computed with inlinable accessors, and can't change its
+ // mutability (because it's already promised to be mutable or fully immutable).
+ return true;
+}
+
+void SILGenModule::tryEmitPropertyDescriptor(AbstractStorageDecl *decl) {
+ // TODO
}
void SILGenModule::emitPropertyBehavior(VarDecl *vd) {
diff --git a/lib/SILGen/SILGen.h b/lib/SILGen/SILGen.h
index 5c040e9..0a8275d 100644
--- a/lib/SILGen/SILGen.h
+++ b/lib/SILGen/SILGen.h
@@ -333,6 +333,12 @@
/// Emit a global initialization.
void emitGlobalInitialization(PatternBindingDecl *initializer, unsigned elt);
+ SILDeclRef getGetterDeclRef(AbstractStorageDecl *decl);
+ SILDeclRef getSetterDeclRef(AbstractStorageDecl *decl);
+ SILDeclRef getAddressorDeclRef(AbstractStorageDecl *decl,
+ AccessKind accessKind);
+ SILDeclRef getMaterializeForSetDeclRef(AbstractStorageDecl *decl);
+
/// Known functions for bridging.
SILDeclRef getStringToNSStringFn();
SILDeclRef getNSStringToStringFn();
@@ -421,6 +427,9 @@
SubstitutionList
getNonMemberVarDeclSubstitutions(VarDecl *var);
+ /// Emit a property descriptor for the given storage decl if it needs one.
+ void tryEmitPropertyDescriptor(AbstractStorageDecl *decl);
+
private:
/// Emit the deallocator for a class that uses the objc allocator.
void emitObjCAllocatorDestructor(ClassDecl *cd, DestructorDecl *dd);
diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp
index 7ab69c1..3f8a2f2 100644
--- a/lib/SILGen/SILGenApply.cpp
+++ b/lib/SILGen/SILGenApply.cpp
@@ -5017,7 +5017,7 @@
return Preparer.prepare();
}
-SILDeclRef SILGenFunction::getGetterDeclRef(AbstractStorageDecl *storage) {
+SILDeclRef SILGenModule::getGetterDeclRef(AbstractStorageDecl *storage) {
auto *getter = storage->getGetter();
return SILDeclRef(getter, SILDeclRef::Kind::Func)
.asForeign(requiresForeignEntryPoint(getter));
@@ -5056,7 +5056,7 @@
return emission.apply(c);
}
-SILDeclRef SILGenFunction::getSetterDeclRef(AbstractStorageDecl *storage) {
+SILDeclRef SILGenModule::getSetterDeclRef(AbstractStorageDecl *storage) {
auto *setter = storage->getSetter();
return SILDeclRef(setter, SILDeclRef::Kind::Func)
.asForeign(requiresForeignEntryPoint(setter));
@@ -5122,7 +5122,7 @@
}
SILDeclRef
-SILGenFunction::getMaterializeForSetDeclRef(AbstractStorageDecl *storage) {
+SILGenModule::getMaterializeForSetDeclRef(AbstractStorageDecl *storage) {
return SILDeclRef(storage->getMaterializeForSetFunc(),
SILDeclRef::Kind::Func);
}
@@ -5199,8 +5199,8 @@
optionalCallback, callbackStorage);
}
-SILDeclRef SILGenFunction::getAddressorDeclRef(AbstractStorageDecl *storage,
- AccessKind accessKind) {
+SILDeclRef SILGenModule::getAddressorDeclRef(AbstractStorageDecl *storage,
+ AccessKind accessKind) {
FuncDecl *addressorFunc = storage->getAddressorForAccess(accessKind);
return SILDeclRef(addressorFunc, SILDeclRef::Kind::Func);
}
diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp
index 14adda3..72d725b7 100644
--- a/lib/SILGen/SILGenExpr.cpp
+++ b/lib/SILGen/SILGenExpr.cpp
@@ -31,6 +31,7 @@
#include "swift/AST/ForeignErrorConvention.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/ASTMangler.h"
+#include "swift/AST/ParameterList.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/SubstitutionMap.h"
#include "swift/AST/Types.h"
@@ -1049,7 +1050,7 @@
assert(var->hasAccessorFunctions() && "Unknown rvalue case");
- SILDeclRef getter = getGetterDeclRef(var);
+ SILDeclRef getter = SGM.getGetterDeclRef(var);
ArgumentSource selfSource;
@@ -1118,10 +1119,10 @@
case AccessStrategy::DirectToAccessor:
case AccessStrategy::DispatchToAccessor:
- return SGF.getGetterDeclRef(storage);
+ return SGF.SGM.getGetterDeclRef(storage);
case AccessStrategy::Addressor:
- return SGF.getAddressorDeclRef(storage, AccessKind::Read);
+ return SGF.SGM.getAddressorDeclRef(storage, AccessKind::Read);
}
llvm_unreachable("should already have been filtered out!");
}
@@ -3058,7 +3059,7 @@
return indexValue;
}
-static SILFunction *getOrCreateKeyPathGetter(SILGenFunction &SGF,
+static SILFunction *getOrCreateKeyPathGetter(SILGenModule &SGM,
SILLocation loc,
AbstractStorageDecl *property,
SubstitutionList subs,
@@ -3074,17 +3075,17 @@
// Build the signature of the thunk as expected by the keypath runtime.
SILType loweredBaseTy, loweredPropTy;
{
- GenericContextScope scope(SGF.SGM.Types, genericSig);
- loweredBaseTy = SGF.getLoweredType(AbstractionPattern::getOpaque(),
- baseType);
- loweredPropTy = SGF.getLoweredType(AbstractionPattern::getOpaque(),
- propertyType);
+ GenericContextScope scope(SGM.Types, genericSig);
+ loweredBaseTy = SGM.Types.getLoweredType(AbstractionPattern::getOpaque(),
+ baseType);
+ loweredPropTy = SGM.Types.getLoweredType(AbstractionPattern::getOpaque(),
+ propertyType);
}
SmallVector<SILParameterInfo, 2> params;
params.push_back({loweredBaseTy.getSwiftRValueType(),
ParameterConvention::Indirect_In});
- auto &C = SGF.getASTContext();
+ auto &C = SGM.getASTContext();
if (!indexes.empty())
params.push_back({C.getUnsafeRawPointerDecl()->getDeclaredType()
->getCanonicalType(),
@@ -3099,7 +3100,7 @@
/*noescape*/ false),
SILCoroutineKind::None,
ParameterConvention::Direct_Unowned,
- params, {}, result, None, SGF.getASTContext());
+ params, {}, result, None, SGM.getASTContext());
// Find the function and see if we already created it.
SmallVector<CanType, 2> interfaceSubs;
@@ -3111,7 +3112,7 @@
auto name = Mangle::ASTMangler()
.mangleKeyPathGetterThunkHelper(property, genericSig, baseType,
interfaceSubs);
- auto thunk = SGF.SGM.M.getOrCreateSharedFunction(
+ auto thunk = SGM.M.getOrCreateSharedFunction(
loc, name, signature, IsBare, IsNotTransparent, IsNotSerialized,
ProfileCounter(), IsThunk);
if (!thunk->empty())
@@ -3119,7 +3120,6 @@
// Emit the thunk, which accesses the underlying property normally with
// reabstraction where necessary.
- auto &SGM = SGF.SGM;
if (genericEnv) {
baseType = genericEnv->mapTypeIntoContext(baseType)->getCanonicalType();
propertyType = genericEnv->mapTypeIntoContext(propertyType)
@@ -3174,7 +3174,7 @@
return thunk;
}
-SILFunction *getOrCreateKeyPathSetter(SILGenFunction &SGF,
+SILFunction *getOrCreateKeyPathSetter(SILGenModule &SGM,
SILLocation loc,
AbstractStorageDecl *property,
SubstitutionList subs,
@@ -3190,14 +3190,14 @@
// Build the signature of the thunk as expected by the keypath runtime.
SILType loweredBaseTy, loweredPropTy;
{
- GenericContextScope scope(SGF.SGM.Types, genericSig);
- loweredBaseTy = SGF.getLoweredType(AbstractionPattern::getOpaque(),
- baseType);
- loweredPropTy = SGF.getLoweredType(AbstractionPattern::getOpaque(),
- propertyType);
+ GenericContextScope scope(SGM.Types, genericSig);
+ loweredBaseTy = SGM.Types.getLoweredType(AbstractionPattern::getOpaque(),
+ baseType);
+ loweredPropTy = SGM.Types.getLoweredType(AbstractionPattern::getOpaque(),
+ propertyType);
}
- auto &C = SGF.getASTContext();
+ auto &C = SGM.getASTContext();
SmallVector<SILParameterInfo, 3> params;
// property value
@@ -3220,7 +3220,7 @@
/*noescape*/ false),
SILCoroutineKind::None,
ParameterConvention::Direct_Unowned,
- params, {}, {}, None, SGF.getASTContext());
+ params, {}, {}, None, SGM.getASTContext());
// Mangle the name of the thunk to see if we already created it.
SmallString<64> nameBuf;
@@ -3235,7 +3235,7 @@
genericSig,
baseType,
interfaceSubs);
- auto thunk = SGF.SGM.M.getOrCreateSharedFunction(
+ auto thunk = SGM.M.getOrCreateSharedFunction(
loc, name, signature, IsBare, IsNotTransparent, IsNotSerialized,
ProfileCounter(), IsThunk);
if (!thunk->empty())
@@ -3243,7 +3243,6 @@
// Emit the thunk, which accesses the underlying property normally with
// reabstraction where necessary.
- auto &SGM = SGF.SGM;
if (genericEnv) {
baseType = genericEnv->mapTypeIntoContext(baseType)->getCanonicalType();
propertyType = genericEnv->mapTypeIntoContext(propertyType)
@@ -3330,7 +3329,7 @@
}
static void
-getOrCreateKeyPathEqualsAndHash(SILGenFunction &SGF,
+getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM,
SILLocation loc,
GenericEnvironment *genericEnv,
ArrayRef<KeyPathPatternComponent::Index> indexes,
@@ -3346,7 +3345,7 @@
? genericEnv->getGenericSignature()->getCanonicalSignature()
: nullptr;
- auto &C = SGF.getASTContext();
+ auto &C = SGM.getASTContext();
auto unsafeRawPointerTy = C.getUnsafeRawPointerDecl()->getDeclaredType()
->getCanonicalType();
auto boolTy = C.getBoolDecl()->getDeclaredType()->getCanonicalType();
@@ -3361,15 +3360,15 @@
SmallVector<TupleTypeElt, 2> indexElts;
for (auto &elt : indexes) {
- indexElts.push_back(SGF.F.mapTypeIntoContext(elt.FormalType));
+ indexElts.push_back(GenericEnvironment::mapTypeIntoContext(genericEnv,
+ elt.FormalType));
}
- auto indexTupleTy = TupleType::get(indexElts, SGF.getASTContext())
+ auto indexTupleTy = TupleType::get(indexElts, SGM.getASTContext())
->getCanonicalType();
RValue indexValue(indexTupleTy);
- auto indexLoweredTy = SGF.getLoweredType(indexTupleTy);
- auto &SGM = SGF.SGM;
+ auto indexLoweredTy = SGM.Types.getLoweredType(indexTupleTy);
// Get or create the equals witness
[&unsafeRawPointerTy, &boolTy, &genericSig, &C, &indexTypes, &equals, &loc,
&SGM, &genericEnv, &indexLoweredTy, &hashableProto, &indexes]{
@@ -3652,7 +3651,7 @@
}
static KeyPathPatternComponent::ComputedPropertyId
-getIdForKeyPathComponentComputedProperty(SILGenFunction &SGF,
+getIdForKeyPathComponentComputedProperty(SILGenModule &SGM,
AbstractStorageDecl *storage,
AccessStrategy strategy) {
switch (strategy) {
@@ -3668,11 +3667,11 @@
// Clang-imported thing), we'll need some other sort of
// stable identifier.
auto getterRef = SILDeclRef(storage->getGetter(), SILDeclRef::Kind::Func);
- return SGF.SGM.getFunction(getterRef, NotForDefinition);
+ return SGM.getFunction(getterRef, NotForDefinition);
}
case AccessStrategy::DispatchToAccessor: {
// Identify the property by its vtable or wtable slot.
- return SGF.getGetterDeclRef(storage);
+ return SGM.getGetterDeclRef(storage);
}
case AccessStrategy::BehaviorStorage:
llvm_unreachable("unpossible");
@@ -3680,6 +3679,169 @@
llvm_unreachable("unhandled access strategy");
}
+static void
+lowerKeyPathSubscriptIndexPatterns(
+ SILGenModule &SGM,
+ SmallVectorImpl<KeyPathPatternComponent::Index> &indexPatterns,
+ SubscriptDecl *subscript,
+ SubstitutionList subscriptSubs,
+ ArrayRef<ProtocolConformanceRef> indexHashables,
+ unsigned &baseOperand,
+ bool &needsGenericContext) {
+ // Capturing an index value dependent on the generic context means we
+ // need the generic context captured in the key path.
+ auto subMap =
+ subscript->getGenericSignature()->getSubstitutionMap(subscriptSubs);
+ auto subscriptSubstTy = subscript->getInterfaceType().subst(subMap);
+ needsGenericContext |= subscriptSubstTy->hasArchetype();
+
+ unsigned i = 0;
+ for (auto *index : *subscript->getIndices()) {
+ auto indexTy = index->getInterfaceType().subst(subMap)
+ ->getCanonicalType();
+ auto hashable = indexHashables[i++];
+ assert(hashable.isAbstract() ||
+ hashable.getConcrete()->getType()->isEqual(indexTy));
+
+ auto indexLoweredTy = SGM.Types.getLoweredType(
+ AbstractionPattern::getOpaque(),
+ indexTy);
+ indexLoweredTy = SILType::getPrimitiveType(
+ indexLoweredTy.getSwiftRValueType()->mapTypeOutOfContext()
+ ->getCanonicalType(),
+ indexLoweredTy.getCategory());
+ indexPatterns.push_back({baseOperand++,
+ indexTy->mapTypeOutOfContext()
+ ->getCanonicalType(),
+ indexLoweredTy,
+ hashable});
+ }
+};
+
+static KeyPathPatternComponent
+emitKeyPathComponentForDecl(SILGenModule &SGM,
+ SILLocation loc,
+ GenericEnvironment *genericEnv,
+ unsigned &baseOperand,
+ bool &needsGenericContext,
+ SubstitutionList subs,
+ AbstractStorageDecl *storage,
+ ArrayRef<ProtocolConformanceRef> indexHashables,
+ CanType baseTy) {
+ if (auto var = dyn_cast<VarDecl>(storage)) {
+ auto componentTy = baseTy->getTypeOfMember(SGM.SwiftModule, var)
+ ->getReferenceStorageReferent()
+ ->getCanonicalType();
+
+ switch (auto strategy = var->getAccessStrategy(AccessSemantics::Ordinary,
+ AccessKind::ReadWrite)) {
+ case AccessStrategy::Storage: {
+ // If the stored value would need to be reabstracted in fully opaque
+ // context, then we have to treat the component as computed.
+ auto componentObjTy = componentTy->getWithoutSpecifierType();
+ if (genericEnv)
+ componentObjTy = genericEnv->mapTypeIntoContext(componentObjTy);
+ auto storageTy = SGM.Types.getSubstitutedStorageType(var,
+ componentObjTy);
+ auto opaqueTy = SGM.Types
+ .getLoweredType(AbstractionPattern::getOpaque(), componentObjTy);
+
+ if (storageTy.getAddressType() == opaqueTy.getAddressType()) {
+ return KeyPathPatternComponent::forStoredProperty(var, componentTy);
+ }
+ LLVM_FALLTHROUGH;
+ }
+ case AccessStrategy::Addressor:
+ case AccessStrategy::DirectToAccessor:
+ case AccessStrategy::DispatchToAccessor: {
+ // We need thunks to bring the getter and setter to the right signature
+ // expected by the key path runtime.
+ auto id = getIdForKeyPathComponentComputedProperty(SGM, var,
+ strategy);
+ auto getter = getOrCreateKeyPathGetter(SGM, loc,
+ var, subs,
+ strategy,
+ needsGenericContext ? genericEnv : nullptr,
+ {},
+ baseTy, componentTy);
+
+ if (var->isSettable(var->getDeclContext())) {
+ auto setter = getOrCreateKeyPathSetter(SGM, loc,
+ var, subs,
+ strategy,
+ needsGenericContext ? genericEnv : nullptr,
+ {},
+ baseTy, componentTy);
+ return KeyPathPatternComponent::forComputedSettableProperty(id,
+ getter, setter, {}, nullptr, nullptr, componentTy);
+ } else {
+ return KeyPathPatternComponent::forComputedGettableProperty(id,
+ getter, {}, nullptr, nullptr, componentTy);
+ }
+ }
+ case AccessStrategy::BehaviorStorage:
+ llvm_unreachable("should not occur");
+ }
+ }
+
+ if (auto decl = dyn_cast<SubscriptDecl>(storage)) {
+ auto strategy = decl->getAccessStrategy(AccessSemantics::Ordinary,
+ AccessKind::ReadWrite);
+ auto baseSubscriptTy =
+ decl->getInterfaceType()->castTo<AnyFunctionType>();
+ if (auto genSubscriptTy = baseSubscriptTy->getAs<GenericFunctionType>())
+ baseSubscriptTy = genSubscriptTy->substGenericArgs(subs);
+ auto baseSubscriptInterfaceTy = cast<AnyFunctionType>(
+ baseSubscriptTy->mapTypeOutOfContext()->getCanonicalType());
+ auto componentTy = baseSubscriptInterfaceTy.getResult();
+
+ SmallVector<KeyPathPatternComponent::Index, 4> indexPatterns;
+ lowerKeyPathSubscriptIndexPatterns(SGM, indexPatterns,
+ decl, subs, indexHashables,
+ baseOperand,
+ needsGenericContext);
+
+ SILFunction *indexEquals = nullptr, *indexHash = nullptr;
+ getOrCreateKeyPathEqualsAndHash(SGM, loc,
+ needsGenericContext ? genericEnv : nullptr,
+ indexPatterns,
+ indexEquals, indexHash);
+
+ auto id = getIdForKeyPathComponentComputedProperty(SGM, decl, strategy);
+ auto getter = getOrCreateKeyPathGetter(SGM, loc,
+ decl, subs,
+ strategy,
+ needsGenericContext ? genericEnv : nullptr,
+ indexPatterns,
+ baseTy, componentTy);
+
+ auto indexPatternsCopy = SGM.getASTContext().AllocateCopy(indexPatterns);
+ if (decl->isSettable()) {
+ auto setter = getOrCreateKeyPathSetter(SGM, loc,
+ decl, subs,
+ strategy,
+ needsGenericContext ? genericEnv : nullptr,
+ indexPatterns,
+ baseTy, componentTy);
+ return KeyPathPatternComponent::forComputedSettableProperty(id,
+ getter, setter,
+ indexPatternsCopy,
+ indexEquals,
+ indexHash,
+ componentTy);
+ } else {
+ return KeyPathPatternComponent::forComputedGettableProperty(id,
+ getter,
+ indexPatternsCopy,
+ indexEquals,
+ indexHash,
+ componentTy);
+ }
+ }
+
+ llvm_unreachable("unknown kind of storage");
+}
+
RValue RValueEmitter::visitKeyPathExpr(KeyPathExpr *E, SGFContext C) {
if (E->isObjC()) {
return visit(E->getObjCStringLiteralExpr(), C);
@@ -3702,15 +3864,10 @@
auto baseTy = rootTy;
SmallVector<SILValue, 4> operands;
- auto lowerSubscriptIndices =
- [this, &operands, &needsGenericContext, baseTy, E]
- (const KeyPathExpr::Component &component) ->
- SmallVector<KeyPathPatternComponent::Index, 4> {
- // Capturing an index value dependent on the generic context means we
- // need the generic context captured in the key path.
- needsGenericContext |=
- component.getIndexExpr()->getType()->hasArchetype()
- | baseTy->hasTypeParameter();
+ auto lowerSubscriptOperands =
+ [this, &operands, E](const KeyPathExpr::Component &component) {
+ if (!component.getIndexExpr())
+ return;
// Evaluate the index arguments.
SmallVector<RValue, 2> indexValues;
@@ -3721,26 +3878,10 @@
indexValues.push_back(std::move(indexResult));
}
- SmallVector<KeyPathPatternComponent::Index, 4> indexPatterns;
- for (unsigned i : indices(indexValues)) {
- auto hashable = component.getSubscriptIndexHashableConformances()[i];
- assert(hashable.isAbstract() ||
- hashable.getConcrete()->getType()->isEqual(indexValues[i].getType()));
- auto &value = indexValues[i];
-
- auto indexTy = value.getType()->mapTypeOutOfContext()->getCanonicalType();
- auto indexLoweredTy = SGF.getLoweredType(value.getType());
- indexLoweredTy = SILType::getPrimitiveType(
- indexLoweredTy.getSwiftRValueType()->mapTypeOutOfContext()
- ->getCanonicalType(),
- indexLoweredTy.getCategory());
- indexPatterns.push_back({(unsigned)operands.size(),
- indexTy, indexLoweredTy,
- hashable});
+ for (auto &rv : indexValues) {
operands.push_back(
- std::move(indexValues[i]).forwardAsSingleValue(SGF, E));
+ std::move(rv).forwardAsSingleValue(SGF, E));
}
- return indexPatterns;
};
/// Returns true if a key path component for the given property or
@@ -3754,13 +3895,16 @@
/// Build an external key path component referencing a property or subscript
/// from another module.
auto makeExternalKeyPathComponent =
- [&](const KeyPathExpr::Component &component,
- CanType ty) -> KeyPathPatternComponent {
+ [&](const KeyPathExpr::Component &component) -> KeyPathPatternComponent {
SmallVector<KeyPathPatternComponent::Index, 4> indices;
SubstitutionList subs = component.getDeclRef().getSubstitutions();
-
+ auto decl = cast<AbstractStorageDecl>(component.getDeclRef().getDecl());
+ auto ty = decl->getStorageInterfaceType();
// Map the substitutions out of context.
if (!subs.empty()) {
+ auto sig = decl->getInnermostDeclContext()
+ ->getGenericSignatureOfContext();
+ auto subMap = sig->getSubstitutionMap(subs);
// If any of the substitutions involve local archetypes, then the
// key path pattern needs to capture the generic context, and we need
// to map the pattern substitutions out of this context.
@@ -3769,98 +3913,60 @@
return s.getReplacement()->hasArchetype();
})) {
needsGenericContext = true;
- auto sig = component.getDeclRef().getDecl()
- ->getInnermostDeclContext()
- ->getGenericSignatureOfContext();
- auto subMap = sig
- ->getSubstitutionMap(component.getDeclRef().getSubstitutions());
subMap = subMap.mapReplacementTypesOutOfContext();
SmallVector<Substitution, 4> subsBuf;
-
sig->getSubstitutions(subMap, subsBuf);
-
subs = SGF.getASTContext().AllocateCopy(subsBuf);
}
+ ty = ty.subst(subMap);
}
- if (component.getKind() == KeyPathExpr::Component::Kind::Subscript)
- indices = lowerSubscriptIndices(component);
+ if (component.getKind() == KeyPathExpr::Component::Kind::Subscript) {
+ unsigned numOperands = operands.size();
+ lowerKeyPathSubscriptIndexPatterns(SGF.SGM,
+ indices,
+ cast<SubscriptDecl>(component.getDeclRef().getDecl()),
+ component.getDeclRef().getSubstitutions(),
+ component.getSubscriptIndexHashableConformances(),
+ numOperands,
+ needsGenericContext);
+
+ lowerSubscriptOperands(component);
+
+ assert(numOperands == operands.size()
+ && "operand count out of sync");
+ }
return KeyPathPatternComponent::forExternal(
- cast<AbstractStorageDecl>(component.getDeclRef().getDecl()),
- subs,
- SGF.getASTContext().AllocateCopy(indices),
- ty);
+ decl, subs, SGF.getASTContext().AllocateCopy(indices),
+ ty->getCanonicalType());
};
for (auto &component : E->getComponents()) {
switch (auto kind = component.getKind()) {
- case KeyPathExpr::Component::Kind::Property: {
- auto decl = cast<VarDecl>(component.getDeclRef().getDecl());
- auto oldBaseTy = baseTy;
- baseTy = baseTy->getTypeOfMember(SGF.SGM.SwiftModule, decl)
- ->getReferenceStorageReferent()
- ->getCanonicalType();
-
+ case KeyPathExpr::Component::Kind::Property:
+ case KeyPathExpr::Component::Kind::Subscript: {
+ auto decl = cast<AbstractStorageDecl>(component.getDeclRef().getDecl());
+
if (shouldUseExternalKeyPathComponent(decl)) {
- loweredComponents.push_back(makeExternalKeyPathComponent(component,
- baseTy));
- continue;
- }
+ loweredComponents.push_back(makeExternalKeyPathComponent(component));
+ } else {
+ unsigned numOperands = operands.size();
+ loweredComponents.push_back(
+ emitKeyPathComponentForDecl(SGF.SGM, SILLocation(E),
+ SGF.F.getGenericEnvironment(),
+ numOperands,
+ needsGenericContext,
+ component.getDeclRef().getSubstitutions(),
+ decl,
+ component.getSubscriptIndexHashableConformances(),
+ baseTy));
+ lowerSubscriptOperands(component);
- switch (auto strategy = decl->getAccessStrategy(AccessSemantics::Ordinary,
- AccessKind::ReadWrite)) {
- case AccessStrategy::Storage: {
- // If the stored value would need to be reabstracted in fully opaque
- // context, then we have to treat the component as computed.
- auto componentObjTy =
- component.getComponentType()->getWithoutSpecifierType();
- auto storageTy = SGF.SGM.Types.getSubstitutedStorageType(decl,
- componentObjTy);
- auto opaqueTy = SGF.getLoweredType(AbstractionPattern::getOpaque(),
- componentObjTy);
-
- if (storageTy.getAddressType() == opaqueTy.getAddressType()) {
- loweredComponents.push_back(
- KeyPathPatternComponent::forStoredProperty(decl, baseTy));
- break;
- }
- LLVM_FALLTHROUGH;
+ assert(numOperands == operands.size()
+ && "operand count out of sync");
}
- case AccessStrategy::Addressor:
- case AccessStrategy::DirectToAccessor:
- case AccessStrategy::DispatchToAccessor: {
- // We need thunks to bring the getter and setter to the right signature
- // expected by the key path runtime.
- auto id = getIdForKeyPathComponentComputedProperty(SGF, decl,
- strategy);
- auto getter = getOrCreateKeyPathGetter(SGF, SILLocation(E),
- decl, component.getDeclRef().getSubstitutions(),
- strategy,
- needsGenericContext ? SGF.F.getGenericEnvironment() : nullptr,
- {},
- oldBaseTy, baseTy);
-
- if (decl->isSettable(decl->getDeclContext())) {
- auto setter = getOrCreateKeyPathSetter(SGF, SILLocation(E),
- decl, component.getDeclRef().getSubstitutions(),
- strategy,
- needsGenericContext ? SGF.F.getGenericEnvironment() : nullptr,
- {},
- oldBaseTy, baseTy);
- loweredComponents.push_back(
- KeyPathPatternComponent::forComputedSettableProperty(id,
- getter, setter, {}, nullptr, nullptr, baseTy));
- } else {
- loweredComponents.push_back(
- KeyPathPatternComponent::forComputedGettableProperty(id,
- getter, {}, nullptr, nullptr, baseTy));
- }
- break;
- }
- case AccessStrategy::BehaviorStorage:
- llvm_unreachable("should not occur");
- }
-
+ baseTy = loweredComponents.back().getComponentType();
+
break;
}
@@ -3889,68 +3995,6 @@
break;
}
- case KeyPathExpr::Component::Kind::Subscript: {
- auto decl = cast<SubscriptDecl>(component.getDeclRef().getDecl());
- auto strategy = decl->getAccessStrategy(AccessSemantics::Ordinary,
- AccessKind::ReadWrite);
- auto oldBaseTy = baseTy;
- auto baseSubscriptTy =
- decl->getInterfaceType()->castTo<AnyFunctionType>();
- if (auto genSubscriptTy = baseSubscriptTy->getAs<GenericFunctionType>())
- baseSubscriptTy = genSubscriptTy
- ->substGenericArgs(component.getDeclRef().getSubstitutions());
- auto baseSubscriptInterfaceTy = cast<AnyFunctionType>(
- baseSubscriptTy->mapTypeOutOfContext()->getCanonicalType());
- baseTy = baseSubscriptInterfaceTy.getResult();
-
- if (shouldUseExternalKeyPathComponent(decl)) {
- loweredComponents.push_back(makeExternalKeyPathComponent(component,
- baseTy));
- continue;
- }
-
- auto indexPatterns = lowerSubscriptIndices(component);
- SILFunction *indexEquals = nullptr, *indexHash = nullptr;
- getOrCreateKeyPathEqualsAndHash(SGF, SILLocation(E),
- needsGenericContext ? SGF.F.getGenericEnvironment() : nullptr,
- indexPatterns,
- indexEquals, indexHash);
-
- auto id = getIdForKeyPathComponentComputedProperty(SGF, decl, strategy);
- auto getter = getOrCreateKeyPathGetter(SGF, SILLocation(E),
- decl, component.getDeclRef().getSubstitutions(),
- strategy,
- needsGenericContext ? SGF.F.getGenericEnvironment() : nullptr,
- indexPatterns,
- oldBaseTy, baseTy);
-
- auto indexPatternsCopy = SGF.getASTContext().AllocateCopy(indexPatterns);
- if (decl->isSettable()) {
- auto setter = getOrCreateKeyPathSetter(SGF, SILLocation(E),
- decl, component.getDeclRef().getSubstitutions(),
- strategy,
- needsGenericContext ? SGF.F.getGenericEnvironment() : nullptr,
- indexPatterns,
- oldBaseTy, baseTy);
- loweredComponents.push_back(
- KeyPathPatternComponent::forComputedSettableProperty(id,
- getter, setter,
- indexPatternsCopy,
- indexEquals,
- indexHash,
- baseTy));
- } else {
- loweredComponents.push_back(
- KeyPathPatternComponent::forComputedGettableProperty(id,
- getter,
- indexPatternsCopy,
- indexEquals,
- indexHash,
- baseTy));
- }
- break;
- }
-
case KeyPathExpr::Component::Kind::Invalid:
case KeyPathExpr::Component::Kind::UnresolvedProperty:
case KeyPathExpr::Component::Kind::UnresolvedSubscript:
diff --git a/lib/SILGen/SILGenFunction.h b/lib/SILGen/SILGenFunction.h
index 3b18174..a41a7bf 100644
--- a/lib/SILGen/SILGenFunction.h
+++ b/lib/SILGen/SILGenFunction.h
@@ -1110,14 +1110,12 @@
CanType baseFormalType,
SILDeclRef accessor);
- SILDeclRef getGetterDeclRef(AbstractStorageDecl *decl);
RValue emitGetAccessor(SILLocation loc, SILDeclRef getter,
SubstitutionList substitutions,
ArgumentSource &&optionalSelfValue,
bool isSuper, bool isDirectAccessorUse,
RValue &&optionalSubscripts, SGFContext C);
- SILDeclRef getSetterDeclRef(AbstractStorageDecl *decl);
void emitSetAccessor(SILLocation loc, SILDeclRef setter,
SubstitutionList substitutions,
ArgumentSource &&optionalSelfValue,
@@ -1125,7 +1123,6 @@
RValue &&optionalSubscripts,
ArgumentSource &&value);
- SILDeclRef getMaterializeForSetDeclRef(AbstractStorageDecl *decl);
MaterializedLValue
emitMaterializeForSetAccessor(SILLocation loc, SILDeclRef materializeForSet,
SubstitutionList substitutions,
@@ -1142,8 +1139,6 @@
SubstitutionList witnessSubs);
void emitMaterializeForSet(AccessorDecl *decl);
- SILDeclRef getAddressorDeclRef(AbstractStorageDecl *decl,
- AccessKind accessKind);
std::pair<ManagedValue,ManagedValue>
emitAddressorAccessor(SILLocation loc, SILDeclRef addressor,
SubstitutionList substitutions,
diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp
index f3f423c..74ac49b 100644
--- a/lib/SILGen/SILGenLValue.cpp
+++ b/lib/SILGen/SILGenLValue.cpp
@@ -1100,15 +1100,15 @@
SILDeclRef getAccessor(SILGenFunction &SGF,
AccessKind accessKind) const override {
if (accessKind == AccessKind::Read) {
- return SGF.getGetterDeclRef(decl);
+ return SGF.SGM.getGetterDeclRef(decl);
} else {
- return SGF.getSetterDeclRef(decl);
+ return SGF.SGM.getSetterDeclRef(decl);
}
}
void emitAssignWithSetter(SILGenFunction &SGF, SILLocation loc,
LValue &&dest, ArgumentSource &&value) {
- SILDeclRef setter = SGF.getSetterDeclRef(decl);
+ SILDeclRef setter = SGF.SGM.getSetterDeclRef(decl);
// Pull everything out of this that we'll need, because we're
// about to modify the LValue and delete this component.
@@ -1151,7 +1151,7 @@
void set(SILGenFunction &SGF, SILLocation loc,
ArgumentSource &&value, ManagedValue base) && override {
- SILDeclRef setter = SGF.getSetterDeclRef(decl);
+ SILDeclRef setter = SGF.SGM.getSetterDeclRef(decl);
FormalEvaluationScope scope(SGF);
// Pass in just the setter.
@@ -1260,7 +1260,7 @@
optSubscripts);
}());
- SILDeclRef materializeForSet = SGF.getMaterializeForSetDeclRef(decl);
+ SILDeclRef materializeForSet = SGF.SGM.getMaterializeForSetDeclRef(decl);
MaterializedLValue materialized;
{
@@ -1421,7 +1421,7 @@
RValue get(SILGenFunction &SGF, SILLocation loc,
ManagedValue base, SGFContext c) && override {
- SILDeclRef getter = SGF.getGetterDeclRef(decl);
+ SILDeclRef getter = SGF.SGM.getGetterDeclRef(decl);
FormalEvaluationScope scope(SGF);
@@ -1578,7 +1578,7 @@
SILDeclRef getAccessor(SILGenFunction &SGF,
AccessKind accessKind) const override {
- return SGF.getAddressorDeclRef(decl, accessKind);
+ return SGF.SGM.getAddressorDeclRef(decl, accessKind);
}
ManagedValue offset(SILGenFunction &SGF, SILLocation loc, ManagedValue base,
@@ -1586,7 +1586,7 @@
assert(SGF.InFormalEvaluationScope &&
"offsetting l-value for modification without writeback scope");
- SILDeclRef addressor = SGF.getAddressorDeclRef(decl, accessKind);
+ SILDeclRef addressor = SGF.SGM.getAddressorDeclRef(decl, accessKind);
std::pair<ManagedValue, ManagedValue> result;
{
FormalEvaluationScope scope(SGF);
diff --git a/lib/SILGen/SILGenMaterializeForSet.cpp b/lib/SILGen/SILGenMaterializeForSet.cpp
index 2b41953..046948d 100644
--- a/lib/SILGen/SILGenMaterializeForSet.cpp
+++ b/lib/SILGen/SILGenMaterializeForSet.cpp
@@ -789,8 +789,8 @@
bool isDirect = (TheAccessSemantics != AccessSemantics::Ordinary);
// Call the mutable addressor.
- auto addressor = SGF.getAddressorDeclRef(WitnessStorage,
- AccessKind::ReadWrite);
+ auto addressor = SGF.SGM.getAddressorDeclRef(WitnessStorage,
+ AccessKind::ReadWrite);
std::pair<ManagedValue, ManagedValue> result;
{
FormalEvaluationScope Scope(SGF);
diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp
index e141786..b66aefa 100644
--- a/lib/SILGen/SILGenType.cpp
+++ b/lib/SILGen/SILGenType.cpp
@@ -885,6 +885,8 @@
// FIXME: Default implementations in protocols.
if (asd->isObjC() && !isa<ProtocolDecl>(asd->getDeclContext()))
SGM.emitObjCPropertyMethodThunks(asd);
+
+ SGM.tryEmitPropertyDescriptor(asd);
}
};
@@ -973,6 +975,8 @@
void visitAbstractStorageDecl(AbstractStorageDecl *vd) {
if (vd->isObjC())
SGM.emitObjCPropertyMethodThunks(vd);
+
+ SGM.tryEmitPropertyDescriptor(vd);
}
};