| // 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) {} |