Skip to content

Commit 32e0c80

Browse files
committed
[TypeChecker] Add more tests for keypath dynamic member lookup
Test inheritance, precedence, existentials, IUO, function type returns and more.
1 parent 0235ff1 commit 32e0c80

File tree

3 files changed

+142
-4
lines changed

3 files changed

+142
-4
lines changed

lib/Sema/CSApply.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1257,7 +1257,9 @@ namespace {
12571257
if (selected->choice.isDecl()) {
12581258
auto locatorKind = ConstraintLocator::SubscriptMember;
12591259
if (selected->choice.getKind() ==
1260-
OverloadChoiceKind::DynamicMemberLookup)
1260+
OverloadChoiceKind::DynamicMemberLookup ||
1261+
selected->choice.getKind() ==
1262+
OverloadChoiceKind::KeyPathDynamicMemberLookup)
12611263
locatorKind = ConstraintLocator::Member;
12621264

12631265
newSubscript =

test/Constraints/keypath_dynamic_member_lookup.swift

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,44 @@ _ = lens.topLeft.y
5353

5454
lens.topLeft = Lens(Point(x: 1, y: 2)) // Ok
5555
lens.bottomRight.y = Lens(12) // Ok
56+
57+
@dynamicMemberLookup
58+
class A<T> {
59+
var value: T
60+
61+
init(_ v: T) {
62+
self.value = v
63+
}
64+
65+
subscript<U>(dynamicMember member: KeyPath<T, U>) -> U {
66+
get { return value[keyPath: member] }
67+
}
68+
}
69+
70+
// Let's make sure that keypath dynamic member lookup
71+
// works with inheritance
72+
73+
class B<T> : A<T> {}
74+
75+
func bar(_ b: B<Point>) {
76+
let _: Int = b.x
77+
let _ = b.y
78+
}
79+
80+
struct Point3D {
81+
var x, y, z: Int
82+
}
83+
84+
// Make sure that explicitly declared members take precedence
85+
class C<T> : A<T> {
86+
var x: Float = 42
87+
}
88+
89+
func baz(_ c: C<Point3D>) {
90+
// CHECK: ref_element_addr {{.*}} : $C<Point3D>, #C.x
91+
let _ = c.x
92+
// CHECK: [[Y:%.*]] = keypath $KeyPath<Point3D, Int>, (root $Point3D; stored_property #Point3D.z : $Int)
93+
// CHECK: [[KEYPATH:%.*]] = function_ref @$s29keypath_dynamic_member_lookup1AC0B6Memberqd__s7KeyPathCyxqd__G_tcluig
94+
// CHECK-NEXT: apply [[KEYPATH]]<Point3D, Int>({{.*}}, [[Y]], {{.*}})
95+
let _ = c.z
96+
}

test/attr/attr_dynamic_member_lookup.swift

Lines changed: 98 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -392,17 +392,19 @@ func testGenerics<S, T, P: GenericProtocol>(
392392
//===----------------------------------------------------------------------===//
393393

394394
@dynamicMemberLookup
395-
class C {
395+
class KP {
396396
subscript(dynamicMember member: String) -> Int { return 7 }
397397
}
398-
_ = \C.[dynamicMember: "hi"]
399-
_ = \C.testLookup
398+
_ = \KP.[dynamicMember: "hi"]
399+
_ = \KP.testLookup
400400

401401
/* KeyPath based dynamic lookup */
402402

403403
struct Point {
404404
var x: Int
405405
let y: Int
406+
407+
private let z: Int = 0 // expected-note 7 {{declared here}}
406408
}
407409

408410
struct Rectangle {
@@ -433,6 +435,99 @@ var bottomRight = Point(x: 10, y: 10)
433435
var lens = Lens(Rectangle(topLeft: topLeft,
434436
bottomRight: bottomRight))
435437

438+
_ = lens.topLeft
439+
_ = lens.topLeft.x
440+
_ = lens.topLeft.y
441+
_ = lens.topLeft.z // expected-error {{'z' is inaccessible due to 'private' protection level}}
442+
443+
_ = lens.bottomRight
444+
_ = lens.bottomRight.x
445+
_ = lens.bottomRight.y
446+
_ = lens.bottomRight.z // expected-error {{'z' is inaccessible due to 'private' protection level}}
447+
436448
lens.topLeft = Lens(Point(x: 1, y: 2)) // Ok
437449
lens.bottomRight.x = Lens(11) // Ok
438450
lens.bottomRight.y = Lens(12) // expected-error {{cannot assign through dynamic lookup property: 'lens' is immutable}}
451+
lens.bottomRight.z = Lens(13) // expected-error {{'z' is inaccessible due to 'private' protection level}}
452+
453+
func acceptKeyPathDynamicLookup(_: Lens<Int>) {}
454+
455+
acceptKeyPathDynamicLookup(lens.topLeft.x)
456+
acceptKeyPathDynamicLookup(lens.topLeft.y)
457+
acceptKeyPathDynamicLookup(lens.topLeft.z) // expected-error {{'z' is inaccessible due to 'private' protection level}}
458+
459+
@dynamicMemberLookup
460+
class A<T> {
461+
var value: T
462+
463+
init(_ v: T) {
464+
self.value = v
465+
}
466+
467+
subscript<U>(dynamicMember member: KeyPath<T, U>) -> U {
468+
get { return value[keyPath: member] }
469+
}
470+
}
471+
472+
// Let's make sure that keypath dynamic member lookup
473+
// works with inheritance
474+
475+
class B<T> : A<T> {}
476+
477+
func bar(_ b: B<Point>) {
478+
let _: Int = b.x
479+
let _ = b.y
480+
let _: Float = b.y // expected-error {{cannot convert value of type 'Int' to specified type 'Float'}}
481+
let _ = b.z // expected-error {{'z' is inaccessible due to 'private' protection level}}
482+
}
483+
484+
// Existentials and IUOs
485+
486+
@dynamicMemberLookup
487+
protocol KeyPathLookup {
488+
associatedtype T
489+
490+
var value: T { get }
491+
492+
subscript(dynamicMember member: KeyPath<T, Int>) -> Int! { get }
493+
}
494+
495+
extension KeyPathLookup {
496+
subscript(dynamicMember member: KeyPath<T, Int>) -> Int! {
497+
get { return value[keyPath: member] }
498+
}
499+
}
500+
501+
class C<T> : KeyPathLookup {
502+
var value: T
503+
init(_ v: T) {
504+
self.value = v
505+
}
506+
}
507+
508+
func baz(_ c: C<Point>) {
509+
let _: Int = c.x
510+
let _ = c.y
511+
let _: Float = c.y // expected-error {{cannot convert value of type 'Int?' to specified type 'Float'}}
512+
let _ = c.z // expected-error {{'z' is inaccessible due to 'private' protection level}}
513+
}
514+
515+
@dynamicMemberLookup
516+
class D<T> {
517+
var value: T
518+
519+
init(_ v: T) {
520+
self.value = v
521+
}
522+
523+
subscript<U: Numeric>(dynamicMember member: KeyPath<T, U>) -> (U) -> U {
524+
get { return { offset in self.value[keyPath: member] + offset } }
525+
}
526+
}
527+
528+
func faz(_ d: D<Point>) {
529+
let _: Int = d.x(42)
530+
let _ = d.y(1 + 0)
531+
let _: Float = d.y(1 + 0) // expected-error {{cannot convert value of type 'Int' to specified type 'Float'}}
532+
let _ = d.z(1 + 0) // expected-error {{'z' is inaccessible due to 'private' protection level}}
533+
}

0 commit comments

Comments
 (0)