Skip to content

Commit 0ddf238

Browse files
committed
Don't stop typechecking stmts on failure.
Generally speaking, it's necessary to typecheck all parts of a statement regardless of whether earlier parts failed to typecheck. For example, even if the condition of an if-statement fails to typecheck, we should still check its branches. This way all expressions in the AST are processed (i.e. SequenceExprs translated to trees) and we get more diagnostics. The big thing left to fix is for-each statement checking. If there are any type errors in the pattern or sequence of a for-each statement, the body doesn't get type-checked. <rdar://problem/23684220>
1 parent 8e738c3 commit 0ddf238

File tree

5 files changed

+69
-74
lines changed

5 files changed

+69
-74
lines changed

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2006,10 +2006,7 @@ bool TypeChecker::typeCheckStmtCondition(StmtCondition &cond, DeclContext *dc,
20062006
// If the pattern didn't get a type, it's because we ran into some
20072007
// unknown types along the way. We'll need to check the initializer.
20082008
auto init = elt.getInitializer();
2009-
if (typeCheckBinding(pattern, init, dc)) {
2010-
hadError = true;
2011-
continue;
2012-
}
2009+
hadError |= typeCheckBinding(pattern, init, dc);
20132010
elt.setPattern(pattern);
20142011
elt.setInitializer(init);
20152012
hadAnyFalsable |= pattern->isRefutablePattern();

lib/Sema/TypeCheckStmt.cpp

Lines changed: 59 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -396,10 +396,10 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
396396
RS->isImplicit());
397397
}
398398

399-
auto failed = TC.typeCheckExpression(E, DC, ResultTy, CTP_ReturnStmt);
399+
auto hadTypeError = TC.typeCheckExpression(E, DC, ResultTy, CTP_ReturnStmt);
400400
RS->setResult(E);
401401

