plum

#treesitter#compiler#wasm

git clone https://git.pyrossh.dev/plum

A statically typed, imperative programming language inspired by rust, python


8805ee9 — Peter John 2026-11-02T18:41:53+05:30
docs(plans): closure field-assignment fix review plan
docs/plans/2026-11-02-closure-field-assign.review.md ADDED
@@ -0,0 +1,38 @@
1
+ # Fix: a closure assigning two fields of a captured record
2
+
3
+ ## Summary
4
+ A closure that assigns more than one field of a record it captures fails to compile:
5
+
6
+ ```plum
7
+ record Pair2(x: Int, y: Int)
8
+
9
+ test "t"
10
+ m := Pair2(x: 0, y: 0)
11
+ f := ||
12
+ m.x = 5
13
+ m.y = 6
14
+ f()
15
+ assert m.y == 6
16
+ ```
17
+
18
+ It fails with `codegen error: codegen: cannot assign field 'x' on non-class type Int`. A single field assignment works, and so do two assignments on a closure *parameter*. The bug was found while building `std/game/Scene`, which had to work around it. Repros are in the session scratchpad (`zi-bugs/a.plum`, `b.plum`, `d.plum`).
19
+
20
+ ## What changes for Plum code
21
+ Nothing new to learn: the snippet above compiles and the test passes. Any number of field assignments to a captured record, through any mix of statements, works the same as it does outside a closure.
22
+
23
+ ## Work, in order
24
+ 1. Add a failing regression test in plum-wasm-codegen/tests for the repro and its variants:
25
+ - two and three field assignments;
26
+ - the assigned value from a captured local (`m.x = k`, `m.y = k + 1`);
27
+ - a nested record field (`m.inner.x = 1`);
28
+ - a struct (value type) captured, which must keep its current semantics, whatever those are; document them;
29
+ - a read after the closure call.
30
+ 2. Find the root cause in codegen (closure capture of a record, probably the captured variable's type after the first statement), and fix it there rather than special-casing two assignments.
31
+ 3. Remove the workaround in `plum-std/game/Scene.plum` if it's still there, keeping its tests green.
32
+
33
+ ## How we will know it works
34
+ - The new tests pass, along with `cargo test --workspace` and `plum test plum-std plum-examples plum-game/web-test/fixtures`.
35
+ - `plum-examples/scene.plum` and `game.plum` still pass the browser check.
36
+
37
+ ## Not in scope
38
+ - Other closure features: capture by reference semantics for structs beyond documenting current behaviour, and `fn(..)?` optional function types.