@@ -1035,40 +1035,6 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
1035
1035
std::swap (*prevCaseDecls, *nextCaseDecls);
1036
1036
}
1037
1037
1038
- void checkUnknownAttrRestrictions (CaseStmt *caseBlock,
1039
- bool &limitExhaustivityChecks) {
1040
- if (caseBlock->getCaseLabelItems ().size () != 1 ) {
1041
- assert (!caseBlock->getCaseLabelItems ().empty () &&
1042
- " parser should not produce case blocks with no items" );
1043
- getASTContext ().Diags .diagnose (caseBlock->getLoc (),
1044
- diag::unknown_case_multiple_patterns)
1045
- .highlight (caseBlock->getCaseLabelItems ()[1 ].getSourceRange ());
1046
- limitExhaustivityChecks = true ;
1047
- }
1048
-
1049
- if (FallthroughDest != nullptr ) {
1050
- if (!caseBlock->isDefault ())
1051
- getASTContext ().Diags .diagnose (caseBlock->getLoc (),
1052
- diag::unknown_case_must_be_last);
1053
- limitExhaustivityChecks = true ;
1054
- }
1055
-
1056
- const auto &labelItem = caseBlock->getCaseLabelItems ().front ();
1057
- if (labelItem.getGuardExpr () && !labelItem.isDefault ()) {
1058
- getASTContext ().Diags .diagnose (labelItem.getStartLoc (),
1059
- diag::unknown_case_where_clause)
1060
- .highlight (labelItem.getGuardExpr ()->getSourceRange ());
1061
- }
1062
-
1063
- const Pattern *pattern =
1064
- labelItem.getPattern ()->getSemanticsProvidingPattern ();
1065
- if (!isa<AnyPattern>(pattern)) {
1066
- getASTContext ().Diags .diagnose (labelItem.getStartLoc (),
1067
- diag::unknown_case_must_be_catchall)
1068
- .highlight (pattern->getSourceRange ());
1069
- }
1070
- }
1071
-
1072
1038
void checkFallthroughPatternBindingsAndTypes (CaseStmt *caseBlock,
1073
1039
CaseStmt *previousBlock) {
1074
1040
auto firstPattern = caseBlock->getCaseLabelItems ()[0 ].getPattern ();
@@ -1236,7 +1202,9 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
1236
1202
1237
1203
// Check restrictions on '@unknown'.
1238
1204
if (caseBlock->hasUnknownAttr ()) {
1239
- checkUnknownAttrRestrictions (caseBlock, limitExhaustivityChecks);
1205
+ checkUnknownAttrRestrictions (
1206
+ getASTContext (), caseBlock, FallthroughDest,
1207
+ limitExhaustivityChecks);
1240
1208
}
1241
1209
1242
1210
// If the previous case fellthrough, similarly check that that case's
@@ -2067,23 +2035,81 @@ void TypeChecker::typeCheckTopLevelCodeDecl(TopLevelCodeDecl *TLCD) {
2067
2035
performTopLevelDeclDiagnostics (TLCD);
2068
2036
}
2069
2037
2038
+ void swift::checkUnknownAttrRestrictions (
2039
+ ASTContext &ctx, CaseStmt *caseBlock, CaseStmt *fallthroughDest,
2040
+ bool &limitExhaustivityChecks) {
2041
+ if (caseBlock->getCaseLabelItems ().size () != 1 ) {
2042
+ assert (!caseBlock->getCaseLabelItems ().empty () &&
2043
+ " parser should not produce case blocks with no items" );
2044
+ ctx.Diags .diagnose (caseBlock->getLoc (),
2045
+ diag::unknown_case_multiple_patterns)
2046
+ .highlight (caseBlock->getCaseLabelItems ()[1 ].getSourceRange ());
2047
+ limitExhaustivityChecks = true ;
2048
+ }
2049
+
2050
+ if (fallthroughDest != nullptr ) {
2051
+ if (!caseBlock->isDefault ())
2052
+ ctx.Diags .diagnose (caseBlock->getLoc (),
2053
+ diag::unknown_case_must_be_last);
2054
+ limitExhaustivityChecks = true ;
2055
+ }
2056
+
2057
+ const auto &labelItem = caseBlock->getCaseLabelItems ().front ();
2058
+ if (labelItem.getGuardExpr () && !labelItem.isDefault ()) {
2059
+ ctx.Diags .diagnose (labelItem.getStartLoc (),
2060
+ diag::unknown_case_where_clause)
2061
+ .highlight (labelItem.getGuardExpr ()->getSourceRange ());
2062
+ }
2063
+
2064
+ const Pattern *pattern =
2065
+ labelItem.getPattern ()->getSemanticsProvidingPattern ();
2066
+ if (!isa<AnyPattern>(pattern)) {
2067
+ ctx.Diags .diagnose (labelItem.getStartLoc (),
2068
+ diag::unknown_case_must_be_catchall)
2069
+ .highlight (pattern->getSourceRange ());
2070
+ }
2071
+ }
2072
+
2070
2073
void swift::bindSwitchCasePatternVars (CaseStmt *caseStmt) {
2071
- llvm::SmallDenseMap<Identifier, VarDecl *, 4 > latestVars;
2074
+ llvm::SmallDenseMap<Identifier, std::pair< VarDecl *, bool > , 4 > latestVars;
2072
2075
auto recordVar = [&](VarDecl *var) {
2073
2076
if (!var->hasName ())
2074
2077
return ;
2075
2078
2076
2079
// If there is an existing variable with this name, set it as the
2077
2080
// parent of this new variable.
2078
2081
auto &entry = latestVars[var->getName ()];
2079
- if (entry) {
2082
+ if (entry. first ) {
2080
2083
assert (!var->getParentVarDecl () ||
2081
- var->getParentVarDecl () == entry);
2082
- var->setParentVarDecl (entry);
2084
+ var->getParentVarDecl () == entry.first );
2085
+ var->setParentVarDecl (entry.first );
2086
+
2087
+ // Check for a mutability mismatch.
2088
+ if (entry.second != var->isLet ()) {
2089
+ // Find the original declaration.
2090
+ auto initialCaseVarDecl = entry.first ;
2091
+ while (auto parentVar = initialCaseVarDecl->getParentVarDecl ())
2092
+ initialCaseVarDecl = parentVar;
2093
+
2094
+ auto diag = var->diagnose (diag::mutability_mismatch_multiple_pattern_list,
2095
+ var->isLet (), initialCaseVarDecl->isLet ());
2096
+
2097
+ VarPattern *foundVP = nullptr ;
2098
+ var->getParentPattern ()->forEachNode ([&](Pattern *P) {
2099
+ if (auto *VP = dyn_cast<VarPattern>(P))
2100
+ if (VP->getSingleVar () == var)
2101
+ foundVP = VP;
2102
+ });
2103
+ if (foundVP)
2104
+ diag.fixItReplace (foundVP->getLoc (),
2105
+ initialCaseVarDecl->isLet () ? " let" : " var" );
2106
+ }
2107
+ } else {
2108
+ entry.second = var->isLet ();
2083
2109
}
2084
2110
2085
2111
// Record this variable as the latest with this name.
2086
- entry = var;
2112
+ entry. first = var;
2087
2113
};
2088
2114
2089
2115
// Wire up the parent var decls for each variable that occurs within
0 commit comments