Skip to content

Commit 3710967

Browse files
committed
[TypeChecker] Prevent pattern resolution from triggering type-checking for unresolved references
Workaround for Clang enum typaliases called `isInvalid()` and `getInterfaceType()` on discovered declarations. That doesn't play well with result builders because declarations/patterns used in the body of a result builder don't get a type until a solution is applied. Calling `isInvalid()` or `getInterfaceType` on declarations located in the body of a result builder trigger a separate type-check for the declaration that interferes with builder transformation and leads to crashes.
1 parent 55b0373 commit 3710967

File tree

2 files changed

+34
-2
lines changed

2 files changed

+34
-2
lines changed

lib/Sema/TypeCheckPattern.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,21 @@ filterForEnumElement(DeclContext *DC, SourceLoc UseLoc,
8484
for (const LookupResultEntry &result : foundElements) {
8585
ValueDecl *e = result.getValueDecl();
8686
assert(e);
87-
if (e->isInvalid()) {
87+
88+
// Check `isInvalid` only if the declaration has been
89+
// verified, otherwise this would cause a problem if
90+
// this declaration is found in the body of a result
91+
// builder because it wouldn't have a type set until
92+
// whole body is type-checked, and `isInvalid` would
93+
// trigger a separate type-check that interfers with
94+
// result builder transformation and causes crashes.
95+
//
96+
// Note: This check cannot simply be removed because
97+
// enums with re-declarationed members would trigger
98+
// an ambiguity assertion below.
99+
if (e->hasInterfaceType() && e->isInvalid())
88100
continue;
89-
}
101+
90102
// Skip if the enum element was referenced as an instance member
91103
if (unqualifiedLookup) {
92104
if (!result.getBaseDecl() ||

test/Constraints/result_builder.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,26 @@ func testSwitch(_ e: E) {
582582
}
583583
}
584584

585+
func testExistingPatternsInCaseStatements() {
586+
tuplify(true) { c in
587+
switch false {
588+
case (c): 1 // Ok
589+
default: 0
590+
}
591+
}
592+
593+
var arr: [Int] = []
594+
595+
tuplify(true) { c in
596+
let n = arr.endIndex
597+
598+
switch arr.startIndex {
599+
case (n): 1 // Ok
600+
default: 0
601+
}
602+
}
603+
}
604+
585605
// CHECK: testSwitch
586606
// CHECK-SAME: first(main.Either<Swift.String, (Swift.Int, Swift.String)>.first("a"))
587607
testSwitch(getE(0))

0 commit comments

Comments
 (0)