Consider the following code:
class C {
int v;
C(this.v);
}
f(C c) {
var x = c.v;
print(x + 1);
}
main() {
C(null);
}
The migration tool currently migrates this to:
class C {
int v; // (1)
C(this.v);
}
f(C c) {
var x = c.v; // (2)
print(x + 1); // (3)
}
main() {
C(null!); // (4)
}
What's happening is that since the use of x at (3) is guaranteed to fail if x is null, and that use post-dominates the declaration of x at (2), the tool infers that the type of x should be non-nullable. But since the type of x is inferred from the type of C.v, it propagates this non-nullability back to the declaration of C.v (at (1)). Which in turn means that null can't be validly passed to the C constructor at (4).
What should happen instead is that the back-propagation of non-nullability should stop at (2), allowing C.v to be nullable, so the migration would be:
class C {
int? v; // (1)
C(this.v);
}
f(C c) {
var x = c.v!; // (2)
print(x + 1); // (3)
}
main() {
C(null); // (4)
}
Consider the following code:
The migration tool currently migrates this to:
What's happening is that since the use of
xat (3) is guaranteed to fail ifxisnull, and that use post-dominates the declaration ofxat (2), the tool infers that the type ofxshould be non-nullable. But since the type ofxis inferred from the type ofC.v, it propagates this non-nullability back to the declaration ofC.v(at (1)). Which in turn means thatnullcan't be validly passed to theCconstructor at (4).What should happen instead is that the back-propagation of non-nullability should stop at (2), allowing
C.vto be nullable, so the migration would be: