haxe icon indicating copy to clipboard operation
haxe copied to clipboard

Inconsistent behavior with abstract array inline functions

Open rifxii opened this issue 4 months ago • 1 comments

After trying to figure out why HaxeFlixel's MatrixVector.set function did not behave correctly when targeting Hashlink, I found out inlined functions caused the compiler to not create unique references for variables used from the abstract. I've created a code sample where this is viewable: https://try.haxe.org/#3852320A. Instead of the sample performing this[0] = y; this[1] = x; it would behave as this[0] = this[1]; this[1] = this[0];. The traced value should return as [0, 10] but instead returns as [0, 0], you can see this work correctly when switching the target to Javascript or Eval.

I originally wrote this off as an odd issue with Hashlink and was planning to write an issue on their repo until I messed around with the test more and found out that this behavior is also reproducible on non-hashlink targets when the inline function's default parameter values are omitted, leading me to believe that this might stem from Haxe instead.

Sample with omitted default parameter values: https://try.haxe.org/#b7e8Eb21. No targets return [0, 10].

The compiler can be forced to create an unique reference when the variable is used inside of the inlined function, for example adding a trace in the function like trace(x, y); would fix it.

rifxii avatar Jul 29 '25 02:07 rifxii

Here's a slightly more minimal sample to reproduce the issue:

function main() {
	var arr = [10,0];
 
	trace('Before flipping: ' + arr);

	// Flips values at 0 and 1
	set(arr, arr[1], arr[0]);
  
	trace('After flipping: ' + arr);
}

inline function set(arr:Array<Int>, x:Int, y:Int) {
	arr[0] = x;
	arr[1] = y;
}

https://try.haxe.org/#8fF5e36F

If the assignments are made to object fields instead of an array, then haxe is capable of generating a temporary variable correctly:

let y = obj.x;
obj.x = obj.y;
obj.y = y;
Object version source code
function main() {
	var obj = {x:10, y:0};
	trace('Before flipping: ' + obj);

	// Flips values at 0 and 1
	set(obj, obj.y, obj.x);
  
	trace('After flipping: ' + obj);
}

inline function set(obj:{x:Int, y:Int}, x:Int, y:Int) {
	obj.x = x;
	obj.y = y;
}

tobil4sk avatar Sep 26 '25 10:09 tobil4sk