Skip to content

Commit 5caa51c

Browse files
authored
Merge pull request #12301 from jckarter/keypath-subscript-coerce-index
Sema: Coerce the type of the index expression in a key path component to match the subscript decl's index type.
2 parents 7ea0c32 + d3a2a0f commit 5caa51c

File tree

3 files changed

+42
-2
lines changed

3 files changed

+42
-2
lines changed

lib/Sema/CSApply.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4071,9 +4071,14 @@ namespace {
40714071

40724072
auto dc = subscript->getInnermostDeclContext();
40734073
SmallVector<Substitution, 4> subs;
4074+
SubstitutionMap subMap;
4075+
auto indexType = subscript->getIndicesInterfaceType();
4076+
40744077
if (auto sig = dc->getGenericSignatureOfContext()) {
40754078
// Compute substitutions to refer to the member.
40764079
solution.computeSubstitutions(sig, locator, subs);
4080+
subMap = sig->getSubstitutionMap(subs);
4081+
indexType = indexType.subst(subMap);
40774082
}
40784083

40794084
auto resolvedTy = foundDecl->openedType->castTo<AnyFunctionType>()
@@ -4082,9 +4087,13 @@ namespace {
40824087

40834088
auto ref = ConcreteDeclRef(cs.getASTContext(), subscript, subs);
40844089

4090+
// Coerce the indices to the type the subscript expects.
4091+
auto indexExpr = coerceToType(origComponent.getIndexExpr(),
4092+
indexType,
4093+
locator);
4094+
40854095
component = KeyPathExpr::Component
4086-
::forSubscriptWithPrebuiltIndexExpr(ref,
4087-
origComponent.getIndexExpr(),
4096+
::forSubscriptWithPrebuiltIndexExpr(ref, indexExpr,
40884097
origComponent.getSubscriptLabels(),
40894098
resolvedTy,
40904099
origComponent.getLoc(),

test/SILGen/keypaths.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,13 @@ func iuoKeyPaths() {
267267
_ = \IUOProperty.iuo!.x
268268
}
269269

270+
class Bass: Hashable {
271+
static func ==(_: Bass, _: Bass) -> Bool { return false }
272+
var hashValue: Int { return 0 }
273+
}
274+
275+
class Treble: Bass { }
276+
270277
struct Subscripts<T> {
271278
subscript() -> T {
272279
get { fatalError() }
@@ -292,6 +299,10 @@ struct Subscripts<T> {
292299
get { fatalError() }
293300
set { fatalError() }
294301
}
302+
subscript(bass: Bass) -> Bass {
303+
get { return bass }
304+
set { }
305+
}
295306
}
296307

297308
// CHECK-LABEL: sil hidden @{{.*}}10subscripts
@@ -321,4 +332,7 @@ func subscripts<T: Hashable, U: Hashable>(x: T, y: U, s: String) {
321332
_ = \Subscripts<String>.[subGeneric: y]
322333

323334
_ = \Subscripts<T>.[s, s].count
335+
336+
_ = \Subscripts<T>.[Bass()]
337+
_ = \Subscripts<T>.[Treble()]
324338
}

test/expr/unary/keypath/keypath.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,23 @@ func testStaticKeyPathComponent() {
417417
_ = \X.Type.b // expected-error{{cannot refer to static member}}
418418
}
419419

420+
class Bass: Hashable {
421+
static func ==(_: Bass, _: Bass) -> Bool { return false }
422+
var hashValue: Int { return 0 }
423+
}
424+
425+
class Treble: Bass { }
426+
427+
struct BassSubscript {
428+
subscript(_: Bass) -> Int { fatalError() }
429+
subscript(_: @autoclosure () -> String) -> Int { fatalError() }
430+
}
431+
432+
func testImplicitConversionInSubscriptIndex() {
433+
_ = \BassSubscript.[Treble()]
434+
_ = \BassSubscript.["hello"] // expected-error{{must be Hashable}}
435+
}
436+
420437
func testSyntaxErrors() { // expected-note{{}}
421438
_ = \. ; // expected-error{{expected member name following '.'}}
422439
_ = \.a ;

0 commit comments

Comments
 (0)