haxe icon indicating copy to clipboard operation
haxe copied to clipboard

[jvm] Bad type on operand stack when spreading an array for Rest<T> generic arg

Open PXshadow opened this issue 1 year ago • 3 comments

function main():Void {
    t(...[10]);
}

function t<T>(x:haxe.Rest<T>) {}

openjdk 21.0.2 Haxe nightly 5.0.0-alpha.1+0620b1b

PXshadow avatar Jan 02 '25 14:01 PXshadow

I don't think an open Rest<T> can work on this target. Rest arguments are based on native arrays, which are invariant. There is no type in the run-time that would accept both int[] and java.lang.Object[], so declaring one in Haxe is always going to cause problems.

You can produce a similar error with Vector directly:

import haxe.ds.Vector;

function main():Void {
	var a = Vector.fromArrayCopy([10]);
	t(a); // Exception in thread "main" java.lang.ClassCastException: class [I cannot be cast to class [Ljava.lang.Object; ([I and [Ljava.lang.Object; are in module java.base of loader 'bootstrap')
}

function t<T>(x:Vector<T>) {
	trace(x);
}

The problem with catching this during typing is that the compiler doesn't have a mechanism to disallow something like a generic Vector<T>, and I'm not sure how that would best be expressed either.

This can be worked around by making t inline, because then we can work with the concrete type at the call-site.

Simn avatar Jan 03 '25 08:01 Simn

Ran into this again today, thanks for the tip about inlining.

PXshadow avatar Nov 05 '25 02:11 PXshadow

Any suggestion for how to overcome the generic arg not allowing variance in this example?


function main():Void {
    new Test<Int>(0,0,...[]);
}

class Test<T> {
    public function new(length:Int, capacity:Int, args:haxe.Rest<T>) {

    }
}

If I set Test to inline it makes it no longer possible to define Test without Rest args:

new Test<Int>(0,0);

Hitting the compiler error, is this also intentional?:

(length : Int, capacity : Int, args : haxe.Rest<Int>) -> Void should be (Int, Int) -> Void

PXshadow avatar Nov 05 '25 02:11 PXshadow