@@ -975,23 +975,59 @@ visitDynamicCallableAttr(DynamicCallableAttr *attr) {
975
975
}
976
976
}
977
977
978
+ static bool hasSingleNonVariadicParam (SubscriptDecl *decl) {
979
+ auto *indices = decl->getIndices ();
980
+ return indices->size () == 1 && !indices->get (0 )->isVariadic ();
981
+ }
982
+
978
983
// / Returns true if the given subscript method is an valid implementation of
979
984
// / the `subscript(dynamicMember:)` requirement for @dynamicMemberLookup.
980
985
// / The method is given to be defined as `subscript(dynamicMember:)`.
981
986
bool swift::isValidDynamicMemberLookupSubscript (SubscriptDecl *decl,
982
987
DeclContext *DC,
983
988
TypeChecker &TC) {
989
+ // It could be
990
+ // - `subscript(dynamicMember: {Writable}KeyPath<...>)`; or
991
+ // - `subscript(dynamicMember: String*)`
992
+ return isValidKeyPathDynamicMemberLookup (decl, TC) ||
993
+ isValidStringDynamicMemberLookup (decl, DC, TC);
994
+
995
+ }
996
+
997
+ bool swift::isValidStringDynamicMemberLookup (SubscriptDecl *decl,
998
+ DeclContext *DC,
999
+ TypeChecker &TC) {
984
1000
// There are two requirements:
985
1001
// - The subscript method has exactly one, non-variadic parameter.
986
1002
// - The parameter type conforms to `ExpressibleByStringLiteral`.
987
- auto indices = decl->getIndices ();
1003
+ if (!hasSingleNonVariadicParam (decl))
1004
+ return false ;
1005
+
1006
+ const auto *param = decl->getIndices ()->get (0 );
1007
+ auto paramType = param->getType ();
988
1008
989
1009
auto stringLitProto =
990
1010
TC.Context .getProtocol (KnownProtocolKind::ExpressibleByStringLiteral);
991
-
992
- return indices->size () == 1 && !indices->get (0 )->isVariadic () &&
993
- TC.conformsToProtocol (indices->get (0 )->getType (),
994
- stringLitProto, DC, ConformanceCheckOptions ());
1011
+
1012
+ // If this is `subscript(dynamicMember: String*)`
1013
+ return bool (TC.conformsToProtocol (paramType, stringLitProto, DC,
1014
+ ConformanceCheckOptions ()));
1015
+ }
1016
+
1017
+ bool swift::isValidKeyPathDynamicMemberLookup (SubscriptDecl *decl,
1018
+ TypeChecker &TC) {
1019
+ if (!hasSingleNonVariadicParam (decl))
1020
+ return false ;
1021
+
1022
+ const auto *param = decl->getIndices ()->get (0 );
1023
+ if (param->isVariadic ())
1024
+ return false ;
1025
+
1026
+ if (auto NTD = param->getType ()->getAnyNominal ()) {
1027
+ return NTD == TC.Context .getKeyPathDecl () ||
1028
+ NTD == TC.Context .getWritableKeyPathDecl ();
1029
+ }
1030
+ return false ;
995
1031
}
996
1032
997
1033
// / The @dynamicMemberLookup attribute is only allowed on types that have at
0 commit comments