Description
Global type inference creates a graph for _SyncStarIterator.moveNext()
is too conservative.
The graph has a return edge that 'falls out' of the while (true) { ...; return ...; ...}
loop and off the end of the method, causing null
to be a possible result. The path is statically not feasible and in modern Dart it is an error to have an implicit return like this so it should be possible to still be approximate with a union over all explicit returns.
The temporary (five years+) fix is to add an unreachable return that removes null
from the inferred return type
The impact is that the program contains unnecessary boolConversionCheck
s on almost all calls to moveNext()
because one of them possibly returns a legacy-nullable value (the inferred null
is there even in sound mode since there is otherwise no reason to narrow return values).
Repro:
Iterable<int> foo() sync* { yield 1; }
main() {
for (final x in foo()) print(x);
}
Compiled with the temporary fix and without:
...
2411c2411
< for (var t1 = A.foo(), t1 = new A._SyncStarIterator(t1._outerHelper(), t1.$ti._eval$1("_SyncStarIterator<1>")); t1.moveNext$0();)
---
> for (var t1 = A.foo(), t1 = new A._SyncStarIterator(t1._outerHelper(), t1.$ti._eval$1("_SyncStarIterator<1>")); A.boolConversionCheck(t1.moveNext$0());)
2739c2739
< if (nestedIterator.moveNext$0()) {
---
> if (A.boolConversionCheck(nestedIterator.moveNext$0())) {
2789d2788
< return false;
2918c2917
< for (count = 0; it.moveNext$0();)
---
> for (count = 0; A.boolConversionCheck(it.moveNext$0());)