Skip to content

Commit 931b4db

Browse files
docs(reflaxe): clarify early source overrides
1 parent f35b5cc commit 931b4db

7 files changed

Lines changed: 65 additions & 18 deletions

File tree

.beads/issues.jsonl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@
430430
{"_type":"issue","id":"haxe.elixir-5tm","title":"Fix unused function warnings in TodoLive","description":"UNUSED FUNCTIONS: Three private functions in TodoLive.ex are unused: render_todo_item/2 (line 590), render_tags/1 (line 668), is_optimistically_toggled/2 (line 275). Either: (1) These are dead code - remove from Haxe source, (2) DCE should eliminate them, or (3) They should be called somewhere. Investigate in src_haxe/server/live/TodoLive.hx and fix appropriately.","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-12-03T00:01:15Z","updated_at":"2025-12-08T17:24:29Z","closed_at":"2025-12-08T11:24:29Z","dependency_count":0,"dependent_count":1,"comment_count":0}
431431
{"_type":"issue","id":"haxe.elixir-e0m","title":"Fix app-level unused variables in TodoLive","description":"APP-LEVEL WARNINGS: TodoLive.ex has many unused variables that should be fixed in the Haxe source (src_haxe/server/live/TodoLive.hx): raw_params_completed, raw_params_description, raw_params_due_date, raw_params_priority, raw_params_tags, raw_params_title, raw_params_user_id (in create_todo), broadcast_result, s_optimistic, broadcast, todo_updated, todo_updates (in toggle_todo_status), refreshed_todos, currently_selected (in handle_event). Either use these variables or remove/prefix them in Haxe source.","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-12-03T00:01:08Z","updated_at":"2025-12-08T17:24:29Z","closed_at":"2025-12-08T11:24:29Z","dependency_count":0,"dependent_count":1,"comment_count":0}
432432
{"_type":"issue","id":"haxe.elixir-upq","title":"Fix unused variable warnings - add underscore prefix in compiler","description":"COMPILER ENHANCEMENT: The compiler generates ~50+ unused variable warnings in Elixir. Variables like 'value', 'this1', 'e', 'o', 'c', 't', 'args', 'cl', 'constr', 'index' are declared but never used. Elixir convention requires prefixing unused variables with underscore (_value, _this1, etc). Fix in code generator to detect unused variables and add underscore prefix automatically. This is a systematic fix, not per-variable.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-12-03T00:00:59Z","updated_at":"2025-12-08T17:24:35Z","closed_at":"2025-12-08T11:24:35Z","dependency_count":0,"dependent_count":1,"comment_count":0}
433+
{"_type":"issue","id":"haxe.elixir.codex-uvr","title":"Clarify remaining early haxe.Exception cross override","description":"Audit the lone authored src/haxe/Exception.cross.hx after the Reflaxe _std layout cleanup. Determine whether it can follow the plain .hx early override convention or must remain .cross.hx for macro/tooling safety, then document the result and validate no regressions.","notes":"Resolved as docs-only cleanup. Kept src/haxe/Exception.cross.hx in place because upstream haxe.Exception is extern and only Elixir output needs the concrete Reflaxe.Exception base; documented the selected plain src/haxe/ds/*.hx early override set separately. Validation: npm run guard:docs-links, npm run guard:stdlib-layout, npm run test:quick. Path scan reported only existing guard/docs examples.","status":"closed","priority":3,"issue_type":"task","owner":"boss@fullofcaffeine.com","created_at":"2026-07-09T10:26:06Z","created_by":"Marcelo Serpa","updated_at":"2026-07-09T10:35:18Z","started_at":"2026-07-09T10:26:25Z","closed_at":"2026-07-09T10:35:18Z","dependency_count":0,"dependent_count":0,"comment_count":0}
433434
{"_type":"issue","id":"haxe.elixir.codex-dnd","title":"Clean nonessential vendored Reflaxe drift","description":"Remove local vendored Reflaxe differences that the patch audit classified as cleanup-only: debug_function_collection/debug_preprocessor instrumentation in ReflectCompiler, debug_preprocessor instrumentation in ExpressionPreprocessor, and whitespace-only drift in EverythingIsExprSanitizer. Keep all required framework patches intact.","acceptance_criteria":"Required patches documented in vendor/reflaxe/PATCHES.md remain present; vendored debug-only drift is removed; whitespace-only drift is either removed or explicitly retained when matching upstream would violate diff hygiene; package smoke and quick compiler validation pass.","status":"closed","priority":3,"issue_type":"chore","owner":"boss@fullofcaffeine.com","created_at":"2026-07-09T09:30:16Z","created_by":"Marcelo Serpa","updated_at":"2026-07-09T09:41:07Z","started_at":"2026-07-09T09:30:28Z","closed_at":"2026-07-09T09:41:07Z","close_reason":"Removed debug-only vendored Reflaxe drift from ReflectCompiler and ExpressionPreprocessor while preserving the six required local framework patches. Kept the one whitespace-only EverythingIsExprSanitizer delta because matching upstream would add trailing whitespace. Verified npm run test:haxelib-package, npm run test:quick, and npm run guard:hx-format.","labels":["cleanup","maintenance","reflaxe"],"dependency_count":0,"dependent_count":0,"comment_count":0}
434435
{"_type":"issue","id":"haxe.elixir.codex-bct","title":"Audit vendored Reflaxe patches for upstream relevance","description":"Review vendor/reflaxe/PATCHES.md against the current upstream Reflaxe implementation and determine whether each local patch is still required, already upstreamed, or can be removed. This is intentionally separate from the Reflaxe layout cleanup so the compiler keeps using the known patched framework during the directory/package migration.","acceptance_criteria":"Patch-by-patch status recorded; safe removals or upstream PR follow-ups identified; no vendored Reflaxe patch is removed without a passing package smoke and core compiler validation.","status":"closed","priority":3,"issue_type":"chore","owner":"boss@fullofcaffeine.com","created_at":"2026-07-09T05:17:12Z","created_by":"Marcelo Serpa","updated_at":"2026-07-09T08:47:05Z","closed_at":"2026-07-09T08:47:05Z","close_reason":"Audited vendored Reflaxe patches against upstream base 430b4187a6bf4813cf618fc3a73ccf494a2ab9f5 and current upstream main 73a983112e039daad46b37912ab238df6bf0cf53. Recorded six required local patches, identified nonessential cleanup candidates, clarified upstream PR/removal validation paths, and removed stale target-owned EnumIntrospectionCompiler content from PATCHES.md. No vendored code patches removed. Verified npm run test:haxelib-package and npm run test:quick.","labels":["follow-up","maintenance","reflaxe"],"dependency_count":0,"dependent_count":0,"comment_count":0}
435436
{"_type":"issue","id":"haxe.elixir.codex-dnv.23.1","title":"Compiler follow-up: preserve returns in reducer-lowered loops","description":"While classifying haxe.ds.Option, OptionTools.all exposed that a return inside a for loop lowered to Enum.reduce can be emitted as a discarded value inside the reducer, after which the function continues to its trailing return. Investigate a compiler-level fix for non-local return semantics in accumulator/reducer-lowered loops.","acceptance_criteria":"A minimal regression demonstrates return inside a reducer-lowered loop exits the enclosing Haxe function; generated Elixir uses an explicit halt/return carrier or equivalent deterministic shape; affected snapshots/runtime tests pass.","status":"closed","priority":3,"issue_type":"bug","owner":"boss@fullofcaffeine.com","created_at":"2026-07-07T11:28:20Z","created_by":"Marcelo Serpa","updated_at":"2026-07-07T13:32:41Z","closed_at":"2026-07-07T13:32:41Z","close_reason":"Implemented return carrier for reducer-lowered loops with regression/runtime coverage","labels":["parity","stdlib"],"dependencies":[{"issue_id":"haxe.elixir.codex-dnv.23.1","depends_on_id":"haxe.elixir.codex-dnv.23","type":"parent-child","created_at":"2026-07-07T05:28:20Z","created_by":"Marcelo Serpa","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* **reflaxe:** align stdlib override sources with the Reflaxe `_std` layout; source-tree and GitHub/Lix builds now load `std/elixir/_std` before target-owned `std` APIs so PhoenixHx/examples keep using the Elixir stdlib overrides in dev mode.
66
* **reflaxe:** audit vendored framework patches against upstream Reflaxe and document which local fixes remain required before they can be removed or upstreamed.
77
* **reflaxe:** remove debug-only vendored framework drift while preserving required local Reflaxe patches.
8+
* **docs:** clarify the remaining early `src/haxe/**` overrides, including why `src/haxe/Exception.cross.hx` intentionally remains the lone source-tree `.cross.hx` file.
89

910
## [0.14.20](https://github.com/fullofcaffeine/reflaxe.elixir/compare/v0.14.19...v0.14.20) (2026-07-09)
1011

docs/01-getting-started/cross-hx.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
> - `.cross.hx` = target-specific implementation of a familiar API (same surface, idiomatic target code)
55
> - The suffix is Haxe 4's target-specific file mechanism; `cross` is Haxe's generic custom-target platform, not a promise that the file is portable across all targets
66
> - In this repo, authored stdlib replacements live as plain `.hx` files under `std/elixir/_std/**`; Reflaxe build can package them as `.cross.hx`
7-
> - Exception: a small set of *early-resolved* overrides may live under the library `src/` classpath so consumer installs pick them up before bootstrap macros run (example: `src/haxe/Exception.cross.hx`)
7+
> - Exception: a small set of *early-resolved* overrides may live under the library `src/` classpath so consumer installs pick them up before bootstrap macros run. `src/haxe/Exception.cross.hx` is the intentional lone source-tree `.cross.hx`; selected `src/haxe/ds/*.hx` files are early plain `.hx` overrides.
88
> - `std/elixir/_std/` is a selective override root: modules we do not provide there keep resolving from the installed official Haxe stdlib
99
> - Reflaxe's skeleton `build` command generates packaged `.cross.hx` files from `_std` source roots; checked-in `std/**/*.cross.hx` is no longer the source layout
1010
> - Prefer `_std` overrides for stable API mappings; use macros for authoring ergonomics; use AST transforms for shape-driven rewrites
@@ -48,7 +48,7 @@ Practical note (consumer installs)
4848
- When installed via haxelib/lix, the library’s `src/` classpath is available immediately, but `std/elixir/_std/` and `std/` are added by bootstrap macros for Elixir builds.
4949
- "Added" means Haxe searches the installed package's override/API directories before the official Haxe stdlib for that compile. No files are copied, generated, or renamed at that moment.
5050
- Some Haxe stdlib modules are resolved *very early* (before bootstrap can run). If a `.cross.hx` override must win for those modules, it needs to live on the initial classpath (under `src/`).
51-
- In rare cases we also use this “early override” pattern for plain `.hx` modules that must work in **both** macro/eval and Elixir target compilation. Those files are dual-mode (`#if macro` implementation, `#else` extern) and live under `src/haxe/**` (example: `src/haxe/ds/BalancedTree.hx`).
51+
- In rare cases we also use this “early override” pattern for plain `.hx` modules that must work in **both** macro/eval and Elixir target compilation, or whose receiver semantics are tied to compiler lowering. Those files live under `src/haxe/**` (examples: `src/haxe/ds/BalancedTree.hx`, `src/haxe/ds/List.hx`).
5252

5353
When compiling for the `cross` platform from a packaged Reflaxe build, Haxe treats files ending in
5454
`.cross.hx` as platform-specific module implementations. During normal source-tree/GitHub/Lix builds,

docs/03-compiler-development/CROSS_FILES_STAGING_MECHANISM.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,8 +232,14 @@ Important detail (Haxe 4 / `cross`)
232232
### Why `elixir_output` shows up inside some `.cross.hx` files
233233

234234
Most target-specific code is hidden from other contexts by classpath gating (`std/elixir/_std/` and
235-
`std/` are added to the active classpath only for Elixir builds). However, a small set of overrides must live on the library `src/` classpath
236-
so consumer installs resolve them *before* bootstrap macros run (example: `src/haxe/Exception.cross.hx`).
235+
`std/` are added to the active classpath only for Elixir builds). However, a small set of overrides
236+
must live on the library `src/` classpath so consumer installs resolve them *before* bootstrap macros
237+
run.
238+
239+
`src/haxe/Exception.cross.hx` is intentionally the lone source-tree `.cross.hx` file in that early
240+
set. Upstream `haxe.Exception` is extern, so macro/eval and non-cross targets can keep resolving the
241+
official stdlib file. The Elixir target needs a concrete emitted base module for exception structs,
242+
so the early `.cross.hx` file provides that implementation only when `elixir_output` is active.
237243

238244
Because `src/` is visible in more situations (tools, JS/genes builds, etc.), those early overrides often use:
239245

@@ -242,6 +248,11 @@ Because `src/` is visible in more situations (tools, JS/genes builds, etc.), tho
242248
This ensures they only emit Elixir-specific implementations (including `__elixir__()` injections) when the
243249
Elixir backend is actually active, while remaining harmless type surfaces elsewhere.
244250

251+
The plain `.hx` early overrides under `src/haxe/ds/**` are the other side of the same constraint:
252+
they must be visible to macro/eval when Haxe needs constructors or WAE-safe stdlib surfaces before
253+
target std insertion can run. See `docs/04-api-reference/STANDARD_LIBRARY_HANDLING.md` for the
254+
current inventory and ownership rules.
255+
245256
Implementation:
246257

247258
- `src/reflaxe/elixir/CompilerBootstrap.hx`

docs/04-api-reference/STANDARD_LIBRARY_HANDLING.md

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ Packaging note:
116116
- If we publish to haxelib.org, validate the generated package path separately with
117117
`npm run test:haxelib-package`.
118118

119-
### Bootstrap-safe overrides (early, dual-mode)
119+
### Bootstrap-safe overrides (early source-classpath modules)
120120

121121
Some stdlib modules are resolved **very early** during compilation, and Haxe runs macros using the `eval` interpreter.
122122
That combination means a few modules must satisfy two requirements at once:
@@ -125,14 +125,31 @@ That combination means a few modules must satisfy two requirements at once:
125125
2) **Elixir output phase (target-side)**: we must avoid emitting the canonical Haxe stdlib implementation when it is
126126
non-idiomatic for BEAM or produces Elixir warnings that fail CI under `--warnings-as-errors` (WAE).
127127

128-
For those specific modules, we use a **dual-mode override** under `src/`:
128+
For those specific modules, we use an early override under `src/haxe/**`, the package classpath that
129+
is available immediately when a project uses `-lib reflaxe.elixir`.
130+
131+
There are three current shapes:
132+
133+
- `src/haxe/Exception.cross.hx` is intentionally still target-suffixed. Upstream `haxe.Exception`
134+
is extern, so macro/eval and non-cross targets can keep resolving upstream. Elixir output needs a
135+
concrete base module for exception structs, so the `.cross.hx` file provides `Reflaxe.Exception`
136+
behind `#if elixir_output ... #else extern ... #end`.
137+
- `src/haxe/ds/{ArraySort,BalancedTree,EnumValueMap,ListSort}.hx` are dual-mode plain `.hx` modules:
138+
`#if macro` gives eval a small implementation, while `#else` exposes an extern surface or target
139+
diagnostic surface so generated Elixir does not emit the canonical mutable stdlib implementation.
140+
- `src/haxe/ds/{GenericStack,HashMap,List}.hx` are early BEAM-safe implementations whose observable
141+
mutation semantics depend on the compiler's receiver-rebinding rules.
142+
143+
For dual-mode plain `.hx` modules, the usual pattern is:
129144

130145
- `#if macro`: small in-memory implementation (keeps macro/eval happy).
131146
- `#else`: `@:nativeGen extern` surface (prevents canonical stdlib code from being emitted into generated `.ex`).
132147

133148
Examples:
134149
- `src/haxe/ds/BalancedTree.hx`
135150
- `src/haxe/ds/EnumValueMap.hx`
151+
- `src/haxe/ds/ArraySort.hx`
152+
- `src/haxe/ds/ListSort.hx`
136153

137154
Why `src/`?
138155
- For haxelib installs, `src/` is the only path guaranteed to be on the initial classpath for `-lib reflaxe.elixir`.
@@ -152,9 +169,12 @@ Why the path looks like the Haxe stdlib (`src/haxe/ds/...`)?
152169
Is this a Reflaxe convention?
153170
- It’s a common pattern across target compilers (including Reflaxe-based ones): when a module must be
154171
resolved before bootstrap/injection can run, it needs to live on the library’s initial classpath.
155-
- The dual-mode approach (`#if macro` implementation, `#else` extern) is specific to our constraints:
172+
- The dual-mode approach (`#if macro` implementation, `#else` extern) is specific to our constraints:
156173
Haxe eval must be able to instantiate the type, but we don’t want to emit the upstream implementation
157174
into Elixir output when it is non-idiomatic or breaks `--warnings-as-errors`.
175+
- `haxe.Exception` is different: because upstream is already extern, the target-specific `.cross.hx`
176+
file can stay out of macro/eval resolution while still giving Elixir builds the concrete base module
177+
they need.
158178

159179
The injection point is macro-time, in:
160180
- `src/reflaxe/elixir/CompilerBootstrap.hx:1` (early injection, invoked from `extraParams.hxml`)

docs/05-architecture/CROSS_OVERRIDES_AND_MULTI_TARGET_HARDENING.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,20 @@ That is not automatically wrong, but it does mean contributors need a clearer me
2222
- normal target-conditional stdlib override sources
2323
2. `std/**/*.hx`
2424
- target-owned APIs/support modules such as `elixir.*`, `phoenix.*`, and `ecto.*`
25-
3. `src/haxe/Exception.cross.hx`
26-
- early-visible bootstrap-safe override
25+
3. `src/haxe/**`
26+
- early-visible bootstrap-safe overrides, including `src/haxe/Exception.cross.hx` and selected
27+
`src/haxe/ds/*.hx` stdlib surfaces
2728

2829
That is a coherent design, but it is a different design from `reflaxe.ocaml`.
2930

3031
## Quick matrix
3132

3233
| Question | Answer for this repo |
3334
| --- | --- |
34-
| Main override style | broad `std/elixir/_std/**/*.hx` plus target-owned `std/**/*.hx` APIs plus one early `src/haxe/*` exception |
35+
| Main override style | broad `std/elixir/_std/**/*.hx` plus target-owned `std/**/*.hx` APIs plus selected early `src/haxe/**` overrides |
3536
| Is `_std` used? | yes |
3637
| Is `.cross.hx` used broadly? | yes in packaged output; source-tree overrides are plain `.hx` |
37-
| Does this repo own early `src/haxe/*` modules? | yes, `src/haxe/Exception.cross.hx` |
38+
| Does this repo own early `src/haxe/*` modules? | yes, `src/haxe/Exception.cross.hx` and selected `src/haxe/ds/*.hx` modules |
3839
| Bootstrap activation currently keys off raw Haxe 4 `Cross`? | yes |
3940
| Same-compilation sibling-target coexistence safe today? | no |
4041
| Highest-priority hardening item | narrow Haxe 4 bootstrap activation and add mixed-target fail-fast |
@@ -79,8 +80,10 @@ It means this repo can inject Elixir stdlib classpaths earlier and more broadly
7980
This repo currently owns:
8081

8182
- `src/haxe/Exception.cross.hx`
83+
- selected `src/haxe/ds/*.hx` modules
8284

83-
That collides directly with the same early module path in `reflaxe.ocaml`.
85+
The sharpest known collision is `src/haxe/Exception.cross.hx`, which collides directly with the same
86+
early module path in `reflaxe.ocaml`.
8487

8588
If both libraries are loaded in one compile, classpath order decides which `haxe.Exception` wins.
8689

@@ -100,7 +103,8 @@ Recommended next steps:
100103

101104
1. Narrow Haxe 4 bootstrap activation so raw `Cross` is not treated as sufficient target identity.
102105
2. Add explicit mixed-target detection/fail-fast behavior when sibling target libraries are active together.
103-
3. Keep `src/haxe/Exception.cross.hx` documented as an early exception-path override, not just another stdlib file.
106+
3. Keep `src/haxe/Exception.cross.hx` documented as the intentional lone source-tree `.cross.hx`
107+
early override, not just another stdlib file.
104108
4. Add a focused coexistence smoke or regression test if a deterministic test shape can be designed.
105109

106110
## Local sibling references

0 commit comments

Comments
 (0)