Skip to content

Commit 181ca35

Browse files
committed
[gardening] Extract out type checking of case label items into its own helper method.
The method StmtChecker::visitSwitchStmt is really large and does a bunch of different things. This implicit submethod was one of the largest of these. By extracting this, we make the original method easier to reason about. Extracting done with Xcode's refactoring engine.
1 parent e038f7e commit 181ca35

File tree

1 file changed

+73
-67
lines changed

1 file changed

+73
-67
lines changed

lib/Sema/TypeCheckStmt.cpp

Lines changed: 73 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,75 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
947947
return S;
948948
}
949949

950+
void checkCaseLabelItem(CaseStmt *caseBlock, CaseLabelItem &labelItem,
951+
bool &limitExhaustivityChecks, Type subjectType) {
952+
SWIFT_DEFER {
953+
// Check the guard expression, if present.
954+
if (auto *guard = labelItem.getGuardExpr()) {
955+
limitExhaustivityChecks |= TC.typeCheckCondition(guard, DC);
956+
labelItem.setGuardExpr(guard);
957+
}
958+
};
959+
960+
Pattern *pattern = labelItem.getPattern();
961+
auto *newPattern = TC.resolvePattern(pattern, DC,
962+
/*isStmtCondition*/ false);
963+
if (!newPattern)
964+
return;
965+
pattern = newPattern;
966+
// Coerce the pattern to the subject's type.
967+
TypeResolutionOptions patternOptions(TypeResolverContext::InExpression);
968+
if (!subjectType ||
969+
TC.coercePatternToType(pattern, TypeResolution::forContextual(DC),
970+
subjectType, patternOptions)) {
971+
limitExhaustivityChecks = true;
972+
973+
// If that failed, mark any variables binding pieces of the pattern
974+
// as invalid to silence follow-on errors.
975+
pattern->forEachVariable([&](VarDecl *VD) { VD->markInvalid(); });
976+
}
977+
labelItem.setPattern(pattern);
978+
979+
// For each variable in the pattern, make sure its type is identical to what
980+
// it was in the first label item's pattern.
981+
auto *firstPattern = caseBlock->getCaseLabelItems()[0].getPattern();
982+
SmallVector<VarDecl *, 4> vars;
983+
firstPattern->collectVariables(vars);
984+
pattern->forEachVariable([&](VarDecl *vd) {
985+
if (!vd->hasName())
986+
return;
987+
for (auto *expected : vars) {
988+
if (expected->hasName() && expected->getName() == vd->getName()) {
989+
if (vd->hasType() && expected->hasType() && !expected->isInvalid() &&
990+
!vd->getType()->isEqual(expected->getType())) {
991+
TC.diagnose(vd->getLoc(), diag::type_mismatch_multiple_pattern_list,
992+
vd->getType(), expected->getType());
993+
vd->markInvalid();
994+
expected->markInvalid();
995+
}
996+
if (expected->isLet() != vd->isLet()) {
997+
auto diag = TC.diagnose(
998+
vd->getLoc(), diag::mutability_mismatch_multiple_pattern_list,
999+
vd->isLet(), expected->isLet());
1000+
1001+
VarPattern *foundVP = nullptr;
1002+
vd->getParentPattern()->forEachNode([&](Pattern *P) {
1003+
if (auto *VP = dyn_cast<VarPattern>(P))
1004+
if (VP->getSingleVar() == vd)
1005+
foundVP = VP;
1006+
});
1007+
if (foundVP)
1008+
diag.fixItReplace(foundVP->getLoc(),
1009+
expected->isLet() ? "let" : "var");
1010+
vd->markInvalid();
1011+
expected->markInvalid();
1012+
}
1013+
return;
1014+
}
1015+
}
1016+
});
1017+
}
1018+
9501019
Stmt *visitSwitchStmt(SwitchStmt *switchStmt) {
9511020
// Type-check the subject expression.
9521021
Expr *subjectExpr = switchStmt->getSubjectExpr();
@@ -979,73 +1048,10 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
9791048
FallthroughDest = std::next(i) == e ? nullptr : *std::next(i);
9801049

9811050
for (auto &labelItem : caseBlock->getMutableCaseLabelItems()) {
982-
// Resolve the pattern in the label.
983-
Pattern *pattern = labelItem.getPattern();
984-
if (auto *newPattern = TC.resolvePattern(pattern, DC,
985-
/*isStmtCondition*/false)) {
986-
pattern = newPattern;
987-
// Coerce the pattern to the subject's type.
988-
TypeResolutionOptions patternOptions(TypeResolverContext::InExpression);
989-
if (!subjectType ||
990-
TC.coercePatternToType(pattern, TypeResolution::forContextual(DC),
991-
subjectType, patternOptions)) {
992-
limitExhaustivityChecks = true;
993-
994-
// If that failed, mark any variables binding pieces of the pattern
995-
// as invalid to silence follow-on errors.
996-
pattern->forEachVariable([&](VarDecl *VD) {
997-
VD->markInvalid();
998-
});
999-
}
1000-
labelItem.setPattern(pattern);
1001-
1002-
// For each variable in the pattern, make sure its type is identical to what it
1003-
// was in the first label item's pattern.
1004-
auto *firstPattern = caseBlock->getCaseLabelItems()[0].getPattern();
1005-
SmallVector<VarDecl *, 4> vars;
1006-
firstPattern->collectVariables(vars);
1007-
pattern->forEachVariable([&](VarDecl *vd) {
1008-
if (!vd->hasName())
1009-
return;
1010-
for (auto *expected : vars) {
1011-
if (expected->hasName() && expected->getName() == vd->getName()) {
1012-
if (vd->hasType() && expected->hasType() &&
1013-
!expected->isInvalid() &&
1014-
!vd->getType()->isEqual(expected->getType())) {
1015-
TC.diagnose(vd->getLoc(),
1016-
diag::type_mismatch_multiple_pattern_list,
1017-
vd->getType(), expected->getType());
1018-
vd->markInvalid();
1019-
expected->markInvalid();
1020-
}
1021-
if (expected->isLet() != vd->isLet()) {
1022-
auto diag = TC.diagnose(
1023-
vd->getLoc(),
1024-
diag::mutability_mismatch_multiple_pattern_list,
1025-
vd->isLet(), expected->isLet());
1026-
1027-
VarPattern *foundVP = nullptr;
1028-
vd->getParentPattern()->forEachNode([&](Pattern *P) {
1029-
if (auto *VP = dyn_cast<VarPattern>(P))
1030-
if (VP->getSingleVar() == vd)
1031-
foundVP = VP;
1032-
});
1033-
if (foundVP)
1034-
diag.fixItReplace(foundVP->getLoc(),
1035-
expected->isLet() ? "let" : "var");
1036-
vd->markInvalid();
1037-
expected->markInvalid();
1038-
}
1039-
return;
1040-
}
1041-
}
1042-
});
1043-
}
1044-
// Check the guard expression, if present.
1045-
if (auto *guard = labelItem.getGuardExpr()) {
1046-
limitExhaustivityChecks |= TC.typeCheckCondition(guard, DC);
1047-
labelItem.setGuardExpr(guard);
1048-
}
1051+
// Resolve the pattern in our case label if it has not been resolved
1052+
// and check that our var decls follow invariants.
1053+
checkCaseLabelItem(caseBlock, labelItem, limitExhaustivityChecks,
1054+
subjectType);
10491055
}
10501056

10511057
// Check restrictions on '@unknown'.

0 commit comments

Comments
 (0)