Skip to content

Commit 7034ef9

Browse files
authored
Revert "Stricter enforcement of the "large space" heuristic"
1 parent 8964108 commit 7034ef9

File tree

7 files changed

+53
-122
lines changed

7 files changed

+53
-122
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ WARNING(unreachable_code_after_stmt,none,
244244
"code after '%select{return|break|continue|throw}0' will never "
245245
"be executed", (unsigned))
246246
WARNING(unreachable_case,none,
247-
"case will never be executed", ())
247+
"%select{case|default}0 will never be executed", (bool))
248248
WARNING(switch_on_a_constant,none,
249249
"switch condition evaluates to a constant", ())
250250
NOTE(unreachable_code_note,none, "will never be executed", ())

include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3858,11 +3858,6 @@ WARNING(redundant_particular_literal_case,none,
38583858
NOTE(redundant_particular_literal_case_here,none,
38593859
"first occurrence of identical literal pattern is here", ())
38603860

3861-
ERROR(cannot_prove_exhaustive_switch,none,
3862-
"analysis of uncovered switch statement is too complex to perform in a "
3863-
"reasonable amount of time; "
3864-
"insert a 'default' clause to cover this switch statement", ())
3865-
38663861
// HACK: Downgrades the above to warnings if any of the cases is marked
38673862
// @_downgrade_exhaustivity_check.
38683863
WARNING(non_exhaustive_switch_warn_swift3,none, "switch must be exhaustive", ())

lib/SILGen/SILGenPattern.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,8 +1031,7 @@ void PatternMatchEmission::emitDispatch(ClauseMatrix &clauses, ArgArray args,
10311031
} else {
10321032
Loc = clauses[firstRow].getCasePattern()->getStartLoc();
10331033
}
1034-
if (!isDefault)
1035-
SGF.SGM.diagnose(Loc, diag::unreachable_case);
1034+
SGF.SGM.diagnose(Loc, diag::unreachable_case, isDefault);
10361035
}
10371036
}
10381037
}

lib/Sema/TypeCheckSwitchStmt.cpp

Lines changed: 41 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,6 @@ namespace {
169169
}
170170
}
171171
}
172-
173172

174173
public:
175174
explicit Space(Type T, Identifier NameForPrinting)
@@ -202,29 +201,6 @@ namespace {
202201
return computeSize(TC, cache);
203202
}
204203

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-
228204
static size_t getMaximumSize() {
229205
return MAX_SPACE_SIZE;
230206
}
@@ -1035,16 +1011,14 @@ namespace {
10351011
if (subjectType && subjectType->isStructurallyUninhabited()) {
10361012
return;
10371013
}
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.
1014+
10471015
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+
}
10481022
return;
10491023
}
10501024

@@ -1089,18 +1063,23 @@ namespace {
10891063

10901064
Space totalSpace(subjectType, Identifier());
10911065
Space coveredSpace(spaces);
1092-
10931066
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());
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+
1079+
diagnoseMissingCases(TC, Switch, /*justNeedsDefault*/true, Space());
11011080
return;
11021081
}
1103-
1082+
11041083
auto uncovered = totalSpace.minus(coveredSpace, TC).simplify(TC);
11051084
if (uncovered.isEmpty()) {
11061085
return;
@@ -1113,12 +1092,11 @@ namespace {
11131092
if (Space::canDecompose(uncovered.getType())) {
11141093
SmallVector<Space, 4> spaces;
11151094
Space::decompose(TC, uncovered.getType(), spaces);
1116-
diagnoseMissingCases(TC, Switch, RequiresDefault::No, Space(spaces));
1095+
diagnoseMissingCases(TC, Switch,
1096+
/*justNeedsDefault*/ false, Space(spaces));
11171097
} else {
1118-
diagnoseMissingCases(TC, Switch, Switch->getCases().empty()
1119-
? RequiresDefault::EmptySwitchBody
1120-
: RequiresDefault::UncoveredSwitch,
1121-
Space());
1098+
diagnoseMissingCases(TC, Switch,
1099+
/*justNeedsDefault*/ true, Space());
11221100
}
11231101
return;
11241102
}
@@ -1129,7 +1107,7 @@ namespace {
11291107
uncovered = Space(spaces);
11301108
}
11311109

1132-
diagnoseMissingCases(TC, Switch, RequiresDefault::No, uncovered,
1110+
diagnoseMissingCases(TC, Switch, /*justNeedsDefault*/ false, uncovered,
11331111
sawDowngradablePattern);
11341112
}
11351113

@@ -1161,15 +1139,8 @@ namespace {
11611139
}
11621140
}
11631141

