Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions BACKLOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,62 @@ The container these bounds were added for now compiles and runs against the stan
Jass, and compiles on Lua (#1239). What is left is generality around it rather than the feature
itself, and one gap in what the suite can see.

27. **A natively keyed store on Lua, selected by a type class.** Decided with the repo owner:
**the native path is taken only where the key's equality is identity**, and a type class says
which keys those are. Everything else keeps today's probing on both targets.

Why it is worth doing. `FastHashMap` does its own hashing and linear probing on both targets, but
a Lua table already is a hash map: `t[key] = value` would let Lua hash, and would lift the fixed

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Encode null values before writing to Lua tables

When V is a class or handle type and put(key, null) is called, this lowering becomes t[key] = nil, which deletes the entry in Lua. The probing implementation tracks occupancy separately, so the same call still affects has and size even though get returns null; the native representation therefore needs a sentinel or separate presence table to preserve backend parity.

AGENTS.md reference: AGENTS.md:L217-L221

Useful? React with 👍 / 👎.

`FASTHASHMAP_CAPACITY`/`FASTHASHMAP_MAX_INSTANCES` limits there entirely. It would also get string
keys off `StringHash`, which this library documents as unusable for the purpose - case insensitive
(`String.wurst:81`, so `a` and `A` share a key), collapsing every partial multibyte slice to one
constant (`MultibyteDiagnostics`), undocumented and changed between game versions, and **not
emulated by the interpreter**, so `FastHashMapTests.testStringKeys` passing says nothing about the

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove the stale claim that the interpreter lacks StringHash

At this commit, StringProvider.StringHash delegates to the byte-oriented Wc3StringHash, and Wc3StringHashTest verifies whole strings, partial multibyte bytes, and parity with the Lua runtime shim. Thus the assertion that the native is not emulated—and that interpreter string-key tests say nothing about it—is false and would misdirect the next implementation attempt; update the rationale to describe the remaining limitation instead.

Useful? React with 👍 / 👎.

game. Other containers - a set, a memo cache, adjacency maps - then build on the one store.

Why the type class is load bearing rather than incidental. A Lua table matches keys by raw
identity, which for a class is reference identity. An instance whose `equals` is structural -
`Hashable<vec2>` comparing components - would therefore have Jass treat two equal-valued keys as
one key and Lua treat them as two, silently, from one program. So the native path is sound only
for `int`, `real`, `string`, `boolean` and reference-keyed classes. A second bound states that:
Comment on lines +38 to +39

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Account for null before admitting reference-keyed classes

For any RawKeyed<MyClass> map, null remains a valid value of MyClass, but Lua lowers it to nil, and t[nil] = value raises a runtime error while the probing implementation can accept it when Hashable does. Consequently reference identity alone is not enough to make this key family backend-compatible; encode/guard the null key or explicitly reject it with matching behavior and regression coverage.

AGENTS.md reference: AGENTS.md:L217-L221

Useful? React with 👍 / 👎.


public interface RawKeyed<T:> // no requirements; a promise that equality is identity

class FastHashMap<K: Hashable> // probing on both targets, any key
class FastHashMap<K: Hashable and RawKeyed> // t[k] on Lua

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Define a compilable selection mechanism for the two map variants

Wurst does not overload type definitions based on generic bounds, so declaring both of these FastHashMap classes in one package makes every reference to that type ambiguous before K or its instances are considered. If the second line is instead meant to replace the first, Hashable-only keys lose the promised probing fallback. The design needs one public class with an explicit specialization mechanism, or distinct type names, before the type class can select a representation.

Useful? React with 👍 / 👎.


which is what the `and` bound is for, and what makes the choice of representation a property of
the key type rather than of the container.

Groundwork already established, so the next attempt does not have to find it again:

- Intrinsics are declared in Wurst with `@compilerintrinsic` in `wurst/_wurst/MagicFunctions.wurst`
and bounds parse there; `wurstNewInstance<T:>() returns T` is the shape to copy. Recognition is
by name plus `!AttrFuncDef.hasApplicableUserFunction(call)` in `CompilerIntrinsics`.
- `ImTranslator.isLuaTarget()` is available during Wurst-to-IM lowering, which is what makes this
feasible: the intrinsic can lower differently per target rather than needing dead-branch
elimination to have happened first. An `if isLua` guard alone does not help, because folding
runs after translation and both branches are lowered.
- A Wurst array access already lowers to a plain `t[i]` on Lua
(`lua.translation.ExprTranslation.translateArrayAccessRaw` builds `LuaExprArrayAccess`). Nothing
in the backend needs changing; the only obstacle is that the language requires an `int` index,
and typechecking is target independent, so relaxing it for Lua alone would let a program compile
for one target and fail on the other.
- `ImTranslator.imError(trace, message)` gives a runtime error call, for the Jass lowering of an
intrinsic that has no Jass meaning. `ImStatementExpr` is available for pairing statements with a
value.

Left to settle. The read is straightforward - `wurstKeyedRead(store, key)` lowering to
`store[key]`. The write is the open question: as an `ExprFunctionCall` it must lower to an
Comment on lines +73 to +74

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Define allocation for each map's native table

The read is not yet straightforward for multiple map instances because this note only identifies existing Wurst arrays as Lua tables, while arrays cannot be function parameters (ArrayTests.testArrayParam) or instance fields, and the current map uses shared static arrays partitioned by a fixed base. The design needs to specify how every map instance obtains and passes a distinct backing table; otherwise retaining the static array keeps the instance limit, while indexing the Lua class object itself risks collisions with its fields and metatable-backed methods.

Useful? React with 👍 / 👎.

`ImExpr`, while what it wants to be is an `ImSet` to an array access. Either wrap it in an
`ImStatementExpr` with a discarded value, or expand it at AST level after validation the way
`wurstMapFields` assigns back to fields, which is a different mechanism and may be the cleaner
one. Settle that before writing the surface.

Blocks `WurstStdlib2#468`, deliberately: shipping `FastHashMap` first would commit
`FASTHASHMAP_CAPACITY`, `isFull()` and `Hashable.hash` to the public API when the Lua path makes
all three meaningless on that target.
Comment on lines +106 to +108

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Mark WurstStdlib2#468 as unblocked

This leaves the repository's canonical backlog claiming that item 27 deliberately blocks WurstStdlib2#468, even though FastHashMap now computes its own hash and the dependency is no longer blocked on this work. Anyone selecting work from this ordered backlog will therefore see the wrong dependency status; update this paragraph to record that only Lua performance and capacity limits remain, and remove the preceding implication that avoiding StringHash is still a correctness motive.

Useful? React with 👍 / 👎.


22. **The library's own tests do not run on Lua.** They run on the interpreter now — all 460 of
them, collected by importing every package in the checkout whose name ends in `Tests`. That
half is done; this is the other one.
Expand Down
Loading