You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The NNBD spec pull request (#293) contains the following text:
When static checking is done in a migrated library, types which are imported
from unmigrated libraries are seen as legacy types. However, for the purposes
of type inference in migrated libraries, types imported from unmigrated
libraries shall be treated as non-nullable. As a result, legacy types will
never appear as type annotations in migrated libraries, nor will they appear in
reified positions.
I'm trying to understand how to interpret this paragraph in light of the fact that type inference and static checking are interleaved.
For example:
// In a legacy libraryList<int> f() { ... }
// In a migrated libraryList<T> g<T>(List<T> l) { ... }
main() {
f()..add(null); // (A)g(f()..add(null))..add(null); // (B)g(f()..add(null))..add(0); // (C)
}
To analyze (A), the analyzer goes through the following steps:
(1) Figure out the type of f() (List<int*>*)
(2) Figure out the argument type expected by f()..add (int*)
(3) Check whether Null is assignable to that type (it is, so there is no error at (A))
To analyze (B), the steps are as above, and then:
(4) Perform type inference to determine the implicit type argument passed to g
(5) Figure out the argument type expected by g(f()..add(null)).add
(6) Check whether Null is assignable to that type
Based on the spec text quoted above, I believe (4) is supposed to infer a type argument of int (as opposed to int*). Meaning that (5) determines that g(f()..add(null)).add requires an int, so the assignability check at (6) will fail, and there will be an error at (B).
But how does this happen? The spec text says "for the purposes of type inference in migrated libraries, types imported from unmigrated libraries shall be treated as non-nullable", which seems to imply that back in step (1), we should have gotten a type of List<int>. But then step (3) would have found an error at (A), which I don't think we want.
I'm wondering if the rule we really want is something like this:
When static checking is done in a migrated library, types which are imported
from unmigrated libraries are seen as legacy types. However, when type inference
is performed in migrated libraries, types are converted to non-nullable types
(or potentially non-nullable types, in the case of type parameters) at
the point where the inference occurs. As a result, legacy types will
never appear as type annotations in migrated libraries, nor will they appear in
reified positions.
I believe this would imply that all the calls to f()..add(null) in the example above are ok, and all the gs are type inferred as g<int>; therefore (A) and (C) are ok, but there's an error at (B).
The text was updated successfully, but these errors were encountered:
I agree with this interpretation, and I see how the text is unclear. I will update it. The intention is that when missing type annotations or type parameters are filled in by inference in a migrated library, the legacy annotations are erased from those types. Does that agree with your interpretation?
I agree with this interpretation, and I see how the text is unclear. I will update it. The intention is that when missing type annotations or type parameters are filled in by inference in a migrated library, the legacy annotations are erased from those types. Does that agree with your interpretation?
The NNBD spec pull request (#293) contains the following text:
I'm trying to understand how to interpret this paragraph in light of the fact that type inference and static checking are interleaved.
For example:
To analyze (A), the analyzer goes through the following steps:
(1) Figure out the type of
f()
(List<int*>*
)(2) Figure out the argument type expected by
f()..add
(int*
)(3) Check whether
Null
is assignable to that type (it is, so there is no error at (A))To analyze (B), the steps are as above, and then:
(4) Perform type inference to determine the implicit type argument passed to
g
(5) Figure out the argument type expected by
g(f()..add(null)).add
(6) Check whether
Null
is assignable to that typeBased on the spec text quoted above, I believe (4) is supposed to infer a type argument of
int
(as opposed toint*
). Meaning that (5) determines thatg(f()..add(null)).add
requires anint
, so the assignability check at (6) will fail, and there will be an error at (B).But how does this happen? The spec text says "for the purposes of type inference in migrated libraries, types imported from unmigrated libraries shall be treated as non-nullable", which seems to imply that back in step (1), we should have gotten a type of
List<int>
. But then step (3) would have found an error at (A), which I don't think we want.I'm wondering if the rule we really want is something like this:
I believe this would imply that all the calls to
f()..add(null)
in the example above are ok, and all theg
s are type inferred asg<int>
; therefore (A) and (C) are ok, but there's an error at (B).The text was updated successfully, but these errors were encountered: