The interpretation of the subtype check result depends on the mode. In partial
NNBD mode all type errors that wouldn't be errors in non-NNBD programs should
become warnings. In full NNBD mode all such errors are errors. This CL adds
the mode explicitly to the interface of the subtype check as a parameter.
Bug: http://dartbug.com/38673
Change-Id: I14bcdd260618530cfdd8189c01abba7469a16679
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/119545
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Dmitry Stefantsov <dmitryas@google.com>
* Ensure that we have a .dill file and it has the correct version before
we start decoding it in dump.dart.
* Throw errors, not strings. Ensure that they have a useful
toString().
* Do not print usage except when the command is invoked
incorrectly (wrong number of arguments). Once we get into the
command it's less likely that it's been invoked incorrectly and more
likely that something else has gone wrong.
Because these utilities are invoked from other scripts (like the
fasta command), printing their usage for problems other than
invoking them correctly doesn't match the way that they were invoked
and it's confusing.
Change-Id: I7832383594d2b3719a0a7a7392ba4685717a79d2
Reviewed-on: https://dart-review.googlesource.com/c/78206
Commit-Queue: Kevin Millikin <kmillikin@google.com>
Reviewed-by: Jens Johansen <jensj@google.com>
This method is no longer needed, since the front end iterates through
members directly to find cross overrides.
Change-Id: Ibc5180962a097c4d6194dbf4cbd1a0dea15050c2
Reviewed-on: https://dart-review.googlesource.com/13582
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
This CL adds the ability to create a list of "forwarding nodes" for a
source class. A forwarding node is a data structure that will later
be resolved to either an explicitly declared member in the class or a
superclass, or to a forwarding stub. The idea is that we will create
the forwarding nodes at the time of outline building, and later,
during type inference, we will resolve each forwarding node as it is
encountered.
The reason we need to defer resolution of the forwarding nodes until
inference is because we may need to use the results of type inference
to determine which member a given forwarding node resolves to. For
example:
num f() => 1;
class A {
final x = 1; // Inferred type: int
}
class B {
final x = f(); // Inferred type: num
}
abstract class C implements A, B {}
We cannot determine at the time of building the outline for C whether
it inherits its x from A or B, because we need the results of type
inference to determine which of the two x's has a more specific type.
Note that some refactoring of ClassHierarchy was necessary in order to
allow the front end to maintain member lists in the same order used
internally by ClassHierarchy. This will let us avoid unnecessary
redundant sorting of methods.
Change-Id: Iee754957e0ad3b16c4b60608e17a4a7b0006dfb4
Reviewed-on: https://dart-review.googlesource.com/7851
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
This will allow tests that use batch_util.dart to be run inside
google3, where package layout conventions are more strictly enforced
(files in test/ cannot import files in bin/ or vice versa).
Change-Id: I046b864bc3b1c4e78b984b0047b7567873146c52
Reviewed-on: https://dart-review.googlesource.com/7340
Reviewed-by: Samir Jindel <sjindel@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
This reverts commit e81deebfd8.
My reasoning in the above commit was wrong. Consider the following code:
class A {
void foo() {}
}
abstract class B extends A {
void foo([x]);
}
class C extends B {}
main() {
B b = new C();
b.foo(42); // BAD: A.foo can't accept arguments.
}
To ensure soundness, this code needs to be disallowed, and the current
mechanism for doing that is to use forEachOverridePair. Note that
forEachOverridePair is a bit of a misnomer; in addition to yielding
all pairs of methods (M1, M2) for which M1 overrides M2, it also
yields pairs of methods (M1, M2) for which the target class inherits
the concrete implementation M1, and M2 is part of the interface.
Technically this latter case is not an "override" but rather an
"implementation" (thanks to Lasse for pointing out this distinction).
However in both cases we need to do the same compile-time check to
ensure soundness: we need to check that the type of M1 is a subtype of
M2 (unless the check is suppressed by a "covariant" keyword). Hence
it makes sense for forEachOverridePair to cover both cases.
To ensure that the above example is properly rejected, it is crucial
that some invocation of forEachOverridePair yield the pair (A.foo,
B.foo). Prior to e81deebfd8,
forEachOverridePair(B) would not yield this pair, but
forEachOverridePair(C) would. After
e81deebfd8, both calls yield this pair.
When I made e81deebfd8, I failed to
notice that forEachOverridePair(C) would yield the pair, so I thought
there was a problem. So my "fix" was unnecessary. And it created a
fresh problem: it meant that the following code would be disallowed:
class A {
void foo() {}
}
abstract class B extends A {
void foo([x]);
}
class C extends B {
void foo([x]) {}
}
main() {
B b = new C();
b.foo(42); // OK: C.foo can accept an argument.
}
There is no a priori soundness reason for rejecting this code, and
according to Lasse, it has not yet been decided whether Dart 2.0 will
allow it.
This CL restores the old behavior. Rather than remove the test case
in e81deebfd8, it modifies it to
demonstrate why the old behavior was correct.
R=scheglov@google.com
Review-Url: https://codereview.chromium.org/3004023002 .
ClassHierarchy.forEachOverridePair contains special logic for unusual
cases like this one:
class A {
void foo() {}
}
class B extends A {
void foo();
}
main() {
B b = new B();
b.foo();
}
In this case, A.foo is considered to override B.foo (contrary to the
usual situation where the derived class method overrides the
superclass method). The reasoning is that calling foo on a concrete
instance of B will cause A.foo to be executed (as illustrated in
main); therefore A.foo is callable via the interface of B.foo, thus in
a sense A.foo "overrides" B.foo.
The code contained a questionable optimization, however; it only
executed this special logic if the derived class was concrete.
Presuambly the reasoning was that if B were abstract, then a concrete
instance of B could never be created, so this situation could never
arise.
However, there is nothing to stop a concrete class from being derived
from B, e.g.:
class A {
void foo() {}
}
abstract class B extends A {
void foo();
}
class C extends B {}
main() {
B b = new C();
b.foo();
}
Now, calling foo on a concrete instance of C will cause A.foo to be
executed (as illustrated in main); therefore A.foo is callable via the
interface of B.foo, as before. So we still need to report this as an
override pair even though B is abstract.
R=ahe@google.com, scheglov@google.com
Review-Url: https://codereview.chromium.org/2998383002 .
The front end will need to use this method to iterate through the
interface of a class in order to determine when to create forwarding
stubs.
The functionality already exists; this CL merely exposes it and adds
tests.
R=scheglov@google.com
Review-Url: https://codereview.chromium.org/3003913002 .
Normally getters and setters are considered distinct and unrelated by
the type inference algorithm. However, if a getter has no declared
type and doesn't override anything, then we fall back on inferring its
type from an inherited setter, and vice versa.
R=sigmund@google.com
Review-Url: https://codereview.chromium.org/2946733003 .