Skip to content

Commit 75e90ca

Browse files
authored
Merge pull request #14798 from xedin/rdar-35870863
[TypeChecker] Fix crash related to chained optionals in case statements
2 parents 3770869 + ea0427e commit 75e90ca

File tree

2 files changed

+45
-6
lines changed

2 files changed

+45
-6
lines changed

lib/Sema/TypeCheckPattern.cpp

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -382,22 +382,49 @@ class ResolvePattern : public ASTVisitor<ResolvePattern,
382382
}
383383

384384
Pattern *convertBindingsToOptionalSome(Expr *E) {
385-
auto *Bind = dyn_cast<BindOptionalExpr>(E->getSemanticsProvidingExpr());
386-
if (!Bind) return getSubExprPattern(E);
385+
auto *expr = E->getSemanticsProvidingExpr();
386+
auto *bindExpr = dyn_cast<BindOptionalExpr>(expr);
387+
if (!bindExpr) {
388+
// Let's see if this expression prefixed with any number of '?'
389+
// has any other disjoint 'BindOptionalExpr' inside of it, if so,
390+
// we need to wrap such sub-expression into `OptionalEvaluationExpr`.
391+
bool hasDisjointChaining = false;
392+
expr->forEachChildExpr([&](Expr *subExpr) -> Expr * {
393+
// If there is `OptionalEvaluationExpr` in the AST
394+
// it means that all of possible `BindOptionalExpr`
395+
// which follow are covered by it.
396+
if (isa<OptionalEvaluationExpr>(subExpr))
397+
return nullptr;
398+
399+
if (isa<BindOptionalExpr>(subExpr)) {
400+
hasDisjointChaining = true;
401+
return nullptr;
402+
}
403+
404+
return subExpr;
405+
});
406+
407+
if (hasDisjointChaining)
408+
E = new (TC.Context) OptionalEvaluationExpr(E);
409+
410+
return getSubExprPattern(E);
411+
}
387412

388-
auto sub = convertBindingsToOptionalSome(Bind->getSubExpr());
389-
return new (TC.Context) OptionalSomePattern(sub, Bind->getQuestionLoc());
413+
auto *subExpr = convertBindingsToOptionalSome(bindExpr->getSubExpr());
414+
return new (TC.Context) OptionalSomePattern(subExpr,
415+
bindExpr->getQuestionLoc());
390416
}
391417

392418
// Convert a x? to OptionalSome pattern. In the AST form, this will look like
393419
// an OptionalEvaluationExpr with an immediate BindOptionalExpr inside of it.
394420
Pattern *visitOptionalEvaluationExpr(OptionalEvaluationExpr *E) {
421+
auto *subExpr = E->getSubExpr();
395422
// We only handle the case where one or more bind expressions are subexprs
396423
// of the optional evaluation. Other cases are not simple postfix ?'s.
397-
if (!isa<BindOptionalExpr>(E->getSubExpr()->getSemanticsProvidingExpr()))
424+
if (!isa<BindOptionalExpr>(subExpr->getSemanticsProvidingExpr()))
398425
return nullptr;
399426

400-
return convertBindingsToOptionalSome(E->getSubExpr());
427+
return convertBindingsToOptionalSome(subExpr);
401428
}
402429

403430

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %target-swift-frontend %s -typecheck
2+
3+
struct S {
4+
let foo = "bar"
5+
}
6+
let s: S? = S()
7+
let str: String? = "hello world"
8+
9+
switch str {
10+
case s?.foo?: ()
11+
default: ()
12+
}

0 commit comments

Comments
 (0)