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 .