Since https://dart-review.googlesource.com/c/sdk/+/133422 has
introduced the possibility that a node previously marked as
non-nullable would later be marked as nullable, we need to make sure
that doesn't happen for types that have been explicitly marked as
non-nullable using a "/*!*/" hint, or types that are non-nullable in
an already-migrated library.
This required refactoring the state of nullability nodes slightly.
Nodes can now be in six states:
1. Non-nullable (previously called "undetermined")
2. Non-nullable, with non-nullable intent (previously called
"nonNullable")
3. Nullable
4. Nullable, with non-nullable intent (previously indistinguishable
from 3)
5. Exact nullable
6. Exact nullable, with non-nullable intent (previously
indistinguishable from 5)
To allow all these states to be distinguished, we separate the state
into two orthogonal parts: a "nullability" part and a "non-null
intent" part.
Change-Id: I588a2e63eaa76e3992fdfbaaa2e8b212cc1f60d1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/133440
Reviewed-by: Mike Fairhurst <mfairhurst@google.com>
It didn't wind up being used, and its presence limits our ability to
modify the graph propagation algorithm (which I plan to do in a
follow-up CL).
Change-Id: I48a9b879f25295075e8d95eb3fb0185839303957
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/133425
Reviewed-by: Mike Fairhurst <mfairhurst@google.com>
Shifted some minor things around in the design as well -- particularly
the symlink is moved to being owned by the workspace as not all
workspace implementation will create symlinks in the original directory.
I've also dropped most of the public interface to FantasyWorkspace.
Will add that back in when I'm more sure what it will be.
Change-Id: I19d1b1c8ad4063868ff7c10869c4561d4db64bf2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/133435
Commit-Queue: Janice Collins <jcollins@google.com>
Reviewed-by: Paul Berry <paulberry@google.com>
This prevents a non-null assertion in a callback function from marking
the parameter type as non-nullable, if that would make the callback
function fail to meet the requirements of its use site. For example,
when migrating:
f(List<int/*?*/> myList) => myList.map((int x) => x + 1);
We previously would produce:
f(List<int?> myList) => myList.map((int x) => x + 1);
(Which would fail immediately due to the callback `(int x) => x + 1`
not accepting `int?`). We now produce:
f(List<int?> myList) => myList.map((int? x) => x! + 1);
(Which only fails if there is actually a null value in the list,
matching the behavior of the code prior to migration).
Addresses another manifestation of
https://github.com/dart-lang/sdk/issues/38699.
Change-Id: Iffe9fbdace00ff1edea0f6d125c86b06fad7bbcb
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/133423
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Mike Fairhurst <mfairhurst@google.com>
Previously, graph propagation occurred in three steps:
1. Mark any nodes connected to `always` by union edges as nullable.
2. Mark any nodes connected to `never` by hard or union edges as
non-nullable, but do not change any nodes marked by #1.
3. Mark any nodes connected to `always` as nullable, but do not change
any nodes marked by #1 or #2 (with additional processing for
substitution nodes).
This approach had the advantage that once a node is marked as nullable
or non-nullable, it is never changed, which made reasoning about the
algorithm a bit easier. But in an upcoming CL I'll need to modify the
algorithm in a way that's incompatible with this approach.
This CL introduces the notion that some edges are "checkable" and some
aren't (an edge is "checkable" if it's ok for graph propagation to
leave it unsatisfied, because the fix builder can insert a null
check). At the moment all edges are considered checkable except for
union edges, but that will change in future CLs in order to address
https://github.com/dart-lang/sdk/issues/38699.
The algorithm is now:
1. Mark any nodes connected to `never` by hard or union edges as
non-nullable.
2. Mark any nodes connected to `always` as nullable, but only change
nodes marked by #1 if necessary to satisfy uncheckable edges (with
additional processing for substitution nodes).
An alternative way of thinking of this algorithm is that hard edges
reflect user intentions that we should try to satisfy if we can, but
which shouldn't take priority over creating output that is free of
static errors. During phase 1, we propagate hard edges to find all
the nodes the user *intends* to make non-nullable. During phase 2, we
propagate nullability, respecting user intention where we can, and
overriding it where we can't.
Change-Id: Ie3f9d9ee66f407f9d4916f7259e7f50a82ebb2bb
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/133402
Reviewed-by: Mike Fairhurst <mfairhurst@google.com>
This serves two purposes:
1. It makes it easier to be confident that we're resetting the
necessary state when re-running graph computation in
`NullabilityGraph.update`.
2. I'm planning some changes to the graph propagation algorithm (in an
upcoming CL). Having the propagation state separate from the rest
of the graph state will make it easier to reason about these
changes.
Change-Id: I5e101bbce6e5ad382dd754bfbb9b72e20df23fd1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/133337
Reviewed-by: Mike Fairhurst <mfairhurst@google.com>
The visitSimpleIdentifier method was failing to return a DecoratedType
for the case where the identifier was `void`.
In practice this didn't matter, since the only time the type returned
from visitSimpleIdentifier is used is when the the identifier is used
as an expression, and `void` can't be used an expression (i.e. `var
voidType = void;` is illegal).
Nonetheless, it's nice to silence the warning, and it seems like it
increases safety to return a value from visitSimpleIdentifier in all
cases.
Change-Id: I239b98b9e5932195e6884738728d26d86c6ab519
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/133336
Reviewed-by: Mike Fairhurst <mfairhurst@google.com>
Moved AnnotationTracker to CompletenessTracker which defers work to
AnnotationTracker and new class TypeNameTracker.
This passes on flutter and p1/g1 packages.
Change-Id: I5c92ed287d4d35b2b2f0d21846db197e24584dc5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/133227
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Mike Fairhurst <mfairhurst@google.com>
When migrating, we'll need to change some null-aware property accesses
and method calls to non-null-aware (due to the fact that the receiver
is non-nullable, or due to the new `?.` shortcut rules), so when
migration re-resolves, it will need to be able to override
resolution's determination of whether a given property access or
method call is null-aware.
Change-Id: I411f43fb937431e757d4dd9b968874db84158e47
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/133240
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
The new FixBuilder infrastructure has the ability to remove dead code
either by commenting it out or by deleting it entirely. Previous to
FixBuilder all we could do is comment it out. My intention when
landing FixBuilder was to keep this behavior so that we could make a
deliberate switch at a later time (when everything was well tested).
But I accidentally set the flag wrong for some code paths, and so
currently we delete code.
This has caused some bugs in the preview tool (which I will file in
the issue tracker shortly). In order to avoid causing problems for
members of the language team who intend to try out the tool this week,
I'm switching back to "comment code out" as a temporary measure.
Change-Id: I0ca8674b6a8d9ab23cf6726a15fa3dc1919085b4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/133081
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
Fixes https://github.com/dart-lang/sdk/issues/40181
As long as its possible to union a bound to a node involved in a
substitution, its possible to make a bound "exact nullable." This
implies that all instantiations of that type must be with a nullable
version of that parameter, which is not desirable for any program.
This marks new failing tests due to
https://github.com/dart-lang/sdk/issues/39404. However, re-running this
on package:collection resulted in a better migration result (no issues
from the non-nullable inferred types being made explicit or not). So my
personal feeling is this is worth landing now, however, we could land it
later.
Change-Id: I63479c5e4edecf301c27e21b5ba57508d625e8ab
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/132748
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Mike Fairhurst <mfairhurst@google.com>
When migrating an unnecessary "if" test like this one:
if (x != null) {
Do something;
} else {
Do something else;
}
We make two modifications to the user's file:
- Drop "if (x != null) {"
- Drop "} else { Do something else; }"
With this change, the first modification has a description of
NullabilityFixDescription.discardCondition and the second has a
description of NullabilityFixDescription.discardElse. Previously,
both modifications had a description of
NullabilityFixDescription.discardElse, which was confusing.
Change-Id: I6407d7616b7a2d2c8af853ab48c3480959c4fdb9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/132682
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
Addresses a concern from code review
https://dart-review.googlesource.com/c/sdk/+/129302 that
EditPlanner.surround is difficult to use correctly, by adding wrapper
methods for several common use cases that are easier to use correctly.
Also adapts fix_aggregator.dart to make use of the new methods.
EditPlanner.surround remains in the public API for EditPlanner because
there are still use cases for it that aren't supported by the wrapper
methods. My hope is that the remaining use cases are either rare
enough or trivial enough that we don't need wrappers for them; if that
proves to be incorrect we can always add more wrapper methods.
Change-Id: Ia1d6cc8b10ffaedcf8803ff7c8f9460ada1d7c4e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/132462
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Now there are only two circumstances in which an AtomicEdit won't have
information about the reason for the change:
- The AtomicEdit object was associated with adding or removing parens,
in which case we don't compute information about the reason for the
change because it's not straightforward to compute, and it should be
clear to the user anyway.
- Information about the reason for the change hasn't been plumbed
through properly (this should be addressed in follow-up CLs).
Since we are rapidly approaching a situation where nearly all
AtomicEdits will have reason information, the separation between
AtomicEdit and AtomicEditWithInfo now seems silly, so I just moved the
`info` object into AtomicEdit and removed AtomicEditWithInfo entirely.
Change-Id: I61afd9cd58b71d4695685e65d0142a2693b8e6b2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/132451
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>