haxe
haxe copied to clipboard
[hl] Cannot extend @:structInit class with constructor in subclass
On HL, I am not able to extend a @:structInit
class if the subclass has a constructor, receiving Invalid_argument("List.map2")
. See below example, which works in try.haxe.org on JS but not HL.
package;
class Main {
static public function main():Void {
// Invalid_argument("List.map2")
var b:B = new B();
trace(b.a);
}
}
@:structInit
class A {
public var a:Int;
}
class B extends A {
public function new() {
a = 1;
}
}
Occurs at least on Haxe 4.0.5 through 4.2.5 and 6bcae15, with HL 1.11
I suspect that this is some general problem in the typer because the HL generator doesn't care about @:structInit
at all.
Yeah this generates a super()
call without arguments, even though the parent constructor has one argument. Fails on some other targets too.
Actually, I think this just has to fail with Missing super constructor call
because we wouldn't know what argument to pass in.
Yeah an error with "super" in it points me in a good direction. It's a bit confusing mixing supers with structInit, but ¯\_(ツ)_/¯
class Main {
static public function main():Void {
var b:B = { };
trace(b.a); // 1
}
}
@:structInit
class A {
public var a:Int;
public function new(i:Int) a = i;
}
@:structInit
class B extends A {
public function new() {
super(1);
}
}
Yeah our @:structInit
handling is a bit shit... We also have problems in the other direction:
class Main {
static public function main():Void {
var a:A = {a: 0};
trace(a);
}
}
class A0 {
public function new(x:String) {}
}
@:structInit
class A extends A0 {
public var a:Int;
}
This can't possibly work because we cannot generate a super()
call to A0
.
The only situation in which we can generate a super(args)
call is if we generate the entire constructor, because only then do we have an argument mapping. I'll look into cleaning this up.
You don't even need to have a constructor in the chain to trigger this; just mixing structInit classes with unmarked ones can break it. In this example, we get the error because the middle class B
is not @:structInit
, even thought it has no explicit constructor.
@:structInit class A {
public var foo: Int = 1;
}
class B extends A {}
@:structInit class C extends B {}
class Test {
static function main() {
var test: C = {};
trace(test.foo);
}
}