@@ -169,6 +169,7 @@ namespace {
169
169
}
170
170
}
171
171
}
172
+
172
173
173
174
public:
174
175
explicit Space (Type T, Identifier NameForPrinting)
@@ -201,6 +202,29 @@ namespace {
201
202
return computeSize (TC, cache);
202
203
}
203
204
205
+ // Walk one level deep into the space to return whether it is
206
+ // composed entirely of irrefutable patterns - these are quick to check
207
+ // regardless of the size of the total type space.
208
+ bool isAllIrrefutable () const {
209
+ switch (getKind ()) {
210
+ case SpaceKind::Empty:
211
+ case SpaceKind::Type:
212
+ return true ;
213
+ case SpaceKind::BooleanConstant:
214
+ return false ;
215
+ case SpaceKind::Constructor:
216
+ return llvm::all_of (getSpaces (), [](const Space &sp) {
217
+ return sp.getKind () == SpaceKind::Type
218
+ || sp.getKind () == SpaceKind::Empty;
219
+ });
220
+ case SpaceKind::Disjunct: {
221
+ return llvm::all_of (getSpaces (), [](const Space &sp) {
222
+ return sp.isAllIrrefutable ();
223
+ });
224
+ }
225
+ }
226
+ }
227
+
204
228
static size_t getMaximumSize () {
205
229
return MAX_SPACE_SIZE;
206
230
}
@@ -1011,14 +1035,16 @@ namespace {
1011
1035
if (subjectType && subjectType->isStructurallyUninhabited ()) {
1012
1036
return ;
1013
1037
}
1014
-
1038
+
1039
+ // Reject switch statements with empty blocks.
1040
+ if (limitedChecking && Switch->getCases ().empty ()) {
1041
+ SpaceEngine::diagnoseMissingCases (TC, Switch,
1042
+ RequiresDefault::EmptySwitchBody,
1043
+ SpaceEngine::Space ());
1044
+ }
1045
+
1046
+ // If the switch body fails to typecheck, end analysis here.
1015
1047
if (limitedChecking) {
1016
- // Reject switch statements with empty blocks.
1017
- if (Switch->getCases ().empty ()) {
1018
- SpaceEngine::diagnoseMissingCases (TC, Switch,
1019
- /* justNeedsDefault*/ true ,
1020
- SpaceEngine::Space ());
1021
- }
1022
1048
return ;
1023
1049
}
1024
1050
@@ -1063,23 +1089,18 @@ namespace {
1063
1089
1064
1090
Space totalSpace (subjectType, Identifier ());
1065
1091
Space coveredSpace (spaces);
1066
- size_t totalSpaceSize = totalSpace.getSize (TC);
1067
- if (totalSpaceSize > Space::getMaximumSize ()) {
1068
- // Because the space is large, we have to extend the size
1069
- // heuristic to compensate for actually exhaustively pattern matching
1070
- // over enormous spaces. In this case, if the covered space covers
1071
- // as much as the total space, and there were no duplicates, then we
1072
- // can assume the user did the right thing and that they don't need
1073
- // a 'default' to be inserted.
1074
- if (!sawRedundantPattern
1075
- && coveredSpace.getSize (TC) >= totalSpaceSize) {
1076
- return ;
1077
- }
1078
1092
1079
- diagnoseMissingCases (TC, Switch, /* justNeedsDefault*/ true , Space ());
1093
+ size_t totalSpaceSize = totalSpace.getSize (TC);
1094
+ if (totalSpaceSize > Space::getMaximumSize () && !coveredSpace.isAllIrrefutable ()) {
1095
+ // Because the space is large, fall back to requiring 'default'.
1096
+ //
1097
+ // FIXME: Explore ways of reducing runtime of this analysis or doing
1098
+ // partial analysis to recover this case.
1099
+ diagnoseMissingCases (TC, Switch,
1100
+ RequiresDefault::SpaceTooLarge, Space ());
1080
1101
return ;
1081
1102
}
1082
-
1103
+
1083
1104
auto uncovered = totalSpace.minus (coveredSpace, TC).simplify (TC);
1084
1105
if (uncovered.isEmpty ()) {
1085
1106
return ;
@@ -1092,11 +1113,12 @@ namespace {
1092
1113
if (Space::canDecompose (uncovered.getType ())) {
1093
1114
SmallVector<Space, 4 > spaces;
1094
1115
Space::decompose (TC, uncovered.getType (), spaces);
1095
- diagnoseMissingCases (TC, Switch,
1096
- /* justNeedsDefault*/ false , Space (spaces));
1116
+ diagnoseMissingCases (TC, Switch, RequiresDefault::No, Space (spaces));
1097
1117
} else {
1098
- diagnoseMissingCases (TC, Switch,
1099
- /* justNeedsDefault*/ true , Space ());
1118
+ diagnoseMissingCases (TC, Switch, Switch->getCases ().empty ()
1119
+ ? RequiresDefault::EmptySwitchBody
1120
+ : RequiresDefault::UncoveredSwitch,
1121
+ Space ());
1100
1122
}
1101
1123
return ;
1102
1124
}
@@ -1107,7 +1129,7 @@ namespace {
1107
1129
uncovered = Space (spaces);
1108
1130
}
1109
1131
1110
- diagnoseMissingCases (TC, Switch, /* justNeedsDefault */ false , uncovered,
1132
+ diagnoseMissingCases (TC, Switch, RequiresDefault::No , uncovered,
1111
1133
sawDowngradablePattern);
1112
1134
}
1113
1135
@@ -1139,8 +1161,15 @@ namespace {
1139
1161
}
1140
1162
}
1141
1163
1164
+ enum class RequiresDefault {
1165
+ No,
1166
+ EmptySwitchBody,
1167
+ UncoveredSwitch,
1168
+ SpaceTooLarge,
1169
+ };
1170
+
1142
1171
static void diagnoseMissingCases (TypeChecker &TC, const SwitchStmt *SS,
1143
- bool justNeedsDefault ,
1172
+ RequiresDefault defaultReason ,
1144
1173
Space uncovered,
1145
1174
bool sawDowngradablePattern = false ) {
1146
1175
SourceLoc startLoc = SS->getStartLoc ();
@@ -1149,20 +1178,30 @@ namespace {
1149
1178
llvm::SmallString<128 > buffer;
1150
1179
llvm::raw_svector_ostream OS (buffer);
1151
1180
1152
- bool InEditor = TC.Context .LangOpts .DiagnosticsEditorMode ;
1153
-
1154
- if (justNeedsDefault) {
1181
+ switch (defaultReason) {
1182
+ case RequiresDefault::EmptySwitchBody: {
1155
1183
OS << tok::kw_default << " :\n " << placeholder << " \n " ;
1156
- if (SS->getCases ().empty ()) {
1157
- TC.Context .Diags .diagnose (startLoc, diag::empty_switch_stmt)
1158
- .fixItInsert (endLoc, buffer.str ());
1159
- } else {
1160
- TC.Context .Diags .diagnose (startLoc, diag::non_exhaustive_switch);
1161
- TC.Context .Diags .diagnose (startLoc, diag::missing_several_cases,
1162
- uncovered.isEmpty ()).fixItInsert (endLoc,
1163
- buffer.str ());
1164
- }
1184
+ TC.diagnose (startLoc, diag::empty_switch_stmt)
1185
+ .fixItInsert (endLoc, buffer.str ());
1186
+ }
1187
+ return ;
1188
+ case RequiresDefault::UncoveredSwitch: {
1189
+ OS << tok::kw_default << " :\n " << placeholder << " \n " ;
1190
+ TC.diagnose (startLoc, diag::non_exhaustive_switch);
1191
+ TC.diagnose (startLoc, diag::missing_several_cases, uncovered.isEmpty ())
1192
+ .fixItInsert (endLoc, buffer.str ());
1193
+ }
1165
1194
return ;
1195
+ case RequiresDefault::SpaceTooLarge: {
1196
+ OS << tok::kw_default << " :\n " << " <#fatalError()#>" << " \n " ;
1197
+ TC.diagnose (startLoc, diag::cannot_prove_exhaustive_switch);
1198
+ TC.diagnose (startLoc, diag::missing_several_cases, uncovered.isEmpty ())
1199
+ .fixItInsert (endLoc, buffer.str ());
1200
+ }
1201
+ return ;
1202
+ case RequiresDefault::No:
1203
+ // Break out to diagnose below.
1204
+ break ;
1166
1205
}
1167
1206
1168
1207
// If there's nothing else to diagnose, bail.
@@ -1189,7 +1228,7 @@ namespace {
1189
1228
//
1190
1229
// missing case '(.none, .some(_))'
1191
1230
// missing case '(.some(_), .none)'
1192
- if (InEditor ) {
1231
+ if (TC. Context . LangOpts . DiagnosticsEditorMode ) {
1193
1232
buffer.clear ();
1194
1233
SmallVector<Space, 8 > emittedSpaces;
1195
1234
for (auto &uncoveredSpace : uncovered.getSpaces ()) {
@@ -1212,7 +1251,7 @@ namespace {
1212
1251
TC.diagnose (startLoc, diag::missing_several_cases, false )
1213
1252
.fixItInsert (endLoc, buffer.str ());
1214
1253
} else {
1215
- TC.Context . Diags . diagnose (startLoc, mainDiagType);
1254
+ TC.diagnose (startLoc, mainDiagType);
1216
1255
1217
1256
SmallVector<Space, 8 > emittedSpaces;
1218
1257
for (auto &uncoveredSpace : uncovered.getSpaces ()) {
0 commit comments