Skip to content

Commit 3de36cb

Browse files
authored
[ConstraintSystem] Disallow use of enum case as a key path component (#31972)
1 parent 1a5d3bf commit 3de36cb

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
@@ -1526,6 +1526,25 @@ class InvalidStaticMemberRefInKeyPath final : public InvalidMemberRefInKeyPath {
15261526
bool diagnoseAsError() override;
15271527
};
15281528

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

lib/Sema/CSFix.cpp

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

761+
case RefKind::EnumCase: {
762+
InvalidEnumCaseRefInKeyPath failure(solution, Member, getLocator());
763+
return failure.diagnose(asNote);
764+
}
765+
761766
case RefKind::MutatingGetter: {
762767
InvalidMemberWithMutatingGetterInKeyPath failure(solution, Member,
763768
getLocator());
@@ -782,6 +787,12 @@ AllowInvalidRefInKeyPath::forRef(ConstraintSystem &cs, ValueDecl *member,
782787
return AllowInvalidRefInKeyPath::create(cs, RefKind::Method, member,
783788
locator);
784789

790+
// Referencing enum cases in key path is not currently allowed.
791+
if (isa<EnumElementDecl>(member)) {
792+
return AllowInvalidRefInKeyPath::create(cs, RefKind::EnumCase, member,
793+
locator);
794+
}
795+
785796
// Referencing initializers in key path is not currently allowed.
786797
if (isa<ConstructorDecl>(member))
787798
return AllowInvalidRefInKeyPath::create(cs, RefKind::Initializer,

lib/Sema/CSFix.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,6 +1328,8 @@ class AllowInvalidRefInKeyPath final : public ConstraintFix {
13281328
// Allow a reference to a initializer instance as a key path
13291329
// component.
13301330
Initializer,
1331+
// Allow a reference to an enum case as a key path component.
1332+
EnumCase,
13311333
} Kind;
13321334

13331335
ValueDecl *Member;
@@ -1349,6 +1351,8 @@ class AllowInvalidRefInKeyPath final : public ConstraintFix {
13491351
return "allow reference to a method as a key path component";
13501352
case RefKind::Initializer:
13511353
return "allow reference to an init method as a key path component";
1354+
case RefKind::EnumCase:
1355+
return "allow reference to an enum case as a key path component";
13521356
}
13531357
llvm_unreachable("covered switch");
13541358
}
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)