Skip to content

Commit f026c61

Browse files
authored
[ConstraintSystem] Disallow use of enum case as a key path component (swiftlang#31969)
1 parent 2ac1eee commit f026c61

File tree

6 files changed

+57
-0
lines changed

6 files changed

+57
-0
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,9 @@ ERROR(expr_keypath_mutating_getter,none,
557557
ERROR(expr_keypath_static_member,none,
558558
"%select{key path|dynamic key path member lookup}1 cannot refer to static member %0",
559559
(DeclName, bool))
560+
ERROR(expr_keypath_enum_case,none,
561+
"%select{key path|dynamic key path member lookup}1 cannot refer to enum case %0",
562+
(DeclName, bool))
560563
ERROR(expr_keypath_empty,none,
561564
"empty key path does not refer to a property", ())
562565
ERROR(expr_unsupported_objc_key_path_component,none,

lib/Sema/CSDiagnostics.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4859,6 +4859,12 @@ bool InvalidStaticMemberRefInKeyPath::diagnoseAsError() {
48594859
return true;
48604860
}
48614861

4862+
bool InvalidEnumCaseRefInKeyPath::diagnoseAsError() {
4863+
emitDiagnostic(diag::expr_keypath_enum_case, getName(),
4864+
isForKeyPathDynamicMemberLookup());
4865+
return true;
4866+
}
4867+
48624868
bool InvalidMemberWithMutatingGetterInKeyPath::diagnoseAsError() {
48634869
emitDiagnostic(diag::expr_keypath_mutating_getter, getName(),
48644870
isForKeyPathDynamicMemberLookup());

lib/Sema/CSDiagnostics.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1524,6 +1524,25 @@ class InvalidStaticMemberRefInKeyPath final : public InvalidMemberRefInKeyPath {
15241524
bool diagnoseAsError() override;
15251525
};
15261526

1527+
/// Diagnose an attempt to reference an enum case as a key path component
1528+
/// e.g.
1529+
///
1530+
/// ```swift
1531+
/// enum E {
1532+
/// case foo
1533+
/// }
1534+
///
1535+
/// _ = \E.Type.foo
1536+
/// ```
1537+
class InvalidEnumCaseRefInKeyPath final : public InvalidMemberRefInKeyPath {
1538+
public:
1539+
InvalidEnumCaseRefInKeyPath(const Solution &solution, ValueDecl *member,
1540+
ConstraintLocator *locator)
1541+
: InvalidMemberRefInKeyPath(solution, member, locator) {}
1542+
1543+
bool diagnoseAsError() override;
1544+
};
1545+
15271546
/// Diagnose an attempt to reference a member which has a mutating getter as a
15281547
/// key path component e.g.
15291548
///

lib/Sema/CSFix.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,11 @@ bool AllowInvalidRefInKeyPath::diagnose(const Solution &solution,
767767
return failure.diagnose(asNote);
768768
}
769769

770+
case RefKind::EnumCase: {
771+
InvalidEnumCaseRefInKeyPath failure(solution, Member, getLocator());
772+
return failure.diagnose(asNote);
773+
}
774+
770775
case RefKind::MutatingGetter: {
771776
InvalidMemberWithMutatingGetterInKeyPath failure(solution, Member,
772777
getLocator());
@@ -791,6 +796,12 @@ AllowInvalidRefInKeyPath::forRef(ConstraintSystem &cs, ValueDecl *member,
791796
return AllowInvalidRefInKeyPath::create(cs, RefKind::Method, member,
792797
locator);
793798

799+
// Referencing enum cases in key path is not currently allowed.
800+
if (isa<EnumElementDecl>(member)) {
801+
return AllowInvalidRefInKeyPath::create(cs, RefKind::EnumCase, member,
802+
locator);
803+
}
804+
794805
// Referencing initializers in key path is not currently allowed.
795806
if (isa<ConstructorDecl>(member))
796807
return AllowInvalidRefInKeyPath::create(cs, RefKind::Initializer,

lib/Sema/CSFix.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1330,6 +1330,8 @@ class AllowInvalidRefInKeyPath final : public ConstraintFix {
13301330
// Allow a reference to a initializer instance as a key path
13311331
// component.
13321332
Initializer,
1333+
// Allow a reference to an enum case as a key path component.
1334+
EnumCase,
13331335
} Kind;
13341336

13351337
ValueDecl *Member;
@@ -1351,6 +1353,8 @@ class AllowInvalidRefInKeyPath final : public ConstraintFix {
13511353
return "allow reference to a method as a key path component";
13521354
case RefKind::Initializer:
13531355
return "allow reference to an init method as a key path component";
1356+
case RefKind::EnumCase:
1357+
return "allow reference to an enum case as a key path component";
13541358
}
13551359
llvm_unreachable("covered switch");
13561360
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %target-swift-frontend -typecheck %s -verify
2+
3+
enum E {
4+
case bar
5+
}
6+
7+
@dynamicMemberLookup
8+
struct S {
9+
subscript(dynamicMember key: KeyPath<E.Type, E>) -> Bool { true }
10+
}
11+
12+
13+
let s = S()
14+
let e = s.bar // expected-error {{dynamic key path member lookup cannot refer to enum case 'bar'}}

0 commit comments

Comments
 (0)