blob: 9ba0eafd942f3a1516d7f08f22d7fc8e6c859ebc [file] [log] [blame]
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Test switch statement "fallthrough" behavior.
//
// Tests behavior for Dart from version 3.0, where there is no error or
// warning related to control reaching the end of switch cases.
// See `case_fallthrough_legacy_error_test.dart` for previous behavior.
// Return type `dynamic` to avoid a warning for either of
// `return;` or `return x;`.
dynamic testSwitch(int x) {
// Catch all control flow leaving the switch.
// Run switch in catch clause to check that `rethrow` is control flow.
TRY:
try {
throw x;
} catch (_) {
// Add loop as break/continue target.
LOOP:
do {
switch (x) {
case 0:
case 1:
nop(x);
break; // Break switch.
case 2:
nop(x);
break LOOP;
case 3:
nop(x);
continue; // Continue loop.
case 4:
nop(x);
continue LOOP;
case 5:
nop(x);
continue LAST;
case 6:
nop(x);
return;
case 7:
nop(x);
return x;
case 8:
nop(x);
throw x;
case 9:
nop(x);
rethrow;
case 10:
case 11:
{
nop(x);
break;
}
case 12:
{
nop(x);
break LOOP;
}
case 13:
{
nop(x);
continue; // Continue loop.
}
case 14:
{
nop(x);
continue LOOP;
}
case 15:
{
nop(x);
continue LAST;
}
case 16:
{
nop(x);
return;
}
case 17:
{
nop(x);
return x;
}
case 18:
{
nop(x);
throw x;
}
case 19:
{
nop(x);
rethrow;
}
case 20:
{
{
nop(x);
break; // Break and exit switch.
}
}
case 21:
{
{
nop(x);
break LOOP; // Break loop, exits switch (and loop).
}
}
case 22:
{
{
nop(x);
continue; // Continue loop, exits switch.
}
}
case 23:
{
{
nop(x);
continue LOOP; // Continue loop, exits switch.
}
}
case 24:
{
{
nop(x);
continue LAST; // Exits case, goto other case.
}
}
case 25:
{
{
nop(x);
return; // Exits function, loop and switch.
}
}
case 26:
{
{
nop(x);
return x; // Exits function, loop and switch.
}
}
case 27:
{
{
nop(x);
throw x; // Exits switch.
}
}
case 28:
{
{
nop(x);
rethrow; // Exits switch.
}
}
case 29:
while (true) break; // Breaks loop, reaches end.
case 30:
do break; while (true); // Breaks loop, reaches end.
case 31:
for (;;) break; // Breaks loop, reaches end.
case 32:
for (var _ in []) break LOOP; // Can be empty, reaches end.
case 33:
if (x.isEven) {
break; // Breaks and exits switch.
} else {
break LOOP; // Breaks loop and exits switch.
}
case 34:
(throw 0); // Exits switch.
case 35:
nop(x); // Reaches end.
case 36:
L:
break; // Breaks and exits switch.
case 37:
L:
break L; // Breaks break statement only, reaches end.
case 38:
L:
if (x.isOdd) {
break L; // Breaks if, reaches end.
} else {
break LOOP;
}
case 39:
notEver(x); // Type Never implies not completing.
case 40:
{
notEver(x);
}
case 41:
{
{
notEver(x);
}
}
case 42:
{
do {
notEver(x);
} while (true);
}
case 43:
{
if (x.isEven) {
notEver(x);
} else {
notEver(-x);
}
}
case 44:
nop(x.isEven ? notEver(x) : notEver(-x));
LAST:
case 99:
}
} while (false);
} finally {
// Catch all control flow leaving the switch and ignore it.
break TRY;
}
}
Never notEver(int x) {
if (x < 0) {
notEver(x + 1);
} else {
throw AssertionError("Never");
}
}
main() {
// Don't let compiler optimize for a specific value.
for (int i = 0; i <= 100; i++) {
testSwitch(i);
}
}
/// Don't make it obvious that a switch case isn't doing anything.
void nop(Object? x) {}