| // RUN: %target-swift-frontend -emit-sil -verify %s | %FileCheck %s |
| |
| struct Point { |
| let x: Int |
| var y: Int |
| } |
| |
| struct Rectangle { |
| var topLeft, bottomRight: Point |
| } |
| |
| @dynamicMemberLookup |
| struct Lens<T> { |
| var obj: T |
| |
| init(_ obj: T) { |
| self.obj = obj |
| } |
| |
| subscript<U>(dynamicMember member: KeyPath<T, U>) -> Lens<U> { |
| get { return Lens<U>(obj[keyPath: member]) } |
| } |
| |
| subscript<U>(dynamicMember member: WritableKeyPath<T, U>) -> Lens<U> { |
| get { return Lens<U>(obj[keyPath: member]) } |
| set { obj[keyPath: member] = newValue.obj } |
| } |
| |
| // Used to make sure that keypath and string based lookup are |
| // property disambiguated. |
| subscript(dynamicMember member: String) -> Lens<Int> { |
| return Lens<Int>(42) |
| } |
| } |
| |
| var topLeft = Point(x: 0, y: 0) |
| var bottomRight = Point(x: 10, y: 10) |
| |
| var lens = Lens(Rectangle(topLeft: topLeft, |
| bottomRight: bottomRight)) |
| |
| // CHECK: function_ref @$s29keypath_dynamic_member_lookup4LensV0B6MemberACyqd__Gs15WritableKeyPathCyxqd__G_tcluig |
| // CHECK-NEXT: apply %45<Rectangle, Point>({{.*}}) |
| // CHECK: function_ref @$s29keypath_dynamic_member_lookup4LensV0B6MemberACyqd__Gs7KeyPathCyxqd__G_tcluig |
| // CHECK-NEXT: apply %54<Point, Int>({{.*}}) |
| _ = lens.topLeft.x |
| |
| // CHECK: function_ref @$s29keypath_dynamic_member_lookup4LensV0B6MemberACyqd__Gs15WritableKeyPathCyxqd__G_tcluig |
| // CHECK-NEXT: apply %69<Rectangle, Point>({{.*}}) |
| // CHECK: function_ref @$s29keypath_dynamic_member_lookup4LensV0B6MemberACyqd__Gs15WritableKeyPathCyxqd__G_tcluig |
| // CHECK-NEXT: apply %76<Point, Int>({{.*}}) |
| _ = 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 |
| } |
| |
| @dynamicMemberLookup |
| struct SubscriptLens<T> { |
| var value: T |
| |
| subscript(foo: String) -> Int { |
| get { return 42 } |
| } |
| |
| subscript<U>(dynamicMember member: KeyPath<T, U>) -> U { |
| get { return value[keyPath: member] } |
| } |
| |
| subscript<U>(dynamicMember member: WritableKeyPath<T, U>) -> U { |
| get { return value[keyPath: member] } |
| set { value[keyPath: member] = newValue } |
| } |
| } |
| |
| func keypath_with_subscripts(_ arr: SubscriptLens<[Int]>, |
| _ dict: inout SubscriptLens<[String: Int]>) { |
| // CHECK: keypath $WritableKeyPath<Array<Int>, ArraySlice<Int>>, (root $Array<Int>; settable_property $ArraySlice<Int>, id @$sSays10ArraySliceVyxGSnySiGcig : {{.*}}) |
| _ = arr[0..<3] |
| // CHECK: keypath $KeyPath<Array<Int>, Int>, (root $Array<Int>; gettable_property $Int, id @$sSa5countSivg : {{.*}}) |
| for idx in 0..<arr.count { |
| // CHECK: keypath $WritableKeyPath<Array<Int>, Int>, (root $Array<Int>; settable_property $Int, id @$sSayxSicig : {{.*}}) |
| let _ = arr[idx] |
| // CHECK: keypath $WritableKeyPath<Array<Int>, Int>, (root $Array<Int>; settable_property $Int, id @$sSayxSicig : {{.*}}) |
| print(arr[idx]) |
| } |
| |
| // CHECK: function_ref @$s29keypath_dynamic_member_lookup13SubscriptLensVySiSScig |
| _ = arr["hello"] |
| // CHECK: function_ref @$s29keypath_dynamic_member_lookup13SubscriptLensVySiSScig |
| _ = dict["hello"] |
| |
| if let index = dict.value.firstIndex(where: { $0.value == 42 }) { |
| // CHECK: keypath $KeyPath<Dictionary<String, Int>, (key: String, value: Int)>, (root $Dictionary<String, Int>; gettable_property $(key: String, value: Int), id @$sSDyx3key_q_5valuetSD5IndexVyxq__Gcig : {{.*}}) |
| let _ = dict[index] |
| } |
| // CHECK: keypath $WritableKeyPath<Dictionary<String, Int>, Optional<Int>>, (root $Dictionary<String, Int>; settable_property $Optional<Int>, id @$sSDyq_Sgxcig : {{.*}}) |
| dict["ultimate question"] = 42 |
| } |
| |
| struct DotStruct { |
| var x, y: Int |
| } |
| |
| class DotClass { |
| var x, y: Int |
| |
| init(x: Int, y: Int) { |
| self.x = x |
| self.y = y |
| } |
| } |
| |
| @dynamicMemberLookup |
| struct DotLens<T> { |
| var value: T |
| |
| subscript<U>(dynamicMember member: WritableKeyPath<T, U>) -> U { |
| get { return value[keyPath: member] } |
| set { value[keyPath: member] = newValue } |
| } |
| |
| subscript<U>(dynamicMember member: ReferenceWritableKeyPath<T, U>) -> U { |
| get { return value[keyPath: member] } |
| set { value[keyPath: member] = newValue } |
| } |
| } |
| |
| func dot_struct_test(_ lens: inout DotLens<DotStruct>) { |
| // CHECK: keypath $WritableKeyPath<DotStruct, Int>, (root $DotStruct; stored_property #DotStruct.x : $Int) |
| lens.x = 1 |
| // CHECK: keypath $WritableKeyPath<DotStruct, Int>, (root $DotStruct; stored_property #DotStruct.y : $Int) |
| let _ = lens.y |
| } |
| |
| func dot_class_test(_ lens: inout DotLens<DotClass>) { |
| // CHECK: keypath $ReferenceWritableKeyPath<DotClass, Int>, (root $DotClass; settable_property $Int, id #DotClass.x!getter.1 : (DotClass) -> () -> Int, getter @$s29keypath_dynamic_member_lookup8DotClassC1xSivpACTK : {{.*}}) |
| lens.x = 1 |
| // CHECK: keypath $ReferenceWritableKeyPath<DotClass, Int>, (root $DotClass; settable_property $Int, id #DotClass.y!getter.1 : (DotClass) -> () -> Int, getter @$s29keypath_dynamic_member_lookup8DotClassC1ySivpACTK : {{.*}}) |
| let _ = lens.y |
| } |
| |
| @dynamicMemberLookup |
| struct OverloadedLens<T> { |
| var value: T |
| |
| subscript<U>(keyPath: KeyPath<T, U>) -> U { |
| get { return value[keyPath: keyPath] } |
| } |
| |
| subscript<U>(dynamicMember keyPath: KeyPath<T, U>) -> U { |
| get { return value[keyPath: keyPath] } |
| } |
| } |
| |
| // Make sure if there is a subscript which accepts key path, |
| // existing dynamic member overloads wouldn't interfere. |
| func test_direct_subscript_ref(_ lens: OverloadedLens<Point>) { |
| // CHECK: function_ref @$s29keypath_dynamic_member_lookup14OverloadedLensVyqd__s7KeyPathCyxqd__Gcluig |
| _ = lens[\.x] |
| // CHECK: function_ref @$s29keypath_dynamic_member_lookup14OverloadedLensVyqd__s7KeyPathCyxqd__Gcluig |
| _ = lens[\.y] |
| |
| // CHECK: function_ref @$s29keypath_dynamic_member_lookup14OverloadedLensV0B6Memberqd__s7KeyPathCyxqd__G_tcluig |
| _ = lens.x |
| // CHECK: function_ref @$s29keypath_dynamic_member_lookup14OverloadedLensV0B6Memberqd__s7KeyPathCyxqd__G_tcluig |
| _ = lens.y |
| } |
| |
| func test_keypath_dynamic_lookup_inside_keypath() { |
| // CHECK: keypath $KeyPath<Point, Int>, (root $Point; stored_property #Point.x : $Int) |
| // CHECK-NEXT: keypath $KeyPath<Lens<Point>, Lens<Int>>, (root $Lens<Point>; gettable_property $Lens<Int>, id @$s29keypath_dynamic_member_lookup4LensV0B6MemberACyqd__Gs7KeyPathCyxqd__G_tcluig : {{.*}}) |
| _ = \Lens<Point>.x |
| // CHECK: keypath $WritableKeyPath<Rectangle, Point>, (root $Rectangle; stored_property #Rectangle.topLeft : $Point) |
| // CHECK-NEXT: keypath $WritableKeyPath<Point, Int>, (root $Point; stored_property #Point.y : $Int) |
| // CHECK-NEXT: keypath $WritableKeyPath<Lens<Rectangle>, Lens<Int>>, (root $Lens<Rectangle>; settable_property $Lens<Point>, id @$s29keypath_dynamic_member_lookup4LensV0B6MemberACyqd__Gs15WritableKeyPathCyxqd__G_tcluig : {{.*}}) |
| _ = \Lens<Rectangle>.topLeft.y |
| // CHECK: keypath $KeyPath<Array<Int>, Int>, (root $Array<Int>; gettable_property $Int, id @$sSa5countSivg : {{.*}}) |
| // CHECK-NEXT: keypath $KeyPath<Lens<Array<Int>>, Lens<Int>>, (root $Lens<Array<Int>>; gettable_property $Lens<Int>, id @$s29keypath_dynamic_member_lookup4LensV0B6MemberACyqd__Gs7KeyPathCyxqd__G_tcluig : {{.*}}) |
| _ = \Lens<[Int]>.count |
| // CHECK: keypath $WritableKeyPath<Array<Int>, Int>, (root $Array<Int>; settable_property $Int, id @$sSayxSicig : {{.*}}) |
| // CHECK-NEXT: keypath $WritableKeyPath<Lens<Array<Int>>, Lens<Int>>, (root $Lens<Array<Int>>; settable_property $Lens<Int>, id @$s29keypath_dynamic_member_lookup4LensV0B6MemberACyqd__Gs15WritableKeyPathCyxqd__G_tcluig : {{.*}}) |
| _ = \Lens<[Int]>.[0] |
| // CHECK: keypath $WritableKeyPath<Array<Array<Int>>, Array<Int>>, (root $Array<Array<Int>>; settable_property $Array<Int>, id @$sSayxSicig : {{.*}}) |
| // CHECK-NEXT: keypath $KeyPath<Array<Int>, Int>, (root $Array<Int>; gettable_property $Int, id @$sSa5countSivg : {{.*}}) |
| // CHECK-NEXT: keypath $KeyPath<Lens<Array<Array<Int>>>, Lens<Int>>, (root $Lens<Array<Array<Int>>>; settable_property $Lens<Array<Int>>, id @$s29keypath_dynamic_member_lookup4LensV0B6MemberACyqd__Gs15WritableKeyPathCyxqd__G_tcluig : {{.*}}) |
| _ = \Lens<[[Int]]>.[0].count |
| } |
| |
| func test_recursive_dynamic_lookup(_ lens: Lens<Lens<Point>>) { |
| // CHECK: keypath $KeyPath<Point, Int>, (root $Point; stored_property #Point.x : $Int) |
| // CHECK-NEXT: keypath $KeyPath<Lens<Point>, Lens<Int>>, (root $Lens<Point>; gettable_property $Lens<Int>, id @$s29keypath_dynamic_member_lookup4LensV0B6MemberACyqd__Gs7KeyPathCyxqd__G_tcluig : {{.*}}) |
| // CHECK: function_ref @$s29keypath_dynamic_member_lookup4LensV0B6MemberACyqd__Gs7KeyPathCyxqd__G_tcluig |
| _ = lens.x |
| // CHECK: keypath $KeyPath<Point, Int>, (root $Point; stored_property #Point.x : $Int) |
| // CHECK: function_ref @$s29keypath_dynamic_member_lookup4LensV0B6MemberACyqd__Gs7KeyPathCyxqd__G_tcluig |
| _ = lens.obj.x |
| // CHECK: [[FIRST_OBJ:%.*]] = struct_extract {{.*}} : $Lens<Lens<Point>>, #Lens.obj |
| // CHECK-NEXT: [[SECOND_OBJ:%.*]] = struct_extract [[FIRST_OBJ]] : $Lens<Point>, #Lens.obj |
| // CHECK-NEXT: struct_extract [[SECOND_OBJ]] : $Point, #Point.y |
| _ = lens.obj.obj.y |
| // CHECK: keypath $KeyPath<Point, Int>, (root $Point; stored_property #Point.x : $Int) |
| // CHECK-NEXT: keypath $KeyPath<Lens<Point>, Lens<Int>>, (root $Lens<Point>; gettable_property $Lens<Int>, id @$s29keypath_dynamic_member_lookup4LensV0B6MemberACyqd__Gs7KeyPathCyxqd__G_tcluig : {{.*}}) |
| // CHECK-NEXT: keypath $KeyPath<Lens<Lens<Point>>, Lens<Lens<Int>>>, (root $Lens<Lens<Point>>; gettable_property $Lens<Lens<Int>>, id @$s29keypath_dynamic_member_lookup4LensV0B6MemberACyqd__Gs7KeyPathCyxqd__G_tcluig : {{.*}}) |
| _ = \Lens<Lens<Point>>.x |
| // CHECK: keypath $WritableKeyPath<Rectangle, Point>, (root $Rectangle; stored_property #Rectangle.topLeft : $Point) |
| // CHECK-NEXT: keypath $WritableKeyPath<Lens<Rectangle>, Lens<Point>>, (root $Lens<Rectangle>; settable_property $Lens<Point>, id @$s29keypath_dynamic_member_lookup4LensV0B6MemberACyqd__Gs15WritableKeyPathCyxqd__G_tcluig : {{.*}}) |
| // CHECK-NEXT: keypath $KeyPath<Point, Int>, (root $Point; stored_property #Point.x : $Int) |
| // CHECK-NEXT: keypath $KeyPath<Lens<Point>, Lens<Int>>, (root $Lens<Point>; gettable_property $Lens<Int>, id @$s29keypath_dynamic_member_lookup4LensV0B6MemberACyqd__Gs7KeyPathCyxqd__G_tcluig : {{.*}}) |
| // CHECK-NEXT: keypath $KeyPath<Lens<Lens<Rectangle>>, Lens<Lens<Int>>>, (root $Lens<Lens<Rectangle>>; settable_property $Lens<Lens<Point>>, id @$s29keypath_dynamic_member_lookup4LensV0B6MemberACyqd__Gs15WritableKeyPathCyxqd__G_tcluig : {{.*}}) |
| _ = \Lens<Lens<Rectangle>>.topLeft.x |
| } |