Description
Take some ridiculous code like:
void main() {
int x = foo();
print(x.runtimeType);
}
int foo() {
num x = 1.5;
if (x is! int) {
label: break label;
print("Gotcha");
}
return x;
}
This code compiles and prints Gotcha
and double
.
If I change label: break label;
to the supposedly completely equivalent label: { break label; }
, it stops compiling, because the flow analysis correctly deduces that label: { break label; }
can terminate normally.
The label: break label;
is mistakenly seen as not terminating. Code immediately after it is considered dead code by the analyzer. Type promotion assumes it never completes.
This affects both analyzer and front-end.
(Guessing we are doing something special with lables, maybe storing them on the inner statement's AST node instead of making a labeled statement a proper composite statement with its own AST node, which makes it much easier to forget that they can be on any statement. Especially since it only matters for composite statements which can contain a break
or continue
. Which includes break
statements.)
(Found while looking at dart-lang/language#2586).