This repository was archived by the owner on Feb 22, 2018. It is now read-only.
This repository was archived by the owner on Feb 22, 2018. It is now read-only.
Generate code for recursive generic definitions #253
Closed
Description
We currently break on code of the following form:
class ElementInjector extends TreeNode<ElementInjector> {
...
}
we generate:
class ElementInjector extends TreeNode$(ElementInjector) {
which generates reference error on ElementInjector
.
(edit by @jmesserly) a lot of discussion below is obsolete, see my recent comment for proposed solution.
Activity
jmesserly commentedon Jul 10, 2015
yeah we don't support recursively bounded quantification. do we want to?
EDIT: see this comment for a solution that will work.
If yes, we likely need to change how library cycles are compiled, to deal with pathological cases like:(edit: removed obsolete code example)without library cycles, it's not too bad. The safest way to handle this is probably, instead of:
generate:
mergeClass copies instance and static methods, as well as fixing what A extends.
We might be able to just fix up "extends", but I think
super
bindings might only work if we do it as shown above. Not 100% sure though.None of this works for lib cycles+incremental compile thojmesserly commentedon Aug 7, 2015
One thing to note: we could take a different approach, and change how reified generics work. We could do a type tagging approach for generic type instances, where each instance points at its runtime type, and from there can get to various generic args. But that brings in a bunch of issues (by un-solving some of the problems the current approach solves).
jmesserly commentedon Aug 27, 2015
I think we can fix this by extending the lazy-load mechanism that we already use to deal with library cycles. Two parts to this:
vsmenon commentedon Nov 9, 2015
@jmesserly
I think I may have asked you this before, and it didn't work out, but I don't recall why. Could we change the prototype after the fact along these lines?:
Change this:
to:
jmesserly commentedon Nov 9, 2015
I think the problem is with
super
being very early bound in JS. So:But yeah, if we could mutate the prototype, and it would affect
super
, then it would work.We could perhaps avoid
super
in these cases, but trying to detect when to avoidsuper
and make the dispatch work at runtime is a bit tricky, IIRC. But that's an option.I guess I was leaning towards something like:
basically, we have methods that are immutable (at least, w.r.t. super), but we have a class that's mutable, so we initialize the methods in a way that makes them happy, then copy them over to the class.
leafpetersen commentedon Nov 9, 2015
Forward declaration seems promising. Does it work when both are generic?
vsmenon commentedon Nov 10, 2015
Ahh, right -
super
- you told me that before....jmesserly commentedon Nov 10, 2015
For that example, yes:
The harder case is more along the lines of:
To support those, we'd have to let dart.generic handle the forward initialization & merging process itself. Which it should be able to do. (We might get some side benefits from that, like it's easier to compute signatures inside, since referring to B$(T) becomes generally safe. We had considered it before IIRC).
jmesserly commentedon Nov 10, 2015
Restating this more fundamentally -- it's hard to implement letrec without mutation :)
We currently have a cycle.
I'm picking on the class -> class method link as it's easy to mutate. However we could consider a design change that makes either the the class methods -> superclass linkage mutable, or a design change that makes methods -> generic type argument mutable.
To break method -> super method link, we'd have to avoid ES6
super
. Not my first choice, but it's an option.To break the method -> generic type arg link, we'd have to make T be mutable somehow. For example
Now we can provide a way to mutate T later. Just not sure if we want to change all generic types. (we don't know which ones someone will create a cycle with until later.) But maybe it's nice looking enough.
jmesserly commentedon Nov 10, 2015
BTW, to complete that example, it would be like:
edit x3: make it more obvious what's going on.
jmesserly commentedon Nov 10, 2015
also: if dart.generic's function argument takes a "types" array I'm not sure how it would know the type parameter name ("T" in this case). I guess it can figure it out after it makes a type:
34 remaining items