Skip to content
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

Floats being treated as Ints in interp mode #10918

Open
roarosa opened this issue Jan 4, 2023 · 5 comments
Open

Floats being treated as Ints in interp mode #10918

roarosa opened this issue Jan 4, 2023 · 5 comments
Milestone

Comments

@roarosa
Copy link

roarosa commented Jan 4, 2023

Code

// Test.hx
class Test {
	static function main() {
		var arr:Array<Float> = [52166, 52013];
		trace(arr[0] * arr[1]);
		trace((arr[0] : Float) * (arr[1] : Float));
	}
}

Command
haxe --main Test --interp

Haxe version: 4.2.5

Expected output

2713310158
2713310158

Actual output

-1581657138
-1581657138

Even when the array values are typed as floats, they still seem to be treated as ints and therefore are running into overflow issues.

@Aurel300
Copy link
Member

Aurel300 commented Jan 4, 2023

Changing the array to contain Float literals ([52166., 52013.]) is a workaround. The value seems to remain a VInt32 even after it is stored in an array, here and in emit_array_declaration. A type annotation (arr[0] : Float) compiles to a TSafeCast, interpreted in emit_safe_cast. This checks whether the types are compatible with is which goes to extra lengths to make integers and floats be "compatible"…

@Simn I assume this was all to avoid the casts, keeping the runtime value typed as integer if possible? FWIW I also have to handle this annoyance a bit in ammer.

@Simn
Copy link
Member

Simn commented Jan 4, 2023

The first question here is if int literals that are typed against Float should become floats right away. I think I once tried that and ran into some problem, but I don't remember exactly.

For the more general case without literals, not quite sure. My usual approach here is to ask "What does Hashlink do?", because if I follow that I can always just blame Nicolas if it turns out to be a bad idea.

@theJenix
Copy link
Contributor

theJenix commented Jan 5, 2023

For what it's worth, as a Haxe application developer, I think I would strongly expect that if a Int literal is stored in a Float typed variable, it behaves like a Float. I don't want to have to manually keep track of value lineage in addition to the types of the variables I'm using, especially if those values are defined at the top of a long code block or outside of the block entirely e.g. if I take the array from the example code and pass that into a function, are those values still 32 bit int typed? I think there's an argument for consistency with other languages as well, where if you assign an int into a float in C++, Java, C#, etc, the compiler takes care of retyping the value and other operations operate according to the type not the literal value itself.

@Simn Simn added this to the Release 4.3 milestone Mar 24, 2023
@tobil4sk
Copy link
Member

What does Hashlink do?

@Simn Hashlink C generates float literals:

r0 = 52166.;
r2 = 52013.;

Though, most other targets seem to have casts.

Neko has the exact same issue #6256. Taking the example from the neko bug report also reveals that PHP and Lua have some minor issues here as well:

var a:Float = 1430000000;
var b:Float = 1430000000.0;

var aa:Float = a * a;
var bb:Float = b * b;

trace('aa: $aa'); // aa: 2044900000000000000
trace('bb: $bb'); // bb: 2.0449E+18

trace('aa == bb: ${aa == bb}'); // aa == bb: false

This old php issue seems to be somewhat relevant as well: #4260.

@Simn Simn modified the milestones: Release 4.3, Later Mar 27, 2023
@Simn
Copy link
Member

Simn commented Mar 27, 2023

Changing this at typer-level gives me these wonderful errors:

src/unit/TestOverloads.hx:30: characters 6-21 : Ambiguous overload, candidates follow
src/unit/TestOverloads.hx:309: characters 27-31 : ... (i : Int, f : Float) -> String
src/unit/TestOverloads.hx:314: characters 27-31 : ... (f : Float, i : Int) -> String
src/unit/TestOverloads.hx:48: characters 6-21 : Ambiguous overload, candidates follow
src/unit/TestOverloads.hx:309: characters 27-31 : ... (i : Int, f : Float) -> String
src/unit/TestOverloads.hx:314: characters 27-31 : ... (f : Float, i : Int) -> String
src/unit/TestOverloads.hx:145: characters 6-24 : Ambiguous overload, candidates follow
src/unit/TestOverloads.hx:238: characters 34-38 : ... (v : Int) -> String
src/unit/TestOverloads.hx:233: characters 34-38 : ... (v : Float) -> String
src/unit/TestOverloads.hx:164: characters 14-29 : Ambiguous overload, candidates follow
src/unit/TestOverloads.hx:495: characters 27-30 : ... (i : Int) -> Void
src/unit/TestOverloads.hx:505: characters 27-30 : ... (f : Float) -> Void
src/unit/TestJava.hx:184: characters 3-25 : Ambiguous overload, candidates follow
src/unit/TestJava.hx:306: characters 38-52 : ... (i : Int) -> Void
native_java/native.jar@haxe/test/MyClass.class@normalOverload:1: character 1 : ... (param1 : Float) -> Void
src/unit/TestJava.hx:198: characters 3-23 : Ambiguous overload, candidates follow
native_java/native.jar@haxe/test/MyClass.class@normalOverload:1: character 1 : ... (param1 : Float) -> Void
native_java/native.jar@haxe/test/MyClass.class@normalOverload:1: character 1 : ... (param1 : Int) -> Void  

I suppose these overloads are now considered equal because there's no longer any cast inbetween. Not sure what to do with this, pushing back to later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants