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);
   }
 };