Skip to content

Commit 1d10951

Browse files
hyperpolymathclaude
andcommitted
docs: KNOWN-ISSUES.md — two codegen bugs with minimal reproducers
Discovered 2026-04-19 while writing the first AffineScript-native test suite (web-ecosystem/double-track-browser/tests/affine/, commit b1f3b80 in that repo). Both bugs block richer AffineScript idioms in the affinescript-deno-test harness: 1. `match` on enum with distinct zero-arity constructors per arm emits invalid WASM (stack imbalance rejected by V8). 2. Non-first struct-field read from a function parameter returns 0 regardless of actual value; first-field reads and let-bound-local reads both work correctly. Each has a minimal reproducer + suggested workaround + best-guess compiler-file location. Estate tracker in ~/Desktop/AI-WORK-todo.md §11. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent ce324fa commit 1d10951

1 file changed

Lines changed: 127 additions & 0 deletions

File tree

KNOWN-ISSUES.md

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
<!-- SPDX-License-Identifier: PMPL-1.0-or-later -->
2+
# Known AffineScript codegen issues
3+
4+
Minimal reproducers for codegen bugs discovered while using AffineScript
5+
downstream. Please open a proper GitHub issue (or link an existing one)
6+
before starting a fix so the fix can be attributed.
7+
8+
---
9+
10+
## Issue 1 — `match` on enum with distinct zero-arity constructors per arm emits invalid WASM
11+
12+
**Discovered:** 2026-04-19 while writing `web-ecosystem/double-track-browser/tests/affine/extension_lifecycle_test.affine`.
13+
14+
**Symptom:** `affinescript compile` succeeds. The emitted `.wasm` is rejected by every WebAssembly validator (tested: V8 via Deno):
15+
16+
```
17+
CompileError: WebAssembly.compile(): Compiling function #1 failed:
18+
expected 1 elements on the stack for fallthru, found 2
19+
```
20+
21+
**Minimal reproducer:**
22+
23+
```affine
24+
enum Lifecycle {
25+
A,
26+
B,
27+
C(Int)
28+
}
29+
30+
fn step(s: Lifecycle) -> Lifecycle {
31+
match s {
32+
A => B(),
33+
B => B(),
34+
C(n) => C(n)
35+
}
36+
}
37+
```
38+
39+
**Workaround:** Downgrade enums to tagged structs when the match must
40+
return distinct zero-arity constructors across arms:
41+
42+
```affine
43+
struct State {
44+
tag: Int,
45+
// ...payload fields
46+
}
47+
```
48+
49+
**Likely location in compiler:** `lib/codegen.ml` around match-arm
50+
lowering for enum construction sites.
51+
52+
---
53+
54+
## Issue 2 — Non-first struct-field read from function parameter returns 0
55+
56+
**Discovered:** 2026-04-19 in the same pilot.
57+
58+
**Symptom:** Reading `s.tag` (field at offset 0) from a function parameter
59+
`s: State` works correctly. Reading `s.profile_id` (field at offset 1) or
60+
`s.activity_count` (field at offset 2) from the same parameter always
61+
returns 0, regardless of the actual value stored in the struct. Reading
62+
the same fields from a let-bound local of the same struct type works
63+
fine.
64+
65+
**Minimal reproducer:**
66+
67+
```affine
68+
struct State {
69+
tag: Int,
70+
profile_id: Int,
71+
activity_count: Int
72+
}
73+
74+
fn build_state(pid: Int) -> State {
75+
{ tag: 2, profile_id: pid, activity_count: 0 }
76+
}
77+
78+
fn read_pid(s: State) -> Int {
79+
s.profile_id
80+
}
81+
82+
pub fn test_direct_local() -> Bool {
83+
let s = { tag: 2, profile_id: 42, activity_count: 0 };
84+
s.profile_id == 42 // PASSES
85+
}
86+
87+
pub fn test_local_from_builder() -> Bool {
88+
let s = build_state(42);
89+
s.profile_id == 42 // PASSES
90+
}
91+
92+
pub fn test_via_helper() -> Bool {
93+
let s = build_state(42);
94+
read_pid(s) == 42 // FAILS: read_pid returns 0
95+
}
96+
```
97+
98+
**Workaround:** Pass individual scalars instead of a struct, or read
99+
struct fields into local variables at the call site before handing off
100+
to a helper:
101+
102+
```affine
103+
fn read_pid_scalar(_tag: Int, pid: Int, _count: Int) -> Int {
104+
pid
105+
}
106+
107+
pub fn test_via_scalar_helper() -> Bool {
108+
let s = build_state(42);
109+
read_pid_scalar(s.tag, s.profile_id, s.activity_count) == 42
110+
}
111+
```
112+
113+
**Likely location in compiler:** `lib/codegen.ml` around struct-field
114+
access codegen for function-parameter locals (likely a wrong local
115+
index or wrong offset calculation when the struct pointer is a function
116+
parameter rather than a let-bound local).
117+
118+
---
119+
120+
## Tracking
121+
122+
Both issues block scaling the `affinescript-deno-test` harness (sibling
123+
component at `developer-ecosystem/affinescript-ecosystem/
124+
affinescript-deno-test/`) from its current 10-test pilot to the
125+
estate-wide TypeScript-test migration in AI-WORK-todo.md §3c.
126+
127+
Estate tracker: `~/Desktop/AI-WORK-todo.md §11`.

0 commit comments

Comments
 (0)