Merge pull request #12303 from jckarter/keypath-subscript-coerce-index-4.0

[4.0] Sema: Coerce the type of the index expression in a key path component to match the subscript decl's index type.
diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp
index e84e714..f370cc9 100644
--- a/lib/Sema/CSApply.cpp
+++ b/lib/Sema/CSApply.cpp
@@ -4172,9 +4172,14 @@
           
           auto dc = subscript->getInnermostDeclContext();
           SmallVector<Substitution, 4> subs;
+          SubstitutionMap subMap;
+          auto indexType = subscript->getIndicesInterfaceType();
+
           if (auto sig = dc->getGenericSignatureOfContext()) {
             // Compute substitutions to refer to the member.
             solution.computeSubstitutions(sig, locator, subs);
+            subMap = sig->getSubstitutionMap(subs);
+            indexType = indexType.subst(subMap);
           }
           
           auto resolvedTy = foundDecl->openedType->castTo<AnyFunctionType>()
@@ -4183,9 +4188,13 @@
           
           auto ref = ConcreteDeclRef(cs.getASTContext(), subscript, subs);
           
+          // Coerce the indices to the type the subscript expects.
+          auto indexExpr = coerceToType(origComponent.getIndexExpr(),
+                                        indexType,
+                                        locator);
+          
           component = KeyPathExpr::Component
-            ::forSubscriptWithPrebuiltIndexExpr(ref,
-                                            origComponent.getIndexExpr(),
+            ::forSubscriptWithPrebuiltIndexExpr(ref, indexExpr,
                                             origComponent.getSubscriptLabels(),
                                             resolvedTy,
                                             origComponent.getLoc(),
diff --git a/test/SILGen/keypaths.swift b/test/SILGen/keypaths.swift
index 5f425ad..7d28bd1 100644
--- a/test/SILGen/keypaths.swift
+++ b/test/SILGen/keypaths.swift
@@ -267,6 +267,13 @@
   _ = \IUOProperty.iuo!.x
 }
 
+class Bass: Hashable {
+  static func ==(_: Bass, _: Bass) -> Bool { return false }
+  var hashValue: Int { return 0 }
+}
+
+class Treble: Bass { }
+
 struct Subscripts<T> {
   subscript() -> T {
     get { fatalError() }
@@ -292,6 +299,10 @@
     get { fatalError() }
     set { fatalError() }
   }
+  subscript(bass: Bass) -> Bass {
+    get { return bass }
+    set { }
+  }
 }
 
 // CHECK-LABEL: sil hidden @{{.*}}10subscripts
@@ -321,4 +332,7 @@
   _ = \Subscripts<String>.[subGeneric: y]
 
   _ = \Subscripts<T>.[s, s].count
+
+  _ = \Subscripts<T>.[Bass()]
+  _ = \Subscripts<T>.[Treble()]
 }
diff --git a/test/expr/unary/keypath/keypath.swift b/test/expr/unary/keypath/keypath.swift
index f45b9b4..d95c2a6 100644
--- a/test/expr/unary/keypath/keypath.swift
+++ b/test/expr/unary/keypath/keypath.swift
@@ -409,6 +409,23 @@
   _ = \X.Type.b // expected-error{{cannot refer to static member}}
 }
 
+class Bass: Hashable {
+  static func ==(_: Bass, _: Bass) -> Bool { return false }
+  var hashValue: Int { return 0 }
+}
+
+class Treble: Bass { }
+
+struct BassSubscript {
+  subscript(_: Bass) -> Int { fatalError() }
+  subscript(_: @autoclosure () -> String) -> Int { fatalError() }
+}
+
+func testImplicitConversionInSubscriptIndex() {
+  _ = \BassSubscript.[Treble()]
+  _ = \BassSubscript.["hello"] // expected-error{{must be Hashable}}
+}
+
 func testSyntaxErrors() { // expected-note{{}}
   _ = \.  ; // expected-error{{expected member name following '.'}}
   _ = \.a ;