Skip to content

Commit 805f25d

Browse files
committed
[Sema] Try limit kicking interface type in filterForEnumElement
Kicking the interface type request of the base decl here is wrong if the decl is e.g a `self` capture in a closure, since we'll be in the middle of type-checking the closure. I'm planning on properly fixing this by folding the lookup into the constraint system, but for now let's at least avoid kicking the request if we don't have an enum case or enum var. That at least prevents it from affecting cases where e.g you're pattern matching against a property in a class. We could potentially tighten up the checking here even further, but that could potentially impact source compatibility for ambiguous cases. I'd like to keep this patch low risk, and then deal with any fallout as part of the pattern type-checking work. rdar://146952007
1 parent 961cfb8 commit 805f25d

File tree

3 files changed

+81
-5
lines changed

3 files changed

+81
-5
lines changed

lib/Sema/TypeCheckPattern.cpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,25 +90,39 @@ filterForEnumElement(DeclContext *DC, SourceLoc UseLoc,
9090
ValueDecl *e = result.getValueDecl();
9191
assert(e);
9292

93-
// Skip if the enum element was referenced as an instance member
93+
// We only care about enum members, and must either have an EnumElementDecl,
94+
// or a VarDecl which could be wrapping an underlying enum element.
95+
// FIXME: We check this up-front to avoid kicking InterfaceTypeRequest
96+
// below to help workaround https://github.com/swiftlang/swift/issues/80657
97+
// for non-enum cases. The proper fix is to move this filtering logic
98+
// into the constraint system.
99+
if (!e->getDeclContext()->getSelfEnumDecl())
100+
continue;
101+
102+
auto *EED = dyn_cast<EnumElementDecl>(e);
103+
auto *VD = dyn_cast<VarDecl>(e);
104+
if (!EED && !VD)
105+
continue;
106+
107+
// Skip if referenced as an instance member
94108
if (unqualifiedLookup) {
95109
if (!result.getBaseDecl() ||
96110
!result.getBaseDecl()->getInterfaceType()->is<MetatypeType>()) {
97111
continue;
98112
}
99113
}
100114

101-
if (auto *oe = dyn_cast<EnumElementDecl>(e)) {
115+
if (EED) {
102116
// Note that there could be multiple elements with the same
103117
// name, such results in a re-declaration error, so let's
104118
// just always pick the last element, just like in `foundConstant`
105119
// case.
106-
foundElement = oe;
120+
foundElement = EED;
107121
continue;
108122
}
109123

110-
if (auto *var = dyn_cast<VarDecl>(e)) {
111-
foundConstant = var;
124+
if (VD) {
125+
foundConstant = VD;
112126
continue;
113127
}
114128
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: not --crash %target-swift-frontend -emit-sil %s
2+
3+
// https://github.com/swiftlang/swift/issues/80657
4+
enum E {
5+
case e
6+
7+
static func foo() {
8+
_ = { [self] in
9+
switch e {
10+
case e:
11+
break
12+
default:
13+
break
14+
}
15+
}
16+
}
17+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: %target-swift-frontend -emit-sil %s
2+
3+
// These cases are similar to https://github.com/swiftlang/swift/issues/80657,
4+
// but we can avoid hitting the same issue for non-enum members.
5+
6+
struct S {
7+
let y = 0
8+
func foo(_ x: Int) {
9+
let _ = { [self] in
10+
switch x {
11+
case y: break
12+
default: break
13+
}
14+
}
15+
}
16+
}
17+
18+
class C {
19+
let y = 0
20+
func foo(_ x: Int) {
21+
let _ = { [self] in
22+
switch x {
23+
case y: break
24+
default: break
25+
}
26+
}
27+
}
28+
}
29+
30+
enum E {
31+
case e
32+
33+
func bar() -> Int {0}
34+
35+
func foo() {
36+
_ = { [self] in
37+
switch 0 {
38+
case bar():
39+
break
40+
default:
41+
break
42+
}
43+
}
44+
}
45+
}

0 commit comments

Comments
 (0)