[TypeChecker] Add more tests for keypath dynamic member lookup

Test inheritance, precedence, existentials, IUO, function type
returns and more.
This commit is contained in:
Pavel Yaskevich
2019-03-21 15:33:46 -07:00
parent 0235ff1e98
commit 32e0c807c6
3 changed files with 142 additions and 4 deletions

View File

@@ -1257,7 +1257,9 @@ namespace {
if (selected->choice.isDecl()) {
auto locatorKind = ConstraintLocator::SubscriptMember;
if (selected->choice.getKind() ==
OverloadChoiceKind::DynamicMemberLookup)
OverloadChoiceKind::DynamicMemberLookup ||
selected->choice.getKind() ==
OverloadChoiceKind::KeyPathDynamicMemberLookup)
locatorKind = ConstraintLocator::Member;
newSubscript =

View File

@@ -53,3 +53,44 @@ _ = lens.topLeft.y
lens.topLeft = Lens(Point(x: 1, y: 2)) // Ok
lens.bottomRight.y = Lens(12) // Ok
@dynamicMemberLookup
class A<T> {
var value: T
init(_ v: T) {
self.value = v
}
subscript<U>(dynamicMember member: KeyPath<T, U>) -> U {
get { return value[keyPath: member] }
}
}
// Let's make sure that keypath dynamic member lookup
// works with inheritance
class B<T> : A<T> {}
func bar(_ b: B<Point>) {
let _: Int = b.x
let _ = b.y
}
struct Point3D {
var x, y, z: Int
}
// Make sure that explicitly declared members take precedence
class C<T> : A<T> {
var x: Float = 42
}
func baz(_ c: C<Point3D>) {
// CHECK: ref_element_addr {{.*}} : $C<Point3D>, #C.x
let _ = c.x
// CHECK: [[Y:%.*]] = keypath $KeyPath<Point3D, Int>, (root $Point3D; stored_property #Point3D.z : $Int)
// CHECK: [[KEYPATH:%.*]] = function_ref @$s29keypath_dynamic_member_lookup1AC0B6Memberqd__s7KeyPathCyxqd__G_tcluig
// CHECK-NEXT: apply [[KEYPATH]]<Point3D, Int>({{.*}}, [[Y]], {{.*}})
let _ = c.z
}

View File

@@ -392,17 +392,19 @@ func testGenerics<S, T, P: GenericProtocol>(
//===----------------------------------------------------------------------===//
@dynamicMemberLookup
class C {
class KP {
subscript(dynamicMember member: String) -> Int { return 7 }
}
_ = \C.[dynamicMember: "hi"]
_ = \C.testLookup
_ = \KP.[dynamicMember: "hi"]
_ = \KP.testLookup
/* KeyPath based dynamic lookup */
struct Point {
var x: Int
let y: Int
private let z: Int = 0 // expected-note 7 {{declared here}}
}
struct Rectangle {
@@ -433,6 +435,99 @@ var bottomRight = Point(x: 10, y: 10)
var lens = Lens(Rectangle(topLeft: topLeft,
bottomRight: bottomRight))
_ = lens.topLeft
_ = lens.topLeft.x
_ = lens.topLeft.y
_ = lens.topLeft.z // expected-error {{'z' is inaccessible due to 'private' protection level}}
_ = lens.bottomRight
_ = lens.bottomRight.x
_ = lens.bottomRight.y
_ = lens.bottomRight.z // expected-error {{'z' is inaccessible due to 'private' protection level}}
lens.topLeft = Lens(Point(x: 1, y: 2)) // Ok
lens.bottomRight.x = Lens(11) // Ok
lens.bottomRight.y = Lens(12) // expected-error {{cannot assign through dynamic lookup property: 'lens' is immutable}}
lens.bottomRight.z = Lens(13) // expected-error {{'z' is inaccessible due to 'private' protection level}}
func acceptKeyPathDynamicLookup(_: Lens<Int>) {}
acceptKeyPathDynamicLookup(lens.topLeft.x)
acceptKeyPathDynamicLookup(lens.topLeft.y)
acceptKeyPathDynamicLookup(lens.topLeft.z) // expected-error {{'z' is inaccessible due to 'private' protection level}}
@dynamicMemberLookup
class A<T> {
var value: T
init(_ v: T) {
self.value = v
}
subscript<U>(dynamicMember member: KeyPath<T, U>) -> U {
get { return value[keyPath: member] }
}
}
// Let's make sure that keypath dynamic member lookup
// works with inheritance
class B<T> : A<T> {}
func bar(_ b: B<Point>) {
let _: Int = b.x
let _ = b.y
let _: Float = b.y // expected-error {{cannot convert value of type 'Int' to specified type 'Float'}}
let _ = b.z // expected-error {{'z' is inaccessible due to 'private' protection level}}
}
// Existentials and IUOs
@dynamicMemberLookup
protocol KeyPathLookup {
associatedtype T
var value: T { get }
subscript(dynamicMember member: KeyPath<T, Int>) -> Int! { get }
}
extension KeyPathLookup {
subscript(dynamicMember member: KeyPath<T, Int>) -> Int! {
get { return value[keyPath: member] }
}
}
class C<T> : KeyPathLookup {
var value: T
init(_ v: T) {
self.value = v
}
}
func baz(_ c: C<Point>) {
let _: Int = c.x
let _ = c.y
let _: Float = c.y // expected-error {{cannot convert value of type 'Int?' to specified type 'Float'}}
let _ = c.z // expected-error {{'z' is inaccessible due to 'private' protection level}}
}
@dynamicMemberLookup
class D<T> {
var value: T
init(_ v: T) {
self.value = v
}
subscript<U: Numeric>(dynamicMember member: KeyPath<T, U>) -> (U) -> U {
get { return { offset in self.value[keyPath: member] + offset } }
}
}
func faz(_ d: D<Point>) {
let _: Int = d.x(42)
let _ = d.y(1 + 0)
let _: Float = d.y(1 + 0) // expected-error {{cannot convert value of type 'Int' to specified type 'Float'}}
let _ = d.z(1 + 0) // expected-error {{'z' is inaccessible due to 'private' protection level}}
}