|
|
@@ -0,0 +1,92 @@
|
|
|
+# Session summary — 2026-10-15: the resolve/check pass
|
|
|
+
|
|
|
+Branch **`resolve-check`** (off `generics-inc1` / `6639c19`).
|
|
|
+Suite **193/193**; fixpoint **OK** (**3,491,608 bytes**); tree clean.
|
|
|
+
|
|
|
+Tags: `v3-resolve-check-step1` … `step4d`,
|
|
|
+`v3-two-phase-parse-plan`.
|
|
|
+
|
|
|
+## What the thread set out to do
|
|
|
+
|
|
|
+Split semantic analysis out of the grammar's parse-time actions into a
|
|
|
+post-parse pass (`Check`), so that identifier binding happens *after* a
|
|
|
+unit's declarations are known — which is what the forward-reference
|
|
|
+machinery (`FwdVar*`, `IsFwdVar`, the `Design` forward branch) exists to
|
|
|
+work around.
|
|
|
+
|
|
|
+## What landed (all green at each step)
|
|
|
+
|
|
|
+| Step | Commit | What |
|
|
|
+| --- | --- | --- |
|
|
|
+| 1 | `50df067` | `Check.def/.mod` scaffold (`Resolve`), called by the driver between `Parse` and `Lower`, gated by `-noresolve`. No-op; byte-identical. |
|
|
|
+| 2 | `f34ca98` | Forward *resolution* moved into `Check` (`NoteForward`/`FlushForward`); made scope-independent (`SymTab.fwdVarScope` + `FindScope`) so it can run post-parse. `FwdVarType` deleted. |
|
|
|
+| 3 | `7ca434b` | The forward operand is now `InvalidType`, so the generic "skip checks on an unknown type" rule replaces the purpose-built leniency. Deleted `SymTab.IsFwdVar`, the `fwdVarT` table and all five guards; `FwdVarRef` no longer allocates a placeholder. |
|
|
|
+| 4a | `5703b27` | Expression nodes now store their type (`SetTy` at the Expr/SimExpr/Term/Fact levels). |
|
|
|
+| 4b | `192ad55` | `Check` resolves a **forward designator's** full type (base symbol + selectors via `SelType`) and stores it on the node. |
|
|
|
+| 4c | `9dc2ed7` | Resolved types **propagate up** the expression tree (`PropNode`/`EvalExpr`); `Lower` reads the stored type for string/set literals (removes a duplicate construction). |
|
|
|
+| 4d | `8efae2e` | A **forward-tainted assignment is now type-checked** — `n := "abc"` with a later `VAR n : INTEGER` was silently accepted. |
|
|
|
+
|
|
|
+New tests: `t_fwdsel.mod`, `t_fwdprop.mod`, `t_bad_fwd.mod` (expect_fail).
|
|
|
+
|
|
|
+## Findings worth keeping
|
|
|
+
|
|
|
+- **The AST is not a typed IR.** `NkArray`/`NkRecord`/`NkPointer`/
|
|
|
+ `NkEnum`/`NkTypeIdent`/`NkProcType` are never built; constructed types
|
|
|
+ live only in `SymTab`. So the original plan's "walk the type AST" had
|
|
|
+ nothing to walk — type-constructor checks stay parse-time.
|
|
|
+- **`Lower` constructs types while emitting** and `NewDesc` does not
|
|
|
+ dedup, so a type must be constructed once and cached on the node (the
|
|
|
+ parser already does, and `Lower` now reads it for literals).
|
|
|
+- **The forward tolerance is a tested feature** (`t_fwdvar`,
|
|
|
+ `t_fwdsel`, `t_fwdprop`, `Showcase22`), including through an
|
|
|
+ array-index selector.
|
|
|
+- **`FwdVar*` cannot be deleted by moving checks.** Even with every
|
|
|
+ check in the walk, `Design` must still *bind* a not-yet-declared name —
|
|
|
+ impossible in one pass. That needs a genuinely **two-phase parse**
|
|
|
+ (declarations before bodies). See `docs/plan-two-phase-parse.md`.
|
|
|
+- **The scanner's position model is quirky**: after `Get`, `sym` is the
|
|
|
+ token just scanned but `pos`/`len` describe the *previous* one
|
|
|
+ (`LexString` vs `LookAheadName`), and `Reset` does **not** reset
|
|
|
+ `pos`/`len`/`nextPos`/`nextLen`/`line`/`col`, so stale values leak
|
|
|
+ across files. Any mid-file restart must reproduce that state exactly.
|
|
|
+
|
|
|
+## Where the machinery lives now
|
|
|
+
|
|
|
+- `SymTab`: `FwdVarRef`/`FwdVarName`/`FwdVarResolve` — record (name,
|
|
|
+ kind, scope) and resolve by name; no placeholder, no leniency.
|
|
|
+- `Check`: `NoteForward`/`FlushForward` (resolve + store the designator
|
|
|
+ type), `SelType`, `EvalExpr`/`PropNode` (propagate), `CheckAssign`
|
|
|
+ (forward-tainted assignments).
|
|
|
+- Grammar: `Design`'s forward branch (`FwdVarRef` + `Check.NoteForward`,
|
|
|
+ `Op=1` marker on the node).
|
|
|
+- `Lower`: unchanged type computation except the literal cases.
|
|
|
+
|
|
|
+## Next steps (choices)
|
|
|
+
|
|
|
+1. **Implement the two-phase parse** (`docs/plan-two-phase-parse.md`),
|
|
|
+ then delete `FwdVar*`/`NoteForward`/`FlushForward` and the `Design`
|
|
|
+ forward branch. Recommended *start*: do the restart at the
|
|
|
+ **driver level** using the exported `Reset` + repeated `Get` (not new
|
|
|
+ scanner internals), add a small grammar **body-entry** production, and
|
|
|
+ **calibrate the stop point empirically** (encode observed `pos`/`len`
|
|
|
+ into the error channel). Largest piece in the thread; spans sessions.
|
|
|
+2. **Drop the non-standard tolerance** (a forward reference is a plain
|
|
|
+ `201`) and update the four tests that rely on it. Deletes the whole
|
|
|
+ mechanism for near-zero work, but is a language-semantics change.
|
|
|
+3. **Extend the touched-subtree checks** (control-flow conditions,
|
|
|
+ `RETURN`, call arity) — the same safe pattern as step 4d; more
|
|
|
+ forward-reference diagnostics, no parser change.
|
|
|
+4. **Stop** — the forward mechanism is clean, forward references are
|
|
|
+ typed and checked, and `FwdVar*` is a small, self-contained path.
|
|
|
+
|
|
|
+## Resume
|
|
|
+
|
|
|
+```sh
|
|
|
+cd .../m2compiler-V3
|
|
|
+git checkout resolve-check
|
|
|
+./bootstrap/fixpoint.sh # FIXPOINT OK
|
|
|
+cd compiler && ./build.sh && ./run_tests.sh # 193/193
|
|
|
+```
|
|
|
+
|
|
|
+Key docs: `docs/plan-resolve-check.md` (running record),
|
|
|
+`docs/plan-two-phase-parse.md` (design for step 1 above).
|