Skip to content

Commit bc4d016

Browse files
committed
[TypeChecker] Fix dynamic member declaration validation to check labels
1 parent 8f88054 commit bc4d016

File tree

4 files changed

+39
-8
lines changed

4 files changed

+39
-8
lines changed

lib/Sema/TypeCheckAttr.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -975,13 +975,17 @@ visitDynamicCallableAttr(DynamicCallableAttr *attr) {
975975
}
976976
}
977977

978-
static bool hasSingleNonVariadicParam(SubscriptDecl *decl) {
978+
static bool hasSingleNonVariadicParam(SubscriptDecl *decl,
979+
Identifier expectedLabel) {
979980
auto *indices = decl->getIndices();
980981
if (decl->isInvalid() || indices->size() != 1)
981982
return false;
982983

983984
auto *index = indices->get(0);
984-
return !index->isVariadic() && index->hasValidSignature();
985+
if (index->isVariadic() || !index->hasValidSignature())
986+
return false;
987+
988+
return index->getArgumentName() == expectedLabel;
985989
}
986990

987991
/// Returns true if the given subscript method is an valid implementation of
@@ -1004,7 +1008,7 @@ bool swift::isValidStringDynamicMemberLookup(SubscriptDecl *decl,
10041008
// There are two requirements:
10051009
// - The subscript method has exactly one, non-variadic parameter.
10061010
// - The parameter type conforms to `ExpressibleByStringLiteral`.
1007-
if (!hasSingleNonVariadicParam(decl))
1011+
if (!hasSingleNonVariadicParam(decl, TC.Context.Id_dynamicMember))
10081012
return false;
10091013

10101014
const auto *param = decl->getIndices()->get(0);
@@ -1020,7 +1024,7 @@ bool swift::isValidStringDynamicMemberLookup(SubscriptDecl *decl,
10201024

10211025
bool swift::isValidKeyPathDynamicMemberLookup(SubscriptDecl *decl,
10221026
TypeChecker &TC) {
1023-
if (!hasSingleNonVariadicParam(decl))
1027+
if (!hasSingleNonVariadicParam(decl, TC.Context.Id_dynamicMember))
10241028
return false;
10251029

10261030
const auto *param = decl->getIndices()->get(0);

test/Constraints/keypath_dynamic_member_lookup.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,3 +179,30 @@ func dot_class_test(_ lens: inout DotLens<DotClass>) {
179179
// CHECK: keypath $ReferenceWritableKeyPath<DotClass, Int>, (root $DotClass; settable_property $Int, id #DotClass.y!getter.1 : (DotClass) -> () -> Int, getter @$s29keypath_dynamic_member_lookup8DotClassC1ySivpACTK : {{.*}})
180180
let _ = lens.y
181181
}
182+
183+
@dynamicMemberLookup
184+
struct OverloadedLens<T> {
185+
var value: T
186+
187+
subscript<U>(keyPath: KeyPath<T, U>) -> U {
188+
get { return value[keyPath: keyPath] }
189+
}
190+
191+
subscript<U>(dynamicMember keyPath: KeyPath<T, U>) -> U {
192+
get { return value[keyPath: keyPath] }
193+
}
194+
}
195+
196+
// Make sure if there is a subscript which accepts key path,
197+
// existing dynamic member overloads wouldn't interfere.
198+
func test_direct_subscript_ref(_ lens: OverloadedLens<Point>) {
199+
// CHECK: function_ref @$s29keypath_dynamic_member_lookup14OverloadedLensVyqd__s7KeyPathCyxqd__Gcluig
200+
_ = lens[\.x]
201+
// CHECK: function_ref @$s29keypath_dynamic_member_lookup14OverloadedLensVyqd__s7KeyPathCyxqd__Gcluig
202+
_ = lens[\.y]
203+
204+
// CHECK: function_ref @$s29keypath_dynamic_member_lookup14OverloadedLensV0B6Memberqd__s7KeyPathCyxqd__G_tcluig
205+
_ = lens.x
206+
// CHECK: function_ref @$s29keypath_dynamic_member_lookup14OverloadedLensV0B6Memberqd__s7KeyPathCyxqd__G_tcluig
207+
_ = lens.y
208+
}

test/attr/attr_dynamic_member_lookup.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ func keypath_with_subscripts(_ arr: SubscriptLens<[Int]>,
576576
_ = arr["hello"] // Ok
577577
_ = dict["hello"] // Ok
578578

579-
_ = arr["hello"] = 42 // expected-error {{cannot assign through subscript: 'arr' is a 'let' constant}}
579+
_ = arr["hello"] = 42 // expected-error {{cannot assign through subscript: subscript is get-only}}
580580
_ = dict["hello"] = 0 // Ok
581581

582582
_ = arr[0] = 42 // expected-error {{cannot assign through subscript: 'arr' is a 'let' constant}}

test/expr/unary/keypath/keypath.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -350,9 +350,9 @@ func testKeyPathSubscript(readonly: ZwithSubscript, writable: inout ZwithSubscri
350350
sink = writable[keyPath: wkp]
351351
sink = readonly[keyPath: rkp]
352352
sink = writable[keyPath: rkp]
353-
readonly[keyPath: kp] = sink // expected-error {{cannot assign through subscript: 'kp' is a read-only key path}}
354-
writable[keyPath: kp] = sink // expected-error {{cannot assign through subscript: 'kp' is a read-only key path}}
355-
readonly[keyPath: wkp] = sink // expected-error {{cannot assign through subscript: 'readonly' is a 'let' constant}}
353+
readonly[keyPath: kp] = sink // expected-error {{cannot assign through subscript: subscript is get-only}}
354+
writable[keyPath: kp] = sink // expected-error {{cannot assign through subscript: subscript is get-only}}
355+
readonly[keyPath: wkp] = sink // expected-error {{cannot assign through subscript: subscript is get-only}}
356356
// FIXME: silently falls back to keypath application, which seems inconsistent
357357
writable[keyPath: wkp] = sink
358358
// FIXME: silently falls back to keypath application, which seems inconsistent

0 commit comments

Comments
 (0)