402-
if (failed) {
402+
if (hadTypeError) {
403403
tryDiagnoseUnnecessaryCastOverOptionSet(TC.Context, E, ResultTy,
404404
DC->getParentModule());
405405
return nullptr;
@@ -415,57 +415,55 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
415415
Type exnType = TC.getExceptionType(DC, TS->getThrowLoc());
416416
if (!exnType) return TS;
417417

418-
auto failed = TC.typeCheckExpression(E, DC, exnType, CTP_ThrowStmt);
418+
auto hadTypeError = TC.typeCheckExpression(E, DC, exnType, CTP_ThrowStmt);
419419
TS->setSubExpr(E);
420-
421-
if (failed) return nullptr;
422420

423-
return TS;
421+
return hadTypeError ? nullptr : TS;
424422
}
425423

426424
Stmt *visitDeferStmt(DeferStmt *DS) {
427425
TC.typeCheckDecl(DS->getTempDecl(), /*isFirstPass*/false);
428426

429427
Expr *theCall = DS->getCallExpr();
430-
if (!TC.typeCheckExpression(theCall, DC))
431-
return nullptr;
428+
auto hadTypeError = TC.typeCheckExpression(theCall, DC);
432429
DS->setCallExpr(theCall);
433430

434-
return DS;
431+
return hadTypeError ? nullptr : DS;
435432
}
436433

437434
Stmt *visitIfStmt(IfStmt *IS) {
438-
StmtCondition C = IS->getCond();
435+
bool hadTypeError = false;
439436

440-
if (TC.typeCheckStmtCondition(C, DC, diag::if_always_true)) return 0;
437+
StmtCondition C = IS->getCond();
438+
hadTypeError |= TC.typeCheckStmtCondition(C, DC, diag::if_always_true);
441439
IS->setCond(C);
442440

443441
AddLabeledStmt ifNest(*this, IS);
444442

445443
Stmt *S = IS->getThenStmt();
446-
if (typeCheckStmt(S)) return 0;
444+
hadTypeError |= typeCheckStmt(S);
447445
IS->setThenStmt(S);
448446

449447
if ((S = IS->getElseStmt())) {
450-
if (typeCheckStmt(S)) return 0;
448+
hadTypeError |= typeCheckStmt(S);
451449
IS->setElseStmt(S);
452450
}
453451

454-
return IS;
452+
return hadTypeError ? nullptr : IS;
455453
}
456454

457455
Stmt *visitGuardStmt(GuardStmt *GS) {
456+
bool hadTypeError = false;
458457
StmtCondition C = GS->getCond();
459-
if (TC.typeCheckStmtCondition(C, DC, diag::guard_always_succeeds))
460-
return 0;
458+
hadTypeError |= TC.typeCheckStmtCondition(C, DC, diag::guard_always_succeeds);
461459
GS->setCond(C);
462460

463461
AddLabeledStmt ifNest(*this, GS);
464462

465463
Stmt *S = GS->getBody();
466-
if (typeCheckStmt(S)) return 0;
464+
hadTypeError |= typeCheckStmt(S);
467465
GS->setBody(S);
468-
return GS;
466+
return hadTypeError ? nullptr : GS;
469467
}
470468

471469
Stmt *visitIfConfigStmt(IfConfigStmt *ICS) {
@@ -479,69 +477,69 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
479477
Stmt *visitDoStmt(DoStmt *DS) {
480478
AddLabeledStmt loopNest(*this, DS);
481479
Stmt *S = DS->getBody();
482-
if (typeCheckStmt(S)) return 0;
480+
bool hadTypeError = typeCheckStmt(S);
483481
DS->setBody(S);
484-
return DS;
482+
return hadTypeError ? nullptr : DS;
485483
}
486484

487485
Stmt *visitWhileStmt(WhileStmt *WS) {
486+
bool hadTypeError = false;
488487
StmtCondition C = WS->getCond();
489-
if (TC.typeCheckStmtCondition(C, DC, diag::while_always_true)) return 0;
488+
hadTypeError |= TC.typeCheckStmtCondition(C, DC, diag::while_always_true);
490489
WS->setCond(C);
491490

492491
AddLabeledStmt loopNest(*this, WS);
493492
Stmt *S = WS->getBody();
494-
if (typeCheckStmt(S)) return 0;
493+
hadTypeError |= typeCheckStmt(S);
495494
WS->setBody(S);
496495

497-
return WS;
496+
return hadTypeError ? nullptr : WS;
498497
}
499498
Stmt *visitRepeatWhileStmt(RepeatWhileStmt *RWS) {
499+
bool hadTypeError = false;
500500
{
501501
AddLabeledStmt loopNest(*this, RWS);
502502
Stmt *S = RWS->getBody();
503-
if (typeCheckStmt(S)) return nullptr;
503+
hadTypeError |= typeCheckStmt(S);
504504
RWS->setBody(S);
505505
}
506506

507507
Expr *E = RWS->getCond();
508-
if (TC.typeCheckCondition(E, DC)) return nullptr;
508+
hadTypeError |= TC.typeCheckCondition(E, DC);
509509
RWS->setCond(E);
510-
return RWS;
510+
return hadTypeError ? nullptr : RWS;
511511
}
512512
Stmt *visitForStmt(ForStmt *FS) {
513+
bool hadTypeError = false;
513514
// Type check any var decls in the initializer.
514515
for (auto D : FS->getInitializerVarDecls())
515516
TC.typeCheckDecl(D, /*isFirstPass*/false);
516517

517518
if (auto *Initializer = FS->getInitializer().getPtrOrNull()) {
518-
if (TC.typeCheckExpression(Initializer, DC, Type(), CTP_Unused,
519-
TypeCheckExprFlags::IsDiscarded))
520-
return nullptr;
519+
hadTypeError |= TC.typeCheckExpression(Initializer, DC, Type(), CTP_Unused,
520+
TypeCheckExprFlags::IsDiscarded);
521521
FS->setInitializer(Initializer);
522522
TC.checkIgnoredExpr(Initializer);
523523
}
524524

525525
if (auto *Cond = FS->getCond().getPtrOrNull()) {
526-
if (TC.typeCheckCondition(Cond, DC))
527-
return nullptr;
526+
hadTypeError |= TC.typeCheckCondition(Cond, DC);
528527
FS->setCond(Cond);
529528
}
530529

531530
if (auto *Increment = FS->getIncrement().getPtrOrNull()) {
532-
if (TC.typeCheckExpression(Increment, DC, Type(), CTP_Unused,
533-
TypeCheckExprFlags::IsDiscarded))
534-
return nullptr;
531+
hadTypeError |= TC.typeCheckExpression(Increment, DC, Type(), CTP_Unused,
532+
TypeCheckExprFlags::IsDiscarded);
535533
FS->setIncrement(Increment);
536534
TC.checkIgnoredExpr(Increment);
537535
}
538536

539537
AddLabeledStmt loopNest(*this, FS);
540538
Stmt *S = FS->getBody();
541-
if (typeCheckStmt(S)) return nullptr;
539+
hadTypeError |= typeCheckStmt(S);
542540
FS->setBody(S);
543541

544-
return FS;
542+
return hadTypeError ? nullptr : FS;
545543
}
546544

547545
Stmt *visitForEachStmt(ForEachStmt *S) {
@@ -808,16 +806,15 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
808806
}
809807

810808
Stmt *visitSwitchStmt(SwitchStmt *S) {
809+
bool hadTypeError = false;
811810
// Type-check the subject expression.
812811
Expr *subjectExpr = S->getSubjectExpr();
813-
bool hadTypeError = TC.typeCheckExpression(subjectExpr, DC);
812+
hadTypeError |= TC.typeCheckExpression(subjectExpr, DC);
814813
subjectExpr = TC.coerceToMaterializable(subjectExpr);
815-
816-
if (!subjectExpr)
817-
return nullptr;
818-
819-
S->setSubjectExpr(subjectExpr);
820-
Type subjectType = subjectExpr->getType();
814+
if (subjectExpr) {
815+
S->setSubjectExpr(subjectExpr);
816+
}
817+
Type subjectType = S->getSubjectExpr()->getType();
821818

822819
// Type-check the case blocks.
823820
AddSwitchNest switchNest(*this);
@@ -835,36 +832,32 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
835832
if (auto *newPattern = TC.resolvePattern(pattern, DC,
836833
/*isStmtCondition*/false)) {
837834
pattern = newPattern;
835+
// Coerce the pattern to the subject's type.
836+
if (TC.coercePatternToType(pattern, DC, subjectType,
837+
TR_InExpression)) {
838+
// If that failed, mark any variables binding pieces of the pattern
839+
// as invalid to silence follow-on errors.
840+
pattern->forEachVariable([&](VarDecl *VD) {
841+
VD->overwriteType(ErrorType::get(TC.Context));
842+
VD->setInvalid();
843+
});
844+
hadTypeError = true;
845+
}
846+
labelItem.setPattern(pattern);
838847
} else {
839848
hadTypeError = true;
840-
continue;
841849
}
842850

843-
// Coerce the pattern to the subject's type.
844-
if (TC.coercePatternToType(pattern, DC, subjectType, TR_InExpression)) {
845-
// If that failed, mark any variables binding pieces of the pattern
846-
// as invalid to silence follow-on errors.
847-
pattern->forEachVariable([&](VarDecl *VD) {
848-
VD->overwriteType(ErrorType::get(TC.Context));
849-
VD->setInvalid();
850-
});
851-
hadTypeError = true;
852-
}
853-
labelItem.setPattern(pattern);
854-
855851
// Check the guard expression, if present.
856852
if (auto *guard = labelItem.getGuardExpr()) {
857-
if (TC.typeCheckCondition(guard, DC))
858-
hadTypeError = true;
859-
else
860-
labelItem.setGuardExpr(guard);
853+
hadTypeError |= TC.typeCheckCondition(guard, DC);
854+
labelItem.setGuardExpr(guard);
861855
}
862856
}
863857

864858
// Type-check the body statements.
865859
Stmt *body = caseBlock->getBody();
866-
if (typeCheckStmt(body))
867-
hadTypeError = true;
860+
hadTypeError |= typeCheckStmt(body);
868861
caseBlock->setBody(body);
869862
}
870863

@@ -882,8 +875,9 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
882875
}
883876

