@@ -947,6 +947,142 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
947
947
return S;
948
948
}
949
949
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
+
1019
+ void checkUnknownAttrRestrictions (CaseStmt *caseBlock,
1020
+ bool &limitExhaustivityChecks) {
1021
+ if (caseBlock->getCaseLabelItems ().size () != 1 ) {
1022
+ assert (!caseBlock->getCaseLabelItems ().empty () &&
1023
+ " parser should not produce case blocks with no items" );
1024
+ TC.diagnose (caseBlock->getLoc (), diag::unknown_case_multiple_patterns)
1025
+ .highlight (caseBlock->getCaseLabelItems ()[1 ].getSourceRange ());
1026
+ limitExhaustivityChecks = true ;
1027
+ }
1028
+
1029
+ if (FallthroughDest != nullptr ) {
1030
+ if (!caseBlock->isDefault ())
1031
+ TC.diagnose (caseBlock->getLoc (), diag::unknown_case_must_be_last);
1032
+ limitExhaustivityChecks = true ;
1033
+ }
1034
+
1035
+ const auto &labelItem = caseBlock->getCaseLabelItems ().front ();
1036
+ if (labelItem.getGuardExpr () && !labelItem.isDefault ()) {
1037
+ TC.diagnose (labelItem.getStartLoc (), diag::unknown_case_where_clause)
1038
+ .highlight (labelItem.getGuardExpr ()->getSourceRange ());
1039
+ }
1040
+
1041
+ const Pattern *pattern =
1042
+ labelItem.getPattern ()->getSemanticsProvidingPattern ();
1043
+ if (!isa<AnyPattern>(pattern)) {
1044
+ TC.diagnose (labelItem.getStartLoc (), diag::unknown_case_must_be_catchall)
1045
+ .highlight (pattern->getSourceRange ());
1046
+ }
1047
+ }
1048
+
1049
+ void checkFallthroughPatternBindingsAndTypes (CaseStmt *caseBlock,
1050
+ CaseStmt *previousBlock) {
1051
+ auto firstPattern = caseBlock->getCaseLabelItems ()[0 ].getPattern ();
1052
+ SmallVector<VarDecl *, 4 > vars;
1053
+ firstPattern->collectVariables (vars);
1054
+
1055
+ for (auto &labelItem : previousBlock->getCaseLabelItems ()) {
1056
+ const Pattern *pattern = labelItem.getPattern ();
1057
+ SmallVector<VarDecl *, 4 > PreviousVars;
1058
+ pattern->collectVariables (PreviousVars);
1059
+ for (auto expected : vars) {
1060
+ bool matched = false ;
1061
+ if (!expected->hasName ())
1062
+ continue ;
1063
+ for (auto previous : PreviousVars) {
1064
+ if (previous->hasName () &&
1065
+ expected->getName () == previous->getName ()) {
1066
+ if (!previous->getType ()->isEqual (expected->getType ())) {
1067
+ TC.diagnose (previous->getLoc (),
1068
+ diag::type_mismatch_fallthrough_pattern_list,
1069
+ previous->getType (), expected->getType ());
1070
+ previous->markInvalid ();
1071
+ expected->markInvalid ();
1072
+ }
1073
+ matched = true ;
1074
+ break ;
1075
+ }
1076
+ }
1077
+ if (!matched) {
1078
+ TC.diagnose (PreviousFallthrough->getLoc (),
1079
+ diag::fallthrough_into_case_with_var_binding,
1080
+ expected->getName ());
1081
+ }
1082
+ }
1083
+ }
1084
+ }
1085
+
950
1086
Stmt *visitSwitchStmt (SwitchStmt *switchStmt) {
951
1087
// Type-check the subject expression.
952
1088
Expr *subjectExpr = switchStmt->getSubjectExpr ();
@@ -979,141 +1115,21 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
979
1115
FallthroughDest = std::next (i) == e ? nullptr : *std::next (i);
980
1116
981
1117
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
- }
1118
+ // Resolve the pattern in our case label if it has not been resolved
1119
+ // and check that our var decls follow invariants.
1120
+ checkCaseLabelItem (caseBlock, labelItem, limitExhaustivityChecks,
1121
+ subjectType);
1049
1122
}
1050
1123
1051
1124
// Check restrictions on '@unknown'.
1052
1125
if (caseBlock->hasUnknownAttr ()) {
1053
- if (caseBlock->getCaseLabelItems ().size () != 1 ) {
1054
- assert (!caseBlock->getCaseLabelItems ().empty () &&
1055
- " parser should not produce case blocks with no items" );
1056
- TC.diagnose (caseBlock->getLoc (),
1057
- diag::unknown_case_multiple_patterns)
1058
- .highlight (caseBlock->getCaseLabelItems ()[1 ].getSourceRange ());
1059
- limitExhaustivityChecks = true ;
1060
- }
1061
-
1062
- if (FallthroughDest != nullptr ) {
1063
- if (!caseBlock->isDefault ())
1064
- TC.diagnose (caseBlock->getLoc (), diag::unknown_case_must_be_last);
1065
- limitExhaustivityChecks = true ;
1066
- }
1067
-
1068
- const auto &labelItem = caseBlock->getCaseLabelItems ().front ();
1069
- if (labelItem.getGuardExpr () && !labelItem.isDefault ()) {
1070
- TC.diagnose (labelItem.getStartLoc (),
1071
- diag::unknown_case_where_clause)
1072
- .highlight (labelItem.getGuardExpr ()->getSourceRange ());
1073
- }
1074
-
1075
- const Pattern *pattern =
1076
- labelItem.getPattern ()->getSemanticsProvidingPattern ();
1077
- if (!isa<AnyPattern>(pattern)) {
1078
- TC.diagnose (labelItem.getStartLoc (),
1079
- diag::unknown_case_must_be_catchall)
1080
- .highlight (pattern->getSourceRange ());
1081
- }
1126
+ checkUnknownAttrRestrictions (caseBlock, limitExhaustivityChecks);
1082
1127
}
1083
1128
1084
1129
// If the previous case fellthrough, similarly check that that case's bindings
1085
1130
// includes our first label item's pattern bindings and types.
1086
1131
if (PreviousFallthrough && previousBlock) {
1087
- auto firstPattern = caseBlock->getCaseLabelItems ()[0 ].getPattern ();
1088
- SmallVector<VarDecl *, 4 > vars;
1089
- firstPattern->collectVariables (vars);
1090
-
1091
- for (auto &labelItem : previousBlock->getCaseLabelItems ()) {
1092
- const Pattern *pattern = labelItem.getPattern ();
1093
- SmallVector<VarDecl *, 4 > PreviousVars;
1094
- pattern->collectVariables (PreviousVars);
1095
- for (auto expected : vars) {
1096
- bool matched = false ;
1097
- if (!expected->hasName ())
1098
- continue ;
1099
- for (auto previous: PreviousVars) {
1100
- if (previous->hasName () && expected->getName () == previous->getName ()) {
1101
- if (!previous->getType ()->isEqual (expected->getType ())) {
1102
- TC.diagnose (previous->getLoc (), diag::type_mismatch_fallthrough_pattern_list,
1103
- previous->getType (), expected->getType ());
1104
- previous->markInvalid ();
1105
- expected->markInvalid ();
1106
- }
1107
- matched = true ;
1108
- break ;
1109
- }
1110
- }
1111
- if (!matched) {
1112
- TC.diagnose (PreviousFallthrough->getLoc (),
1113
- diag::fallthrough_into_case_with_var_binding, expected->getName ());
1114
- }
1115
- }
1116
- }
1132
+ checkFallthroughPatternBindingsAndTypes (caseBlock, previousBlock);
1117
1133
}
1118
1134
1119
1135
// Type-check the body statements.
0 commit comments