|
@@ -1,107 +1,100 @@
|
|
|
-# Next session — handoff (2026-10-18)
|
|
|
|
|
|
|
+# Next session — plan
|
|
|
|
|
|
|
|
-State: branch **`resolve-check`**, tree clean. Suite **239/239**,
|
|
|
|
|
-fixpoint **OK (3,812,771 bytes)**, corpus **405/612, 0 crashes**.
|
|
|
|
|
-Tags include `v3-enum-import`, `v3-ordl`, `v3-showcase24`,
|
|
|
|
|
-`v3-convert`, `v3-set-word`, `v3-strict-decl-order`, `v3-m2-conformance`,
|
|
|
|
|
-`v3-gap-examples`.
|
|
|
|
|
|
|
+**Branch state (2026-10-18):** `master` and `resolve-check` are both at
|
|
|
|
|
+`95ca4d6` (merged, fast-forward) and pushed to `origin`. Work on
|
|
|
|
|
+`master`.
|
|
|
|
|
|
|
|
-## Policy (decided)
|
|
|
|
|
|
|
+**Baseline:** suite **239/239**, fixpoint **OK (3,812,771 bytes)**,
|
|
|
|
|
+corpus **405/612, 0 crashes**. The corpus harness resolves transitive
|
|
|
|
|
+imports (method from 2026-10-18).
|
|
|
|
|
|
|
|
-Follow **Modula-2**, not gm2 degradation: declaration before use (only a
|
|
|
|
|
-`POINTER`'s base may forward-reference). `docs/gaps/` classifies every
|
|
|
|
|
-remaining case; **`decl-order` and `gm2-ext` are not targets** (gm2
|
|
|
|
|
-accepts non-conforming code; V3 correctly rejects it). The corpus is
|
|
|
|
|
-gm2's testsuite, so its number mixes both; the **`undeclared identifier`
|
|
|
|
|
-bucket (44) is now inflated by the decl-order files** — don't chase it
|
|
|
|
|
-blindly.
|
|
|
|
|
|
|
+**Policy:** follow **Modula-2**, not gm2 degradation — declaration
|
|
|
|
|
+before use (only a `POINTER`'s base may forward-reference). In
|
|
|
|
|
+`docs/gaps/`, the `decl-order` and `gm2-ext` classes are **not targets**;
|
|
|
|
|
+the 44-file "undeclared identifier" bucket is inflated by them.
|
|
|
|
|
|
|
|
-The corpus harness now resolves **transitive** imports (2026-10-18); that
|
|
|
|
|
-is the measurement method from here.
|
|
|
|
|
|
|
+---
|
|
|
|
|
|
|
|
-## P0 — generics: two instantiations of one generic (a real bug)
|
|
|
|
|
|
|
+## P0 — generics: two instantiations of one generic (real bug, do first)
|
|
|
|
|
|
|
|
-`analysis_gaps.md` §10: instantiating one generic twice with arguments
|
|
|
|
|
-from different families fails on the second instantiation
|
|
|
|
|
-(`GStack(INTEGER)` + `GStack(CHAR)` → `incompatible assignment` at
|
|
|
|
|
-`n^.val := v`); `INTEGER`+`CARDINAL` passes only because the wrong
|
|
|
|
|
-binding still type-checks. Each type argument alone works.
|
|
|
|
|
|
|
+Instantiating one generic twice with arguments from different families
|
|
|
|
|
+fails on the second instantiation:
|
|
|
|
|
|
|
|
-**Likely culprit:** `SymTab.EnterTypeParamBound` (SymTab.mod ~line 675):
|
|
|
|
|
|
|
+```mod
|
|
|
|
|
+GENERIC DEFINITION MODULE GStack (T : TYPE);
|
|
|
|
|
+TYPE NodeRec = RECORD val : T; next : Node END; ...
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+`GStack(CHAR)` alone works; `GStack(INTEGER)` alone works; together,
|
|
|
|
|
+the second fails (`incompatible assignment` at `n^.val := v`).
|
|
|
|
|
+`INTEGER` + `CARDINAL` appears to pass only because the stale binding
|
|
|
|
|
+still type-checks.
|
|
|
|
|
+
|
|
|
|
|
+**Likely culprit:** `SymTab.EnterTypeParamBound` returns early when the
|
|
|
|
|
+formal is already visible, so the first instantiation's binding sticks:
|
|
|
|
|
|
|
|
```mod
|
|
```mod
|
|
|
IF Lookup(name) AND (SymKind(name) = KindType) THEN RETURN TRUE END;
|
|
IF Lookup(name) AND (SymKind(name) = KindType) THEN RETURN TRUE END;
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-During an instantiation re-parse the formal is already visible, so it
|
|
|
|
|
-returns **without rebinding** to the new actual — the first
|
|
|
|
|
-instantiation's binding sticks.
|
|
|
|
|
-
|
|
|
|
|
-*First steps:* reproduce with a five-file session (`GBox(T)` generic
|
|
|
|
|
-def/mod + two instantiations + a program); check how the driver
|
|
|
|
|
-establishes the scope for each re-parse (`InstBegin`/`Reenter`, compiler
|
|
|
|
|
-frame); make the formal binding per-instantiation (fresh alias), then
|
|
|
|
|
-add a regression test (two instantiations, distinct scalar families) and
|
|
|
|
|
-re-run fixpoint (generics are used in the compiler's own generics
|
|
|
|
|
-tests, not its source).
|
|
|
|
|
|
|
+*Steps:* five-file repro (generic def/mod + two instantiations + a
|
|
|
|
|
+program); make the substitution per-instantiation (fresh alias); add a
|
|
|
|
|
+regression test with two distinct scalar families; keep the fixpoint
|
|
|
|
|
+green.
|
|
|
|
|
|
|
|
## P1 — quick, bounded corpus wins
|
|
## P1 — quick, bounded corpus wins
|
|
|
|
|
|
|
|
-- **`gap22` `__FILE__`/`__LINE__`** (`packed`): gm2 predefined
|
|
|
|
|
- constants; `__`/`_` are not legal identifier chars in V3. Either add
|
|
|
|
|
- the two pseudo-constants or leave as `gm2-ext` (+1 file).
|
|
|
|
|
-- **`gap09` scalar actual into `ARRAY OF BYTE`** (gm2's untyped byte
|
|
|
|
|
- buffer; `aochar`, `arrayofbyte`, `bytearray`): accept a scalar/
|
|
|
|
|
- `ADDRESS` actual for an `ARRAY OF BYTE`/`VAR ARRAY OF BYTE` formal by
|
|
|
|
|
- passing its address (+ ~3 files).
|
|
|
|
|
-- **`gap16`/`gap17` set span**: raise the cap / handle `SET OF CARDINAL`
|
|
|
|
|
- (low value).
|
|
|
|
|
-
|
|
|
|
|
-## P2 — structural (parser / semantics)
|
|
|
|
|
-
|
|
|
|
|
-- **`gap12` variant records**: empty variant arms, `ELSE`, untagged
|
|
|
|
|
- inner `CASE` (`varient2/3/8`, `tsize`/`2`).
|
|
|
|
|
-- **`gap11` bare procedure value as a statement** (`tinyproc2/4`).
|
|
|
|
|
-- **`gap10` `VAR` actual type leniency** (gm2 same-size rule;
|
|
|
|
|
- `testparam2/3`) — decide whether to adopt it (non-standard).
|
|
|
|
|
-- **`gap13` remainder**: the *standard* built-ins (`ORD`, `CHR`, `VAL`,
|
|
|
|
|
- `MOD`, …) are still Coco/R keyword tokens; de-reserving them needs
|
|
|
|
|
- contextual-keyword parsing (predeclared identifiers). `ORDL` (the
|
|
|
|
|
- corpus case) is done.
|
|
|
|
|
-- **`gap18` set-typed `CASE` labels** (`bitset5`).
|
|
|
|
|
|
|
+- **`gap22` `__FILE__`/`__LINE__`** (`packed`, +1).
|
|
|
|
|
+- **`gap09` scalar actual → `ARRAY OF BYTE`** (`aochar`,
|
|
|
|
|
+ `arrayofbyte`, `bytearray`, +~3).
|
|
|
|
|
+
|
|
|
|
|
+## P2 — structural
|
|
|
|
|
+
|
|
|
|
|
+- **`gap12`** variant records: empty arms, `ELSE`, untagged inner
|
|
|
|
|
+ `CASE` (5 files).
|
|
|
|
|
+- **`gap11`** bare procedure value as a statement.
|
|
|
|
|
+- **`gap10`** `VAR`-param type leniency (decide whether to adopt gm2's
|
|
|
|
|
+ same-size rule — non-standard).
|
|
|
|
|
+- **`gap13` remainder**: de-reserve the *standard* builtins (`ORD`,
|
|
|
|
|
+ `CHR`, `VAL`, …) — contextual-keyword parser refactor (`ORDL` is done).
|
|
|
|
|
+- **`gap18`** set-typed `CASE` labels.
|
|
|
|
|
|
|
|
## P3 — conformance remainder (architectural)
|
|
## P3 — conformance remainder (architectural)
|
|
|
|
|
|
|
|
Forward references to module-level **variables/procedures** from a
|
|
Forward references to module-level **variables/procedures** from a
|
|
|
procedure body still work (the two-phase parse defers bodies). Strict
|
|
procedure body still work (the two-phase parse defers bodies). Strict
|
|
|
-declaration-before-use would require order-aware body checking; decide
|
|
|
|
|
-whether to pursue (high risk, touches self-hosting). The declaration
|
|
|
|
|
-part itself is already strict.
|
|
|
|
|
|
|
+declaration-before-use would require order-aware body checking; high
|
|
|
|
|
+risk, touches self-hosting. The declaration part is already strict.
|
|
|
|
|
|
|
|
## P4 — latent correctness
|
|
## P4 — latent correctness
|
|
|
|
|
|
|
|
-The **size-sensitive V3 miscompile** (historical "removing `ASTDUMP`
|
|
|
|
|
-breaks the fixpoint") is still unroot-caused. Worth a dedicated
|
|
|
|
|
-bisection session: it is a correctness landmine, unlike the remaining
|
|
|
|
|
-language gaps.
|
|
|
|
|
|
|
+The **size-sensitive V3 miscompile** ("removing `ASTDUMP` breaks the
|
|
|
|
|
+fixpoint") is still unroot-caused. Dedicated bisection session; a real
|
|
|
|
|
+correctness landmine.
|
|
|
|
|
|
|
|
## P5 — housekeeping
|
|
## P5 — housekeeping
|
|
|
|
|
|
|
|
- Consolidate `docs/summary_*.md` (see `docs/INDEX.md`).
|
|
- Consolidate `docs/summary_*.md` (see `docs/INDEX.md`).
|
|
|
-- Decide merge/push of `resolve-check` (no pushes so far).
|
|
|
|
|
|
|
+- (Merge of `resolve-check` → `master`: **done**.)
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
|
|
|
## Gates for every step
|
|
## Gates for every step
|
|
|
|
|
|
|
|
-`./build.sh`, `./run_tests.sh` (must stay 100%), `bootstrap/fixpoint.sh`
|
|
|
|
|
-(**byte-identical**), `corpusx.sh` (record OK/CRASH + note), update
|
|
|
|
|
-`docs/gaps/` + `STATUS`/`README`, commit with a `v3-*` tag.
|
|
|
|
|
|
|
+`compiler/build.sh` → `compiler/run_tests.sh` (must stay 100%) →
|
|
|
|
|
+`bootstrap/fixpoint.sh` (**byte-identical**) → `corpusx.sh` (record
|
|
|
|
|
+OK/CRASH + note) → update `docs/gaps/` + `STATUS`/`README` → commit with
|
|
|
|
|
+a `v3-*` tag.
|
|
|
|
|
|
|
|
## Resume
|
|
## Resume
|
|
|
|
|
|
|
|
```sh
|
|
```sh
|
|
|
cd .../m2compiler-V3
|
|
cd .../m2compiler-V3
|
|
|
-git checkout resolve-check
|
|
|
|
|
|
|
+git checkout master
|
|
|
cd compiler && ./build.sh && ./run_tests.sh # 239/239
|
|
cd compiler && ./build.sh && ./run_tests.sh # 239/239
|
|
|
cd .. && TMP="$PWD/.scratch/fixpoint" ./bootstrap/fixpoint.sh
|
|
cd .. && TMP="$PWD/.scratch/fixpoint" ./bootstrap/fixpoint.sh
|
|
|
M2FLAGS="" ./.scratch/corpusx.sh # 405 OK, 0 crash
|
|
M2FLAGS="" ./.scratch/corpusx.sh # 405 OK, 0 crash
|
|
|
```
|
|
```
|
|
|
|
|
+
|
|
|
|
|
+**Recommendation:** P0 first (a real defect), then two P1 wins, and
|
|
|
|
|
+reserve a separate session for P4.
|