plum
git clone https://git.pyrossh.dev/plum
A statically typed, imperative programming language inspired by rust, python
949dabf
— Peter John
2026-11-05T16:34:55+05:30
Build speed: one test binary per crate, editor assets only for dist builds
- AGENTS.md +1 -1
- Cargo.toml +3 -0
- Makefile.toml +5 -0
- docs/backlog.md +3 -0
- docs/plans/2026-11-05-build-speed.md +92 -0
- docs/plans/2026-11-05-build-speed.results.md +21 -0
- docs/plans/2026-11-05-language-simplification-d3.progress.md +11 -0
- plum-checker/tests/{checker_tests.rs → checker/checker_tests.rs} +0 -0
- plum-checker/tests/{closure_hint_test.rs → checker/closure_hint_test.rs} +0 -0
- plum-checker/tests/{features → checker/features}/closure_types.rs +0 -0
- plum-checker/tests/{features → checker/features}/io_capability.rs +0 -0
- plum-checker/tests/{features/main.rs → checker/features/mod.rs} +0 -0
- plum-checker/tests/{features → checker/features}/mutability.rs +0 -0
- plum-checker/tests/{features → checker/features}/optional_unpinned.rs +0 -0
- plum-checker/tests/{features → checker/features}/pattern_casing.rs +0 -0
- plum-checker/tests/{features → checker/features}/primitive_generics.rs +0 -0
- plum-checker/tests/{features → checker/features}/types.rs +0 -0
- plum-checker/tests/{features → checker/features}/variant_pattern.rs +0 -0
- plum-checker/tests/{fusion_pipeline_test.rs → checker/fusion_pipeline_test.rs} +0 -0
- plum-checker/tests/{inline_variants_tests.rs → checker/inline_variants_tests.rs} +0 -0
- plum-checker/tests/checker/main.rs +9 -0
- plum-checker/tests/{question_tests.rs → checker/question_tests.rs} +0 -0
- plum-checker/tests/{subtyping_tests.rs → checker/subtyping_tests.rs} +0 -0
- plum-cli/build.rs +17 -0
- plum-cli/src/editor.rs +6 -1
- plum-cli/tests/{assert_once_test.rs → cli/assert_once_test.rs} +0 -0
- plum-cli/tests/{compile_tests.rs → cli/compile_tests.rs} +0 -0
- plum-cli/tests/{crash_test.rs → cli/crash_test.rs} +0 -0
- plum-cli/tests/{explain_layout_test.rs → cli/explain_layout_test.rs} +0 -0
- plum-cli/tests/{game_web_test.rs → cli/game_web_test.rs} +0 -0
- plum-cli/tests/{host_stub_test.rs → cli/host_stub_test.rs} +0 -0
- plum-cli/tests/cli/main.rs +9 -0
- plum-cli/tests/{test_scope_test.rs → cli/test_scope_test.rs} +0 -0
- plum-core/tests/{closure_escape_test.rs → core/closure_escape_test.rs} +0 -0
- plum-core/tests/{closure_spec_test.rs → core/closure_spec_test.rs} +0 -0
- plum-core/tests/{closure_types_parse_test.rs → core/closure_types_parse_test.rs} +0 -0
- plum-core/tests/{drive_test.rs → core/drive_test.rs} +0 -0
- plum-core/tests/{for_next_test.rs → core/for_next_test.rs} +0 -0
- plum-core/tests/{formatter_test.rs → core/formatter_test.rs} +0 -0
- plum-core/tests/{forms_list_range_test.rs → core/forms_list_range_test.rs} +0 -0
- plum-core/tests/{fused_closure_generic_test.rs → core/fused_closure_generic_test.rs} +0 -0
- plum-core/tests/{generics_test.rs → core/generics_test.rs} +0 -0
- plum-core/tests/{inline_variants_test.rs → core/inline_variants_test.rs} +0 -0
- plum-core/tests/{layout_test.rs → core/layout_test.rs} +0 -0
- plum-core/tests/{list_literal_test.rs → core/list_literal_test.rs} +0 -0
- plum-core/tests/{loader_test.rs → core/loader_test.rs} +0 -0
- plum-core/tests/{lower_test.rs → core/lower_test.rs} +0 -0
- plum-core/tests/core/main.rs +33 -0
- plum-core/tests/{match_body_parse_test.rs → core/match_body_parse_test.rs} +0 -0
- plum-core/tests/{override_parse_test.rs → core/override_parse_test.rs} +0 -0
- plum-core/tests/{parser_test.rs → core/parser_test.rs} +0 -0
- plum-core/tests/{purity_test.rs → core/purity_test.rs} +0 -0
- plum-core/tests/{question_parse_test.rs → core/question_parse_test.rs} +0 -0
- plum-core/tests/{record_embed_test.rs → core/record_embed_test.rs} +0 -0
- plum-core/tests/{record_init_parse_test.rs → core/record_init_parse_test.rs} +0 -0
- plum-core/tests/{record_init_test.rs → core/record_init_test.rs} +0 -0
- plum-core/tests/{rename_test.rs → core/rename_test.rs} +0 -0
- plum-core/tests/{session_test.rs → core/session_test.rs} +0 -0
- plum-core/tests/{simplify_test.rs → core/simplify_test.rs} +0 -0
- plum-core/tests/{subtyping_test.rs → core/subtyping_test.rs} +0 -0
- plum-core/tests/{tail_test.rs → core/tail_test.rs} +0 -0
- plum-core/tests/{tests_lower_test.rs → core/tests_lower_test.rs} +0 -0
- plum-core/tests/{trmc_test.rs → core/trmc_test.rs} +0 -0
- plum-core/tests/{unions_test.rs → core/unions_test.rs} +0 -0
- plum-core/tests/{uniqueness_test.rs → core/uniqueness_test.rs} +0 -0
- plum-core/tests/{visit_test.rs → core/visit_test.rs} +0 -0
- plum-core/tests/{whistle_test.rs → core/whistle_test.rs} +0 -0
- plum-wasm-codegen/tests/{codegen_tests.rs → wasm_codegen/codegen_tests.rs} +0 -0
- plum-wasm-codegen/tests/{e2e_mem/main.rs → wasm_codegen/e2e_mem/mod.rs} +0 -0
- plum-wasm-codegen/tests/{e2e_mem → wasm_codegen/e2e_mem}/reuse.rs +0 -0
- plum-wasm-codegen/tests/{e2e_mem → wasm_codegen/e2e_mem}/unique_inplace.rs +0 -0
- plum-wasm-codegen/tests/{e2e_mem → wasm_codegen/e2e_mem}/unique_spread.rs +0 -0
- plum-wasm-codegen/tests/{e2e_records → wasm_codegen/e2e_records}/empty_record_embed.rs +0 -0
- plum-wasm-codegen/tests/{e2e_records → wasm_codegen/e2e_records}/enum_init.rs +0 -0
- plum-wasm-codegen/tests/{e2e_records → wasm_codegen/e2e_records}/inline_variants.rs +0 -0
- plum-wasm-codegen/tests/{e2e_records/main.rs → wasm_codegen/e2e_records/mod.rs} +0 -0
- plum-wasm-codegen/tests/{e2e_records → wasm_codegen/e2e_records}/record_embed.rs +0 -0
- plum-wasm-codegen/tests/{e2e_records → wasm_codegen/e2e_records}/record_init.rs +0 -0
- plum-wasm-codegen/tests/{e2e_records → wasm_codegen/e2e_records}/unboxed_variants.rs +0 -0
- plum-wasm-codegen/tests/{e2e_tail → wasm_codegen/e2e_tail}/closure_tail.rs +0 -0
- plum-wasm-codegen/tests/{e2e_tail → wasm_codegen/e2e_tail}/error_tail.rs +0 -0
- plum-wasm-codegen/tests/{e2e_tail → wasm_codegen/e2e_tail}/loop_break.rs +0 -0
- plum-wasm-codegen/tests/{e2e_tail/main.rs → wasm_codegen/e2e_tail/mod.rs} +0 -0
- plum-wasm-codegen/tests/{e2e_tail → wasm_codegen/e2e_tail}/tail.rs +0 -0
- plum-wasm-codegen/tests/{e2e_types → wasm_codegen/e2e_types}/closure_optional.rs +0 -0
- plum-wasm-codegen/tests/{e2e_types → wasm_codegen/e2e_types}/closure_types.rs +0 -0
- plum-wasm-codegen/tests/{e2e_types → wasm_codegen/e2e_types}/io_entry.rs +0 -0
- plum-wasm-codegen/tests/{e2e_types → wasm_codegen/e2e_types}/list_and_shadow.rs +0 -0
- plum-wasm-codegen/tests/{e2e_types/main.rs → wasm_codegen/e2e_types/mod.rs} +0 -0
- plum-wasm-codegen/tests/{e2e_types → wasm_codegen/e2e_types}/question.rs +0 -0
- plum-wasm-codegen/tests/{e2e_types → wasm_codegen/e2e_types}/subtyping.rs +0 -0
- plum-wasm-codegen/tests/{e2e_types → wasm_codegen/e2e_types}/type_param_static.rs +0 -0
- plum-wasm-codegen/tests/{examples_test.rs → wasm_codegen/examples_test.rs} +0 -0
- plum-wasm-codegen/tests/{fusion_alloc_test.rs → wasm_codegen/fusion_alloc_test.rs} +0 -0
- plum-wasm-codegen/tests/wasm_codegen/main.rs +9 -0
AGENTS.md
CHANGED
|
@@ -6,7 +6,7 @@ Do not use git worktrees or feature branches. Work directly on `master` in the m
|
|
|
6
6
|
|
|
7
7
|
## Disk space
|
|
8
8
|
|
|
9
|
-
The SSD is nearly full. After a plan or phase is finished and merged to `master`, run:
|
|
9
|
+
The SSD is nearly full. After a plan or phase is finished and merged to `master`, check `df -h /` and, only when under ~20 GB is free, run:
|
|
10
10
|
|
|
11
11
|
```
|
|
12
12
|
cargo clean-all -y
|
Cargo.toml
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
members = ["plum-core", "plum-cli", "plum-checker", "plum-wasm-codegen", "plum-lsp", "plum-test-support", "plum-host"]
|
|
3
3
|
resolver = "2"
|
|
4
4
|
|
|
5
|
+
[profile.dev]
|
|
6
|
+
debug = "line-tables-only"
|
|
7
|
+
|
|
5
8
|
[profile.dev.package.wasmtime]
|
|
6
9
|
opt-level = 3
|
|
7
10
|
|
Makefile.toml
CHANGED
|
@@ -101,6 +101,8 @@ fi
|
|
|
101
101
|
# everything to R2. Version comes from plum-cli/Cargo.toml — bump that first.
|
|
102
102
|
|
|
103
103
|
[env]
|
|
104
|
+
# Distributed binaries embed the editor assets (dev builds skip them).
|
|
105
|
+
PLUM_EMBED_EDITOR = "1"
|
|
104
106
|
PLUM_VERSION = { script = ["grep -m1 '^version' plum-cli/Cargo.toml | sed -E 's/version = \"(.*)\"/\\1/'"] }
|
|
105
107
|
|
|
106
108
|
[tasks.dist-macos]
|
|
@@ -108,6 +110,7 @@ description = "Build a release plum-cli binary for this Mac into dist/plum-cli/"
|
|
|
108
110
|
script_runner = "@shell"
|
|
109
111
|
script = '''
|
|
110
112
|
set -e
|
|
113
|
+
export PLUM_EMBED_EDITOR=1
|
|
111
114
|
cargo build --release -p plum-cli
|
|
112
115
|
mkdir -p dist/plum-cli
|
|
113
116
|
ARCH=$(uname -m)
|
|
@@ -125,6 +128,7 @@ description = "Cross-build a release plum-cli binary for Linux x86_64 (via `cros
|
|
|
125
128
|
script_runner = "@shell"
|
|
126
129
|
script = '''
|
|
127
130
|
set -e
|
|
131
|
+
export PLUM_EMBED_EDITOR=1
|
|
128
132
|
cross build --release -p plum-cli --target x86_64-unknown-linux-gnu
|
|
129
133
|
mkdir -p dist/plum-cli
|
|
130
134
|
cp target/x86_64-unknown-linux-gnu/release/plum dist/plum-cli/plum-linux-x86_64
|
|
@@ -136,6 +140,7 @@ description = "Cross-build a release plum-cli binary for Windows x86_64 (via `cr
|
|
|
136
140
|
script_runner = "@shell"
|
|
137
141
|
script = '''
|
|
138
142
|
set -e
|
|
143
|
+
export PLUM_EMBED_EDITOR=1
|
|
139
144
|
cross build --release -p plum-cli --target x86_64-pc-windows-gnu
|
|
140
145
|
mkdir -p dist/plum-cli
|
|
141
146
|
cp target/x86_64-pc-windows-gnu/release/plum.exe dist/plum-cli/plum-windows-x86_64.exe
|
docs/backlog.md
CHANGED
|
@@ -10,6 +10,9 @@ Open work, in the order the user queued it, plus smaller items found during buil
|
|
|
10
10
|
- **Move the Rust code into `compiler/`** (user 2026-11-04: once all the refactoring is done) — every Rust crate (plum-core, plum-checker, plum-wasm-codegen, plum-cli, plum-lsp, plum-host, plum-test-support, plum-runtime, plum-game) goes under `compiler/`; `plum-std` and `plum-examples` stay at the top level. Mechanical but touches hardcoded paths: workspace `Cargo.toml` members, every `CARGO_MANIFEST_DIR/..` repoRoot (test-support, tests, cli), the loader's std lookup, the checker's `isStdFile`/`isIoFile` path tests, `cmdBuild`'s runtime manifest path, plum-game web-test fixtures, scripts/, Makefile.toml, plum-tooling (vscode/tree-sitter paths), README and docs links. Open question for then: keep the `plum-` prefixes inside `compiler/` or drop them (`compiler/core`, …).
|
|
11
11
|
2. **Simplify the language: no traits, no union enums, native inline variants** (decided by the user 2026-11-04; runs right after compiler-cleanup phase 3a, before explicit generics and 3b; decision record §13). Traits are removed as a language feature and replaced by records embedding records with subtyping + `override` dispatch (a `Ship` embedding `Node` is accepted wherever a `Node` is, and calls dispatch to Ship's overrides — the scene graph's `trait Actor` becomes a base record). Union enums (`enum X = A | B` of records) are removed: `JsonParse` and the union examples become inline-variant enums, union syntax becomes an error. Inline variants compile natively as struct subtypes of their enum, deleting `hoistInlineVariants`, the `List__Cons(Cons(..))` wrappers, union forwarders, `union_lower` and the checker's union plan. `unboxed_variants.plum` is a compiler probe: move it to a codegen test. Same plan also covers (user 2026-11-04): `=` reassign-only, no generators (`fun*`/`yield`; Seq deleted, one loop form `for x := range v` over Int or any `next(self) -> Option[Pair[T, Self]]`), no variadics (`...T`; `[..]` literal → `Cons`/`Nil`, `[k => v]` → `Map.empty().with(..)`), no value enums, `record` merged into `struct` now, and **run D: error sets / `T!E` / `T?` / `null` replaced by std `Option[T]` and `Result[T, E]` enums**, with postfix `?` as the ONLY sugar (revised 2026-11-05: `try`, `?:`, `?.`, `catch`, `T?`, `E!T`, `null` all removed; runs right after run C; decision record §13 item 1). Runs A (in progress), B (struct), C (traits/unions), D (Option/Result).
|
|
12
12
|
3. **Benchmark** before FBIP (user: FBIP waits for it).
|
|
13
|
+
- **Unbox iterators / niche Option layout** (user 2026-11-05: later, here, not before generics). Run D made `for` loops slower: for-over-List 1M 28 → 49 ms (+75%), for-over-Range 6 → 8 ms (+33%), Map.get +17% (docs/plans/2026-11-05-language-simplification-d.benchmark.md). Cause: `next() -> Option[Pair[T, Self]]` allocates a `Some` cell per step on top of the Pair (the old `Pair?` was a nullable ref). Options: `Option[R]` for a GC ref R as a nullable ref (niche), and/or fusion/drive unboxing the `Some(step) := it.next()` loop. Bisect 961bd21 vs d7658cc back-to-back first.
|
|
14
|
+
- **Run C game A/B** still owed (stress_scene/stress_world vs pre-run-C). D2 found closure-spec hints were empty since run C (fixed), which may explain part of it.
|
|
15
|
+
- **Build-speed** done separately right after run D (2026-11-05).
|
|
13
16
|
4. **FBIP: no heap mutation** — persistent std collections updated in place when unique, Koka-style `fip` functions as a checked in-place guarantee, a reference count used only as a uniqueness check if static proof falls short. Worklist = the `mut` fields left today (see below). (Decision record §9.)
|
|
14
17
|
5. **One product type, `struct`** — after FBIP, merge `record` into an immutable `struct` with compiler-chosen boxing (optional hint, shown by `--explain`). (Decision record §9b.)
|
|
15
18
|
- **Decide: do we still need traits?** (user 2026-11-04, decide with this item and item 2, since traits are lowered through the same hidden-union machinery). Today traits are used only by `std/game/imperative/Scene` (`trait Actor`, 14 fields), `std/game/pure/PureScene` (field-less `trait Actor` for `Custom` nodes) and three examples. The functional scene, the kids' games plan and `../kam_plum` use none. Their unique job is letting std hold user-defined kinds (a scene tree of the game's own `Ship`/`Orb`) with static dispatch.
|
docs/plans/2026-11-05-build-speed.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Build speed: fewer test binaries, no nested release build in dev
|
|
2
|
+
|
|
3
|
+
**Goal:** an edit to a compiler crate followed by `cargo build --workspace --tests` (or `cargo build -p plum-cli`) takes far less time. Today ~63 integration-test binaries each link wasmtime, and `plum-cli/build.rs` runs a nested `cargo build --release -p plum-lsp`, an `-O2` compile of the ~10 MB tree-sitter `parser.c`, and an npm build of the VS Code client on every plum-cli build whose inputs changed.
|
|
4
|
+
**Architecture:** Cargo workspace (plum-core, plum-checker, plum-wasm-codegen, plum-cli, ...), plum-cli/build.rs, Makefile.toml.
|
|
5
|
+
**Tech stack:** Rust 2021, cargo, cargo-make.
|
|
6
|
+
**Detail:** contracts
|
|
7
|
+
**Target-min:** 15
|
|
8
|
+
|
|
9
|
+
## Global constraints
|
|
10
|
+
- Work on `master` in the main checkout, default shared `target/` (no CARGO_TARGET_DIR). Don't commit. Never run `plum format` on real files. No `sed -i -E` (macOS backups).
|
|
11
|
+
- No `cargo test` (hook): `cargo build --tests -p <crate>`, run binaries in `target/debug/deps` (newest by mtime, `/bin/ls -t`; `ls` is aliased).
|
|
12
|
+
- No test is deleted or weakened: merging only moves files. Test counts per crate stay the same (record before/after).
|
|
13
|
+
- Moving a test file one directory deeper breaks relative `include_str!`/`include_bytes!`/fixture paths: use `env!("CARGO_MANIFEST_DIR")`-based paths or fix the relative path.
|
|
14
|
+
- Each merged crate ends with ONE integration-test binary: `tests/<name>/main.rs` with `mod <file>;` per former file (former `dir/main.rs` → `dir/mod.rs` as a nested module). Keep file names.
|
|
15
|
+
|
|
16
|
+
## Task graph
|
|
17
|
+
```mermaid
|
|
18
|
+
flowchart LR
|
|
19
|
+
T1[build.rs gating + dev profile + AGENTS.md]
|
|
20
|
+
T2[merge plum-core tests]
|
|
21
|
+
T3[merge plum-checker + plum-cli tests]
|
|
22
|
+
T4[merge plum-wasm-codegen tests]
|
|
23
|
+
T5[measure + results]
|
|
24
|
+
%% taskgraph
|
|
25
|
+
T1 --> T5
|
|
26
|
+
T2 --> T5
|
|
27
|
+
T3 --> T5
|
|
28
|
+
T4 --> T5
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Package A: build
|
|
32
|
+
**Probe entry:** run=cargo build --workspace --tests
|
|
33
|
+
|
|
34
|
+
### T1 build.rs gating, dev profile, AGENTS.md · Complexity 3 · Est. context 30k
|
|
35
|
+
**Owns:** plum-cli/build.rs, Makefile.toml, Cargo.toml, AGENTS.md, plum-cli/src/editor*.rs
|
|
36
|
+
**Components:** 1
|
|
37
|
+
**LOC owned:** 60
|
|
38
|
+
**Tests:** fast
|
|
39
|
+
**Model:** sonnet
|
|
40
|
+
**Produces:** plum-cli dev builds skip editor assets unless `PLUM_EMBED_EDITOR=1`
|
|
41
|
+
e.g. `cargo build -p plum-cli` -> no nested plum-lsp release build, no parser.c .so, no npm; `PLUM_EMBED_EDITOR=1 cargo build -p plum-cli` -> all three as today
|
|
42
|
+
**Notes:** reuse the existing graceful placeholders (each asset already degrades when its toolchain is missing); emit `cargo:rerun-if-env-changed=PLUM_EMBED_EDITOR`. Set `PLUM_EMBED_EDITOR=1` in every Makefile.toml dist task. `plum editor ...` with a placeholder asset must print a clear "this plum was built without editor assets; rebuild with PLUM_EMBED_EDITOR=1" (check plum-cli/src for where the embedded bins are used). Workspace `Cargo.toml`: `[profile.dev] debug = "line-tables-only"` (keep the wasmtime/cranelift opt-level overrides). AGENTS.md "Disk space": after a merged plan/phase check `df -h /` and run `cargo clean-all -y` only when under ~20 GB free (user 2026-11-05).
|
|
43
|
+
**Test code:** `cargo build -p plum-cli` succeeds without npm/cc being invoked (check build output / `-vv`); plum-cli test binaries green; `target/debug/plum test plum-std/Option.plum` green.
|
|
44
|
+
|
|
45
|
+
## Package B: test binaries
|
|
46
|
+
**Probe entry:** run=cargo build --workspace --tests
|
|
47
|
+
|
|
48
|
+
### T2 merge plum-core tests · Complexity 2 · Est. context 30k
|
|
49
|
+
**Owns:** plum-core/tests/**
|
|
50
|
+
**Components:** 1
|
|
51
|
+
**LOC owned:** 60
|
|
52
|
+
**Tests:** fast
|
|
53
|
+
**Model:** sonnet
|
|
54
|
+
**Produces:** plum-core has one integration-test binary `core`
|
|
55
|
+
e.g. `cargo build --tests -p plum-core` -> deps has `core-<hash>` (plus the lib unit-test binary), not 33
|
|
56
|
+
**Test code:** total passed count of plum-core integration tests before == after (record both); all green.
|
|
57
|
+
|
|
58
|
+
### T3 merge plum-checker and plum-cli tests · Complexity 2 · Est. context 30k
|
|
59
|
+
**Owns:** plum-checker/tests/**, plum-cli/tests/**
|
|
60
|
+
**Components:** 1
|
|
61
|
+
**LOC owned:** 50
|
|
62
|
+
**Tests:** fast
|
|
63
|
+
**Model:** sonnet
|
|
64
|
+
**Produces:** plum-checker has one binary `checker`, plum-cli one binary `cli`
|
|
65
|
+
e.g. `features/main.rs` -> `checker/features/mod.rs`
|
|
66
|
+
**Notes:** plum-cli tests may spawn `target/debug/plum` or use `env!("CARGO_BIN_EXE_plum")`; keep that working. Fixture dirs (`plum-checker/tests/fixtures`) stay where they are unless paths are relative.
|
|
67
|
+
**Test code:** passed counts per crate before == after; all green.
|
|
68
|
+
|
|
69
|
+
### T4 merge plum-wasm-codegen tests · Complexity 2 · Est. context 30k
|
|
70
|
+
**Owns:** plum-wasm-codegen/tests/**
|
|
71
|
+
**Components:** 1
|
|
72
|
+
**LOC owned:** 50
|
|
73
|
+
**Tests:** fast
|
|
74
|
+
**Model:** sonnet
|
|
75
|
+
**Produces:** plum-wasm-codegen has one binary `wasm_codegen` (`codegen` is git-ignored)
|
|
76
|
+
e.g. `e2e_types/main.rs` -> `wasm_codegen/e2e_types/mod.rs`; codegen_tests.rs, examples_test.rs, fusion_alloc_test.rs become modules
|
|
77
|
+
**Notes:** shared helpers duplicated across the e2e_* mains may now collide — keep them per module (`super::` paths) rather than merging.
|
|
78
|
+
**Test code:** passed count before == after; all green.
|
|
79
|
+
|
|
80
|
+
### T5 measure and results · Complexity 2 · Est. context 20k
|
|
81
|
+
**Owns:** docs/plans/2026-11-05-build-speed.results.md
|
|
82
|
+
**Components:** 1
|
|
83
|
+
**LOC owned:** 30
|
|
84
|
+
**Tests:** slow
|
|
85
|
+
**Model:** sonnet
|
|
86
|
+
**Consumes:** plum-cli dev builds skip editor assets unless `PLUM_EMBED_EDITOR=1` (T1) · plum-core has one integration-test binary `core` (T2) · plum-checker has one binary `checker`, plum-cli one binary `cli` (T3) · plum-wasm-codegen has one binary `wasm_codegen` (T4)
|
|
87
|
+
**Produces:** before/after build timings
|
|
88
|
+
**Notes:** baseline (before T1-T4) is in the coordinator's notes and goes in the doc as given. After: warm build, then `touch plum-checker/src/lib.rs` → time `cargo build --workspace --tests`; `touch plum-wasm-codegen/src/lib.rs` → same; `touch plum-core/src/ast.rs` → time `cargo build -p plum-cli`; count test executables in target/debug/deps; `uptime`. Also run every test binary and `target/debug/plum test plum-std plum-examples` (662).
|
|
89
|
+
**Test code:** results table before/after; all green.
|
|
90
|
+
|
|
91
|
+
## Review Focus
|
|
92
|
+
- B: state — no test lost (counts before == after per crate); fixture paths still resolve.
|
docs/plans/2026-11-05-build-speed.results.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Build speed results (2026-11-05)
|
|
2
|
+
|
|
3
|
+
| Edit, then build | Before | After |
|
|
4
|
+
|---|---|---|
|
|
5
|
+
| `touch plum-checker/src/lib.rs` → `cargo build --workspace --tests` | 17 s | 3 s |
|
|
6
|
+
| `touch plum-wasm-codegen/src/lib.rs` → `cargo build --workspace --tests` | 9 s | 4 s |
|
|
7
|
+
| `touch plum-core/src/ast.rs` → `cargo build -p plum-cli` | 13 s | 2 s |
|
|
8
|
+
| integration-test binaries | ~63 | 13 (one per crate + lib unit tests) |
|
|
9
|
+
|
|
10
|
+
Before at load ~9, after at load ~15 (so the after numbers are if anything pessimistic). Cold builds after `cargo clean-all` are unchanged by this work; they are now rare (AGENTS.md: clean only when under ~20 GB free).
|
|
11
|
+
|
|
12
|
+
## Changes
|
|
13
|
+
- `plum-cli/build.rs`: the nested `cargo build --release -p plum-lsp`, the `-O2` tree-sitter grammar `.so` and the npm VS Code client build run only with `PLUM_EMBED_EDITOR=1` (set by the Makefile.toml dist tasks); otherwise 0-byte placeholders, and `plum editor` says "this plum was built without editor assets; rebuild with PLUM_EMBED_EDITOR=1".
|
|
14
|
+
- Workspace `[profile.dev] debug = "line-tables-only"`.
|
|
15
|
+
- One integration-test binary per crate: `plum-core/tests/core` (381 tests), `plum-checker/tests/checker` (130), `plum-cli/tests/cli` (15), `plum-wasm-codegen/tests/wasm_codegen` (206; not `codegen`, which `.gitignore` excludes). Counts identical before and after.
|
|
16
|
+
- AGENTS.md disk rule: `cargo clean-all -y` only when `df -h /` shows under ~20 GB free.
|
|
17
|
+
|
|
18
|
+
## Sweep
|
|
19
|
+
All test binaries green; `plum test plum-std plum-examples` 662 passed, 65/65 files.
|
|
20
|
+
|
|
21
|
+
Running one test file now: `target/debug/deps/core-<hash> parser_test::` (filter by module path).
|
docs/plans/2026-11-05-language-simplification-d3.progress.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
- start d7658cc
|
|
2
|
+
Ruling: skip Wave 0 skeleton - removal run, no new interfaces - cost: none
|
|
3
|
+
Ruling: accept predicted 45.6 min - removal chain is forced (layer order) - cost: longer run
|
|
4
|
+
- unblocked: dispatched T1 T2 at Ruling: README/docs part of T7 pulled forward as fixer F-D3-1 (only README/docs, no overlap with T4-T6) - keeps lsp test green between tasks - cost: none
|
|
5
|
+
Ruling: README/docs part of T7 pulled forward as fixer F-D3-1 - keeps lsp test green - cost: none
|
|
6
|
+
Ruling: T3 touched loader.rs, scanner.c, arrays.plum, vscode-plum/* outside Owns - needed for the grammar removal to stay green - cost: none
|
|
7
|
+
Ruling: D3 loop regression (for-over-List +75%, Range +33%; cause: Some cell per next() step) - niche Option layout moves up to right after the build-speed task, ahead of explicit fn generics - core loops matter more than queue order - cost: generics slip one item
|
|
8
|
+
Ruling: final-review vscode/progress "blocked, nothing saved" - checkpoint refusals are bookkeeping; edits are in the working tree (git diff shows them); real leftover (?: and ?. highlight rules) sent to F-D3-2 - cost: none
|
|
9
|
+
Ruling: final-review error_union_tests coverage - 12 deleted tests were error-set/catch/inferred-set only except try_on_type_param_static (live `?` on T.static) -> twin in F-D3-2 - cost: none
|
|
10
|
+
Ruling: final-review "no test summary" - T8 ran all 62 binaries (777 passed) + plum sweep 662 + corpus green - cost: none
|
|
11
|
+
Ruling: final-review loop regression - accepted for D3 commit; fixed next (niche Option layout after build-speed task) - cost: loops slower until then
|
plum-checker/tests/{checker_tests.rs → checker/checker_tests.rs}
RENAMED
|
File without changes
|
plum-checker/tests/{closure_hint_test.rs → checker/closure_hint_test.rs}
RENAMED
|
File without changes
|
plum-checker/tests/{features → checker/features}/closure_types.rs
RENAMED
|
File without changes
|
plum-checker/tests/{features → checker/features}/io_capability.rs
RENAMED
|
File without changes
|
plum-checker/tests/{features/main.rs → checker/features/mod.rs}
RENAMED
|
File without changes
|
plum-checker/tests/{features → checker/features}/mutability.rs
RENAMED
|
File without changes
|
plum-checker/tests/{features → checker/features}/optional_unpinned.rs
RENAMED
|
File without changes
|
plum-checker/tests/{features → checker/features}/pattern_casing.rs
RENAMED
|
File without changes
|
plum-checker/tests/{features → checker/features}/primitive_generics.rs
RENAMED
|
File without changes
|
plum-checker/tests/{features → checker/features}/types.rs
RENAMED
|
File without changes
|
plum-checker/tests/{features → checker/features}/variant_pattern.rs
RENAMED
|
File without changes
|
plum-checker/tests/{fusion_pipeline_test.rs → checker/fusion_pipeline_test.rs}
RENAMED
|
File without changes
|
plum-checker/tests/{inline_variants_tests.rs → checker/inline_variants_tests.rs}
RENAMED
|
File without changes
|
plum-checker/tests/checker/main.rs
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#![allow(non_snake_case)]
|
|
2
|
+
//! Single integration-test binary for plum-checker (one link instead of one per file).
|
|
3
|
+
mod checker_tests;
|
|
4
|
+
mod closure_hint_test;
|
|
5
|
+
mod features;
|
|
6
|
+
mod fusion_pipeline_test;
|
|
7
|
+
mod inline_variants_tests;
|
|
8
|
+
mod question_tests;
|
|
9
|
+
mod subtyping_tests;
|
plum-checker/tests/{question_tests.rs → checker/question_tests.rs}
RENAMED
|
File without changes
|
plum-checker/tests/{subtyping_tests.rs → checker/subtyping_tests.rs}
RENAMED
|
File without changes
|
plum-cli/build.rs
CHANGED
|
@@ -32,6 +32,23 @@ fn main() {
|
|
|
32
32
|
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
|
|
33
33
|
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
|
|
34
34
|
|
|
35
|
+
println!("cargo:rerun-if-env-changed=PLUM_EMBED_EDITOR");
|
|
36
|
+
// Editor assets (nested plum-lsp release build, parser.c -O2, npm) are slow
|
|
37
|
+
// and only matter for distributed binaries: dev builds embed empty
|
|
38
|
+
// placeholders unless PLUM_EMBED_EDITOR=1.
|
|
39
|
+
if env::var("PLUM_EMBED_EDITOR").as_deref() != Ok("1") {
|
|
40
|
+
for (name, file) in [
|
|
41
|
+
("PLUM_GRAMMAR_SO", "plum-grammar.so"),
|
|
42
|
+
("PLUM_LSP_BIN", if cfg!(windows) { "plum-lsp.exe" } else { "plum-lsp" }),
|
|
43
|
+
("PLUM_VSCODE_EXTENSION_JS", "vscode-extension.js"),
|
|
44
|
+
] {
|
|
45
|
+
let path = out_dir.join(file);
|
|
46
|
+
std::fs::write(&path, []).expect("failed to write placeholder editor asset");
|
|
47
|
+
println!("cargo:rustc-env={name}={}", path.display());
|
|
48
|
+
}
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
35
52
|
buildGrammarSo(&manifest_dir, &out_dir);
|
|
36
53
|
buildPlumLsp(&manifest_dir, &out_dir);
|
|
37
54
|
buildVscodeExtensionClient(&manifest_dir, &out_dir);
|
plum-cli/src/editor.rs
CHANGED
|
@@ -123,7 +123,12 @@ fn writeExecutable(path: &Path, bytes: &[u8]) -> Result<()> {
|
|
|
123
123
|
Ok(())
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
const NO_EDITOR_ASSETS: &str = "this plum was built without editor assets; rebuild with PLUM_EMBED_EDITOR=1 for the language server and precompiled grammar";
|
|
127
|
+
|
|
126
128
|
fn installHelix() -> Result<()> {
|
|
129
|
+
if PLUM_LSP_BIN.is_empty() {
|
|
130
|
+
eprintln!("note: {NO_EDITOR_ASSETS}");
|
|
131
|
+
}
|
|
127
132
|
let config_dir = helixConfigDir()?;
|
|
128
133
|
fs::create_dir_all(&config_dir)
|
|
129
134
|
.with_context(|| format!("failed to create {}", config_dir.display()))?;
|
|
@@ -447,7 +452,7 @@ fn installVscode(insiders: bool) -> Result<()> {
|
|
|
447
452
|
writeExecutable(&server_dir.join(bin_name), PLUM_LSP_BIN)?;
|
|
448
453
|
println!("installed plum-lsp language server support");
|
|
449
454
|
} else {
|
|
450
|
-
println!("
|
|
455
|
+
println!("note: {NO_EDITOR_ASSETS}; installed syntax highlighting only");
|
|
451
456
|
}
|
|
452
457
|
|
|
453
458
|
println!(
|
plum-cli/tests/{assert_once_test.rs → cli/assert_once_test.rs}
RENAMED
|
File without changes
|
plum-cli/tests/{compile_tests.rs → cli/compile_tests.rs}
RENAMED
|
File without changes
|
plum-cli/tests/{crash_test.rs → cli/crash_test.rs}
RENAMED
|
File without changes
|
plum-cli/tests/{explain_layout_test.rs → cli/explain_layout_test.rs}
RENAMED
|
File without changes
|
plum-cli/tests/{game_web_test.rs → cli/game_web_test.rs}
RENAMED
|
File without changes
|
plum-cli/tests/{host_stub_test.rs → cli/host_stub_test.rs}
RENAMED
|
File without changes
|
plum-cli/tests/cli/main.rs
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#![allow(non_snake_case)]
|
|
2
|
+
//! Single integration-test binary for plum-cli (one link instead of one per file).
|
|
3
|
+
mod assert_once_test;
|
|
4
|
+
mod compile_tests;
|
|
5
|
+
mod crash_test;
|
|
6
|
+
mod explain_layout_test;
|
|
7
|
+
mod game_web_test;
|
|
8
|
+
mod host_stub_test;
|
|
9
|
+
mod test_scope_test;
|
plum-cli/tests/{test_scope_test.rs → cli/test_scope_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{closure_escape_test.rs → core/closure_escape_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{closure_spec_test.rs → core/closure_spec_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{closure_types_parse_test.rs → core/closure_types_parse_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{drive_test.rs → core/drive_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{for_next_test.rs → core/for_next_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{formatter_test.rs → core/formatter_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{forms_list_range_test.rs → core/forms_list_range_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{fused_closure_generic_test.rs → core/fused_closure_generic_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{generics_test.rs → core/generics_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{inline_variants_test.rs → core/inline_variants_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{layout_test.rs → core/layout_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{list_literal_test.rs → core/list_literal_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{loader_test.rs → core/loader_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{lower_test.rs → core/lower_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/core/main.rs
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
mod closure_escape_test;
|
|
2
|
+
mod closure_spec_test;
|
|
3
|
+
mod closure_types_parse_test;
|
|
4
|
+
mod drive_test;
|
|
5
|
+
mod for_next_test;
|
|
6
|
+
mod formatter_test;
|
|
7
|
+
mod forms_list_range_test;
|
|
8
|
+
mod fused_closure_generic_test;
|
|
9
|
+
mod generics_test;
|
|
10
|
+
mod inline_variants_test;
|
|
11
|
+
mod layout_test;
|
|
12
|
+
mod list_literal_test;
|
|
13
|
+
mod loader_test;
|
|
14
|
+
mod lower_test;
|
|
15
|
+
mod match_body_parse_test;
|
|
16
|
+
mod override_parse_test;
|
|
17
|
+
mod parser_test;
|
|
18
|
+
mod purity_test;
|
|
19
|
+
mod question_parse_test;
|
|
20
|
+
mod record_embed_test;
|
|
21
|
+
mod record_init_parse_test;
|
|
22
|
+
mod record_init_test;
|
|
23
|
+
mod rename_test;
|
|
24
|
+
mod session_test;
|
|
25
|
+
mod simplify_test;
|
|
26
|
+
mod subtyping_test;
|
|
27
|
+
mod tail_test;
|
|
28
|
+
mod tests_lower_test;
|
|
29
|
+
mod trmc_test;
|
|
30
|
+
mod unions_test;
|
|
31
|
+
mod uniqueness_test;
|
|
32
|
+
mod visit_test;
|
|
33
|
+
mod whistle_test;
|
plum-core/tests/{match_body_parse_test.rs → core/match_body_parse_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{override_parse_test.rs → core/override_parse_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{parser_test.rs → core/parser_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{purity_test.rs → core/purity_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{question_parse_test.rs → core/question_parse_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{record_embed_test.rs → core/record_embed_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{record_init_parse_test.rs → core/record_init_parse_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{record_init_test.rs → core/record_init_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{rename_test.rs → core/rename_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{session_test.rs → core/session_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{simplify_test.rs → core/simplify_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{subtyping_test.rs → core/subtyping_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{tail_test.rs → core/tail_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{tests_lower_test.rs → core/tests_lower_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{trmc_test.rs → core/trmc_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{unions_test.rs → core/unions_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{uniqueness_test.rs → core/uniqueness_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{visit_test.rs → core/visit_test.rs}
RENAMED
|
File without changes
|
plum-core/tests/{whistle_test.rs → core/whistle_test.rs}
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{codegen_tests.rs → wasm_codegen/codegen_tests.rs}
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{e2e_mem/main.rs → wasm_codegen/e2e_mem/mod.rs}
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{e2e_mem → wasm_codegen/e2e_mem}/reuse.rs
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{e2e_mem → wasm_codegen/e2e_mem}/unique_inplace.rs
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{e2e_mem → wasm_codegen/e2e_mem}/unique_spread.rs
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{e2e_records → wasm_codegen/e2e_records}/empty_record_embed.rs
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{e2e_records → wasm_codegen/e2e_records}/enum_init.rs
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{e2e_records → wasm_codegen/e2e_records}/inline_variants.rs
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{e2e_records/main.rs → wasm_codegen/e2e_records/mod.rs}
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{e2e_records → wasm_codegen/e2e_records}/record_embed.rs
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{e2e_records → wasm_codegen/e2e_records}/record_init.rs
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{e2e_records → wasm_codegen/e2e_records}/unboxed_variants.rs
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{e2e_tail → wasm_codegen/e2e_tail}/closure_tail.rs
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{e2e_tail → wasm_codegen/e2e_tail}/error_tail.rs
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{e2e_tail → wasm_codegen/e2e_tail}/loop_break.rs
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{e2e_tail/main.rs → wasm_codegen/e2e_tail/mod.rs}
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{e2e_tail → wasm_codegen/e2e_tail}/tail.rs
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{e2e_types → wasm_codegen/e2e_types}/closure_optional.rs
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{e2e_types → wasm_codegen/e2e_types}/closure_types.rs
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{e2e_types → wasm_codegen/e2e_types}/io_entry.rs
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{e2e_types → wasm_codegen/e2e_types}/list_and_shadow.rs
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{e2e_types/main.rs → wasm_codegen/e2e_types/mod.rs}
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{e2e_types → wasm_codegen/e2e_types}/question.rs
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{e2e_types → wasm_codegen/e2e_types}/subtyping.rs
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{e2e_types → wasm_codegen/e2e_types}/type_param_static.rs
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{examples_test.rs → wasm_codegen/examples_test.rs}
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/{fusion_alloc_test.rs → wasm_codegen/fusion_alloc_test.rs}
RENAMED
|
File without changes
|
plum-wasm-codegen/tests/wasm_codegen/main.rs
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#![allow(non_snake_case)]
|
|
2
|
+
//! Single integration-test binary for plum-wasm-codegen (one link instead of one per file).
|
|
3
|
+
mod codegen_tests;
|
|
4
|
+
mod e2e_mem;
|
|
5
|
+
mod e2e_records;
|
|
6
|
+
mod e2e_tail;
|
|
7
|
+
mod e2e_types;
|
|
8
|
+
mod examples_test;
|
|
9
|
+
mod fusion_alloc_test;
|