1164-
enum class RequiresDefault {
1165-
No,
1166-
EmptySwitchBody,
1167-
UncoveredSwitch,
1168-
SpaceTooLarge,
1169-
};
1170-
11711142
static void diagnoseMissingCases(TypeChecker &TC, const SwitchStmt *SS,
1172-
RequiresDefault defaultReason,
1143+
bool justNeedsDefault,
11731144
Space uncovered,
11741145
bool sawDowngradablePattern = false) {
11751146
SourceLoc startLoc = SS->getStartLoc();
@@ -1178,30 +1149,20 @@ namespace {
11781149
llvm::SmallString<128> buffer;
11791150
llvm::raw_svector_ostream OS(buffer);
11801151

1181-
switch (defaultReason) {
1182-
case RequiresDefault::EmptySwitchBody: {
1183-
OS << tok::kw_default << ":\n" << placeholder << "\n";
1184-
TC.diagnose(startLoc, diag::empty_switch_stmt)
1185-
.fixItInsert(endLoc, buffer.str());
1186-
}
1187-
return;
1188-
case RequiresDefault::UncoveredSwitch: {
1152+
bool InEditor = TC.Context.LangOpts.DiagnosticsEditorMode;
1153+
1154+
if (justNeedsDefault) {
11891155
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-
}
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-
}
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+
}
12011165
return;
1202-
case RequiresDefault::No:
1203-
// Break out to diagnose below.
1204-
break;
12051166
}
12061167

12071168
// If there's nothing else to diagnose, bail.
@@ -1228,7 +1189,7 @@ namespace {
12281189
//
12291190
// missing case '(.none, .some(_))'
12301191
// missing case '(.some(_), .none)'
1231-
if (TC.Context.LangOpts.DiagnosticsEditorMode) {
1192+
if (InEditor) {
12321193
buffer.clear();
12331194
SmallVector<Space, 8> emittedSpaces;
12341195
for (auto &uncoveredSpace : uncovered.getSpaces()) {
@@ -1251,7 +1212,7 @@ namespace {
12511212
TC.diagnose(startLoc, diag::missing_several_cases, false)
12521213
.fixItInsert(endLoc, buffer.str());
12531214
} else {
1254-
TC.diagnose(startLoc, mainDiagType);
1215+
TC.Context.Diags.diagnose(startLoc, mainDiagType);
12551216

12561217
SmallVector<Space, 8> emittedSpaces;
12571218
for (auto &uncoveredSpace : uncovered.getSpaces()) {

test/SILGen/unreachable_code.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ func testUnreachableCase5(a : Tree) {
106106
switch a {
107107
case _:
108108
break
109-
default:
109+
default: // expected-warning {{default will never be executed}}
110110
return
111111
}
112112
}

test/SILOptimizer/unreachable_code.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ class r20097963MyClass {
208208
str = "A"
209209
case .B:
210210
str = "B"
211-
default:
211+
default: // expected-warning {{default will never be executed}}
212212
str = "unknown" // Should not be rejected.
213213
}
214214
return str

test/Sema/exhaustive_switch.swift

Lines changed: 8 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ enum ContainsOverlyLargeEnum {
444444
}
445445

446446
func quiteBigEnough() -> Bool {
447-
switch (OverlyLargeSpaceEnum.case1, OverlyLargeSpaceEnum.case2) { // expected-error {{analysis of uncovered switch statement is too complex to perform in a reasonable amount of time}}
447+
switch (OverlyLargeSpaceEnum.case1, OverlyLargeSpaceEnum.case2) { // expected-error {{switch must be exhaustive}}
448448
// expected-note@-1 {{do you want to add a default clause?}}
449449
case (.case0, .case0): return true
450450
case (.case1, .case1): return true
@@ -460,7 +460,8 @@ func quiteBigEnough() -> Bool {
460460
case (.case11, .case11): return true
461461
}
462462

463-
switch (OverlyLargeSpaceEnum.case1, OverlyLargeSpaceEnum.case2) { // expected-error {{analysis of uncovered switch statement is too complex to perform in a reasonable amount of time}}
463+
// No diagnostic
464+
switch (OverlyLargeSpaceEnum.case1, OverlyLargeSpaceEnum.case2) { // expected-error {{switch must be exhaustive}}
464465
// expected-note@-1 {{do you want to add a default clause?}}
465466
case (.case0, _): return true
466467
case (.case1, _): return true
@@ -476,9 +477,8 @@ func quiteBigEnough() -> Bool {
476477
}
477478

478479

479-
// expected-error@+1 {{analysis of uncovered switch statement is too complex to perform in a reasonable amount of time}}
480+
// No diagnostic
480481
switch (OverlyLargeSpaceEnum.case1, OverlyLargeSpaceEnum.case2) {
481-
// expected-note@-1 {{do you want to add a default clause?}}
482482
case (.case0, _): return true
483483
case (.case1, _): return true
484484
case (.case2, _): return true
@@ -493,9 +493,8 @@ func quiteBigEnough() -> Bool {
493493
case (.case11, _): return true
494494
}
495495

496-
// expected-error@+1 {{analysis of uncovered switch statement is too complex to perform in a reasonable amount of time}}
496+
// No diagnostic
497497
switch (OverlyLargeSpaceEnum.case1, OverlyLargeSpaceEnum.case2) {
498-
// expected-note@-1 {{do you want to add a default clause?}}
499498
case (_, .case0): return true
500499
case (_, .case1): return true
501500
case (_, .case2): return true
@@ -510,22 +509,21 @@ func quiteBigEnough() -> Bool {
510509
case (_, .case11): return true
511510
}
512511

513-
// No diagnostic
512+
// No diagnostic
514513
switch (OverlyLargeSpaceEnum.case1, OverlyLargeSpaceEnum.case2) {
515514
case (_, _): return true
516515
}
517516

518-
// expected-error@+1 {{analysis of uncovered switch statement is too complex to perform in a reasonable amount of time}}
517+
// No diagnostic
519518
switch (OverlyLargeSpaceEnum.case1, OverlyLargeSpaceEnum.case2) {
520-
// expected-note@-1 {{do you want to add a default clause?}}
521519
case (.case0, .case0): return true
522520
case (.case1, .case1): return true
523521
case (.case2, .case2): return true
524522
case (.case3, .case3): return true
525523
case _: return true
526524
}
527525

528-
// No diagnostic
526+
// No diagnostic
529527
switch ContainsOverlyLargeEnum.one(.case0) {
530528
case .one: return true
531529
case .two: return true
@@ -561,28 +559,6 @@ func infinitelySized() -> Bool {
561559
}
562560
}
563561

564-
// SR-6316: Size heuristic is insufficient to catch space covering when the
565-
// covered space size is greater than or equal to the master space size.
566-
func largeSpaceMatch(_ x: Bool) {
567-
switch (x, (x, x, x, x), (x, x, x, x)) { // expected-error {{analysis of uncovered switch statement is too complex to perform in a reasonable amount of time}}
568-
// expected-note@-1 {{do you want to add a default clause?}}
569-
case (true, (_, _, _, _), (_, true, true, _)):
570-
break
571-
case (true, (_, _, _, _), (_, _, false, _)):
572-
break
573-
case (_, (_, true, true, _), (_, _, false, _)):
574-
break
575-
case (_, (_, _, false, _), (_, true, true, _)):
576-
break
577-
case (_, (_, true, true, _), (_, true, true, _)):
578-
break
579-
case (_, (_, _, false, _), (_, _, false, _)):
580-
break
581-
case (_, (false, false, false, false), (_, _, _, _)):
582-
break
583-
}
584-
}
585-
586562
func diagnoseDuplicateLiterals() {
587563
let str = "def"
588564
let int = 2

0 commit comments

Comments
 (0)