884877
bool checkCatchStmt(CatchStmt *S) {
878+
bool hadTypeError = false;
885879
// Check the catch pattern.
886-
bool hadTypeError = TC.typeCheckCatchPattern(S, DC);
880+
hadTypeError |= TC.typeCheckCatchPattern(S, DC);
887881

888882
// Check the guard expression, if present.
889883
if (Expr *guard = S->getGuardExpr()) {
@@ -910,11 +904,8 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
910904
// Type-check the 'do' body. Type failures in here will generally
911905
// not cause type failures in the 'catch' clauses.
912906
Stmt *newBody = S->getBody();
913-
if (typeCheckStmt(newBody)) {
914-
hadTypeError = true;
915-
} else {
916-
S->setBody(newBody);
917-
}
907+
hadTypeError |= typeCheckStmt(newBody);
908+
S->setBody(newBody);
918909

919910
// Check all the catch clauses independently.
920911
for (auto clause : S->getCatches()) {

test/Parse/foreach.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func for_each(r: Range<Int>, iir: IntRange<Int>) {
3030
}
3131

3232
// Parse errors
33-
for i r { // expected-error 2{{expected ';' in 'for' statement}} expected-error {{use of unresolved identifier 'i'}}
33+
for i r { // expected-error 2{{expected ';' in 'for' statement}} expected-error {{use of unresolved identifier 'i'}} expected-error {{type 'Range<Int>' does not conform to protocol 'BooleanType'}}
3434
}
3535
for i in r sum = sum + i; // expected-error{{expected '{' to start the body of for-each loop}}
3636
for let x in 0..<10 {} // expected-error {{'let' pattern is already in an immutable context}} {{7-11=}}

test/Parse/recovery.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ func missingControllingExprInFor() {
185185
#if true // <rdar://problem/21679557> compiler crashes on "for{{"
186186
// expected-error @+2 {{missing initialization in a 'for' statement}}
187187
// expected-note @+1 2 {{to match this opening '{'}}
188-
for{{
188+
for{{ // expected-error {{expression resolves to an unused function}}
189189
#endif // expected-error 2 {{expected '}' at end of closure}}
190190

191191
#if true

test/stmt/statements.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,13 @@ func for_loop_multi_iter() {
438438
}
439439
}
440440

441+
// rdar://problem/23684220
442+
// Even if the condition fails to typecheck, save it in the AST anyway; the old
443+
// condition may have contained a SequenceExpr.
444+
func r23684220(b: Any) {
445+
if let _ = b ?? b {} // expected-error {{initializer for conditional binding must have Optional type, not 'Any' (aka 'protocol<>')}}
446+
}
447+
441448
// Errors in case syntax
442449
class
443450
case, // expected-error {{expected identifier in enum 'case' declaration}} expected-error {{expected pattern}}

0 commit comments

Comments
 (0)