-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Support @virtual
annotation on fields in DDC
#27385
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Also we need to support |
given an example like: import 'package:meta/meta.dart';
abstract class A {
@virtual
final Object x = 0;
A() { print(x); }
}
class B extends A {
Object get gee => super.x;
}
class C extends B {
final Object x = 42;
}
main() {
var c = new C();
print(c.x);
print(c.gee);
print("foo");
} it would be great to generate something like: bin__t.A_getter_x = class A_getter_x extends bin__t.A {
new() {
var setterProp = { configurable: true, set: function(x) {
this[super_A_x] = x;
delete this.x;
} };
Object.defineProperty(this, "x", setterProp);
super.new();
}
get x() {
return this[super_A_x];
}
set x(value) {
this[super_A_x] = value;
}
}
const super_A_x = Symbol(bin__t.A.name + "." + 'super_x'.toString());
bin__t.B = class B extends bin__t.A_getter_x {
thanks to @floitschG for writing that up! |
Note, above does not work if a mixin introduces a field override. Not in the way DDC currently expands mixins, at least: we currently merge all of the mixins together. But mixins could define the same field, effectively overriding between the mixins or in relation to the extended class. We might have to expand each level of mixins. Another possible problem is anything that changes how the hierarchy looks has the potential of messing up mirrors. I don't think we rely on that, but it's a potential risk. |
It turns out we already have some bugs related to how mixins are handled -- the existing support for a field that overrides a getter/setter also doesn't work correctly: #28059 ... so for now I will ignore mixins or possibly try to fix that bug before this one. |
hit another snag, in this test: https://github.com/dart-lang/sdk/blob/master/tests/language_strong/super_field_2_test.dart#L17, because there's the If we allow the field to be overridden, we need to treat That seems like a bridge too far, so I've backed out of that approach. Will link my updated CL. |
https://codereview.chromium.org/2571363002/ -- note this patch relies on |
I'm not sure I understand your concerns wrt Why is it a problem to search for |
it's probably an extra tree walk over every class compile time as things are currently set up. But the bigger problem is we can't do it in a cross module way. If I have a class hierarchy C extends B extends A, where B uses super.x and C overrides x from A. B would induce a field slot for A.x, but C has no way of knowing the contents of B's method bodies (if C and B are not in the same module), so it doesn't know that B did that, and will try again to induce A.x. We could try and solve that somehow; this has not and has never been technically unsolvable in a pure Dart universe, it's just getting way beyond what a simple/straightforward compiler to JS can do and putting interop/future potential growth scenarios at risk. It's no longer field overrides that change the location of the JS property, but something that in principle should be unrelated (super). So we don't have a reliable correspondence anymore between Dart class structure and JS class structure. I'm frequently put in a difficult position between folks that want DDC to generate JS that just executes, appearance be darned, and users that want our compiler to produce straightforward output. @vsmenon and @leafpetersen and I go back and forth on this one a lot. It would be so much easier to discard output quality as a goal, but my understanding is we have not done so, because we would like to keep longer term growth opportunities open. |
If a field is marked @virtual in Analyzer, DDC will allow it to be overridden as well also fixes #28114, abstract getters/setters broke generation of forwarding getters/setters [email protected] Review-Url: https://codereview.chromium.org/2571363002 .
Sorry for the late reply. (The comment was drowned in my github notifications). Clearly, we don't want subclasses to inspect superclasses. That would be too expensive (and unnecessary). From what I can tell, the problem is, when we have a Example: class A {
int x;
A(this.x)
}
class B extends A {
B(x) : super(x);
foo() => super.x;
}
class C extends B {
C() : super(42);
get x => 499;
} The important thing here is that
Here are two proposals that should be able to deal with this configuration without needing
if (Object.prototype.hasOwnProperty.call(this, super_a_x)) {
return this[super_a_x);
} where
// The class A is unchanged.
class A extends core.Object {
new(x) {
this.x = x;
}
};
// The intermediate class for B virtualizes `x`:
class A_getter_x extends A {
new() {
var prop = Object.getOwnPropertyDescriptor(this, 'x');
// If the class has already a property for `x`, then a subclass tries to
// virtualize as well. No need to intercept the initializer call.
if (!prop) {
var setterProp = { configurable: true, set: function(x) {
this[super_A_x] = x;
delete this.x;
} };
Object.defineProperty(this, "x", setterProp);
}
super.new(...arguments);
}
get x() {
return this[super_A_x];
}
set x(value) {
this[super_A_x] = value;
}
}
class B extends A_getter_x {
new(x) {
super.new(core.int._check(x));
}
foo() {
return super.x; // Safe, because we inserted the virtualization class.
}
};
// C doesn't know that B already virtualized, and inserts another virtualizer class.
class B_getter_x extends B {
new() {
// The prop check isn't necessary, but makes the boilerplate less diverse.
var prop = Object.getOwnPropertyDescriptor(this, 'x');
if (!prop) {
var setterProp = { configurable: true, set: function(x) {
this[super_A_x] = x;
delete this.x;
} };
Object.defineProperty(this, "x", setterProp);
}
super.new(...arguments);
}
// It's safe to do duplicate the getter and setter.
get x() {
return this[super_A_x];
}
set x(value) {
this[super_A_x] = value;
}
}
class C extends B_getter_x {
new() {
super.new(42);
}
get x() {
return 499;
}
}; |
This is marked as closed, but there's still discussion about the implementation of this in DDC? File another issue to track implementation quality? |
I think you're looking for #28119 |
@floitschG - It would be super useful for me (and I suspect others on this list), if you could put together a high level overview of what your proposal is along with some examples of how it handles the various cases (e.g. field -> field overrides, field -> setter/getter overrides, setter/getter -> field overrides, overriding one (but not both) of the capabilities, mixins, super calls, etc). I haven't had any time at all to spend on this in the past couple of months, but I spent a bit of time looking over this bug yesterday. I had a hard time extracting out from the one or two examples what the general approach was, and how all of the different cases fit in. After some thought, I think I would roughly characterize it as follows:
That's my sketch of what I think your proposal is, but I think we could all be more confident in evaluating the robustness, complexity, and implementation costs of the approach if we saw a more complete development. |
@jmesserly @leafpetersen: I tried implementing Florian's idea here with a bit of guidance from the inventor himself. It passes the problematic tests identified by Jen and a few more. |
these are being added to strong mode in #27384
The text was updated successfully, but these errors were encountered: