Description
Currently, type flow analysis works on a data flow summary which is a linear sequence of simple operations. Control dependency for conditional execution is expressed using an optional condition which can be attached to any data flow operation. This representation results in the high speed of the analysis (which is important as TFA may need to re-analyze each summary many times due to context sensitivity), but misses control dependencies for a sequence of statements and needs to approximate loops.
For example:
class A {
@pragma('vm:never-inline')
B foo() => throw 'Does not return';
}
class B {
@pragma('vm:never-inline')
void bar() {
print('Not reachable');
}
}
void main() {
A().foo();
B().bar();
}
In this case, there are no data dependencies between A().foo()
and B().bar()
. So, although analysis infers that A.foo()
does not return (returns empty type), B().bar()
is not affected and it is not eliminated.
If there is a data dependency (A().foo().bar()
), the dependent .bar()
call is eliminated (replaced with throw
).
Related issue about approximation of loops in data flow: #40256.
We can try to express full control flow in the TFA summary and see if the improvements in the analysis precision would outweigh increased compilation time.