With this change, we no longer use the "never" graph node for:
- instance creations
- explicit references to `this` or `super`
- the static type of `throw` and `rethrow` expressions
Change-Id: I995be86ee0f4d8002c70cf98e7e5d2767529d00b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/125226
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This eliminates a few direct references to `always` and `never` nodes
from the edge builder. It also fixes a latent bug where we were
failing to create a hard edge when handling "is" expressions.
Change-Id: I4c88432c97932eac3554cfcb75bbd634c0e2e4c1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/125061
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
Previously, when the migration engine found a type that was implicitly
or explicitly dynamic, it assumed the type was meant to be nullable.
This seemed reasonable (since, after migration, `dynamic` indeed
allows null), but it caused unnecessary nullabilities to be
propagated. With this change, the migration engine tracks whether
dynamic types can be nullable or not, just as it does for all other
types. This cleans up a number of tricky corner cases in the
migration engine that were getting in the way of fixing up uses of
`always` and `never` nodes.
Note that if a `dynamic` type is determined to be non-nullable, it
will still be `dynamic` after migration; this change merely prevents
nullabilities from being needlessly propagated from that dynamic type
to other types.
Note that we still assume `dynamic` is nullable when it occurs in an
already-migrated library or as the result of a dynamic dispatch.
Change-Id: I380d0907f3489d0b84f3fdd7164113daae24274e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/125084
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Samuel Rawlins <srawlins@google.com>
A core assumption of the migration tool is that the code being
migrated may have some dependencies that have already been migrated
(e.g. the SDK itself). Of course these dependencies will need to be
analyzed as "opted in" libraries so that they can have nullability
annotations.
However, when the migration tool was first being developed, we didn't
yet have a migrated SDK, so the SDK was opted out and we just had to
pretend that it was opted in.
This CL prepares to switch over to a truly opted-in SDK by updating
the AlreadyMigratedCodeDecorator to handle opted-in code.
Change-Id: I797752401f8c7bf7cdf8d26d03d00d3d213a5127
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/124466
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
Previously, when the code being migrated referred to a nullable or a
non-nullable type in an already-migrated library, we would use the
`always` or `never` graph node to represent the nullability of the
type. This was problematic, because it made it difficult for
instrumentation to pinpoint precisely which element in an
already-migrated library was the cause of an expresion being
null-checked, or a type being made non-nullable.
We now create a fresh nullability node for each non-nullable type
coming from already-migrated code, with an edge to `always` or `never`
to ensure that the fresh node has the correct nullability, so that
instrumentation can see precisely which element it came from.
Since the migration tool doesn't traverse the ASTs of already-migrated
code, we can't report an AST node that caused such an edge, so an
`element` getter has been added EdgeOriginInfo to allow us to report
the element that caused the edge.
As before, types associated with already-migrated code are reported to
instrumentation via InstrumentationListener.externalDecoratedType. As
a new enhancement, bounds of generic parameters in already-migrated
code are reported to instrumentation via
InstrumentationListener.externalDecoratedTypeParameterBound.
Change-Id: Ided4e96e2920f8d9062688f5a6fda29b9b71dd12
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/124000
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Mike Fairhurst <mfairhurst@google.com>
This should make it easier to verify that the CFE implementation is
correct.
Note that this effort encountered a few bugs in the analyzer
implementation, which are marked with TODOs. I will fix them in
follow-up CLs.
Change-Id: Ic164a1cf214b5730f848b17db2838c29d25b00d0
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/122850
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
When promoting a type parameter, we need to create an intersection
type (e.g. "T & int"). Such a type is represented in the analyzer and
the front end as a type parameter type pointing to the same type
variable, but with a different bound.
Change-Id: I1655f9242d913ca958c279cc80c3f6329f6b396d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/122581
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
It would have been very useful in helping to track down
https://github.com/dart-lang/sdk/issues/38341#issuecomment-542892773
to have this information surfaced through the instrumentation output.
Specifically, it would be nice if the user could hover over a type
annotation that was *not* made nullable due to a propagationStep whose
`reason` was `StateChangeReason.upstream`, and see information about
all the edges for which the `sourceNode` corresponds to that type and
`isUpstreamTriggered` returns `true`. These are, in effect, the edges
that prevented the type from being marked nullable.
(Note that there's another possible reason a type might not be marked
nullable. It might be that there are no edges for which the
`destinationNode` corresponds to that type and `isTriggered` returns
`true`. In this case, the node is indeterminate, so the migration
engine left it as non-nullable because there was no need to make it
nullable).
Change-Id: I9b969201b813496d41f3a373454c2659f683178d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/121941
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
When visiting an assignment target that is an index expression
(`x[y]`) we'll need to know whether we are doing a compound assignment
or not, because this will influence whether the type context for the
index expression (`y`) should come from `operator[]` or `operator[]=`.
So before adding index expression support to FixBuilder, let's add an
`isCompound` boolean to indicate whether the assignment context is a
compound assignment or not.
Change-Id: I26a41544e10ef9c9ba042c1d7862563bd9d18b68
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/121407
Reviewed-by: Mike Fairhurst <mfairhurst@google.com>
A few changes here:
- Prefix expressions didn't support dynamic invocations.
- Prefix expressions didn't support generic types.
- Postfix expressions were handled incorrectly (we used the return
type of operator+ for `x++`, whereas the type should have been the
same as the type of `x`).
Change-Id: I35077b82a6e9c4e4f6ad8bb1264f5d725ec0d9a9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/121401
Reviewed-by: Mike Fairhurst <mfairhurst@google.com>