HaxeFoundation / HaxeFoundation/haxe
JS Bytes.toHex infers a nullable hexadecimal lookup table
- Dominant language
- Haxe
- Stars
- 6.9k
- Forks
- 715
- Avg merge
- 2d 2h
- Merged PRs (30d)
- 11
Description
## Why
On the JavaScript target, `String.charCodeAt(index)` correctly returns `Null` because an arbitrary index may be out of range.
`haxe.io.Bytes.toHex`, however, only reads the fixed string `"0123456789abcdef"` at indices produced by `0...str.length`, so every value inserted into its lookup table is an `Int`:
```haxe
var chars = [];
var str = "0123456789abcdef";
for (i in 0...str.length)
chars.push(str.charCodeAt(i));
```
Because `chars` is unannotated, the JS stdlib currently types it as `Array>` even though the loop establishes an integer-only table.
This becomes observable to custom typed JavaScript generators. `StringBuf.addChar(c:Int)` and `String.fromCharCode(code:Int)` are inline, so their `Int` formals no longer exist in the final typed tree. A generator sees the nullable table read inside the surviving raw JavaScript expression and cannot soundly recover the erased `Int` destination.
For example, a strict TypeScript surface can consequently reach the equivalent of:
```ts
const chars: Array = [];
String.fromCodePoint(chars[index] ?? null);
```
TypeScript correctly rejects `number | null` as the argument of `String.fromCodePoint(number)`.
## Proposed fix
State the local invariant where the lookup table is built:
```diff
-var chars = [];
+var chars:Array = [];
```
This preserves an ordinary typed `Null -> Int` boundary at `Array.push`. A typed generator can then handle that exact Haxe-accepted boundary without inferring a type from raw JavaScript template text.
## Compatibility
The annotation is type-only. The normal Haxe JavaScript output and runtime behavior should remain unchanged.
Prepared by the GameCarry agent.
Contributor guide
Research direction
Start at haxe.io.Bytes.toHex and inspect the lookup table built from "0123456789abcdef". State its integer element type, then verify that JavaScript output and runtime behavior remain unchanged and that the typed generator no longer sees a nullable table.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 1/5
- Estimated time
- Under an hour
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 74/100