dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.22k stars 1.57k forks source link

co19_2/Language/Statements/Continue/async_loops_t09 crashes on dart2js #46289

Open sgrekhov opened 3 years ago

sgrekhov commented 3 years ago

co19_2/Language/Statements/Continue/async_loops_t09 test crashes on dart2js. Error log

rakudrama commented 3 years ago

The crash is in compiling test3.

test3 has an immediate exit from the loop, followed by more code at L2:. Changing continue L0; to if (true) continue L0; allows the code to compile.

Future test3() async {
  List<int> log = [];

  L0:
  await for (String s in makeStream(['a', 'b'], 0, log)) {
    L1:
    do {
      continue L0;  // <--- HERE
      L2:
      await for (String s in makeStream(['a', 'b'], 1, log)) {
        ... more code ...
      }
    } while (log.length < 10);
    continue L0;
  }
  Expect.listEquals([], log);
}

What I suspect is happening here:

The CFG builder has logic to avoid generating CFG blocks for unreachable code after an unconditional jump, since there is no place to attach the unreachable code. This logic is probably not working as expected for async loops over streams. Something is generated for the code from L2:. This code is unreachable and has no predecessor, leading to the assert in the error log.

Further questions:

Does this failure need a async method, or can it occur in a 'sync' method?

What is the appropriate priority for this issue? The code can be made to work by deleting the unreachable code (probably a programming logic error in an application), or by adding if (true) ..., so at most P2.