|
|
@@ -225,4 +225,30 @@ Measured while scaffolding (branch `resolve-check`):
|
|
|
statement checks moved out of the actions, i.e. the walk, still
|
|
|
blocked on `Lower`'s type/emit split.
|
|
|
|
|
|
+- **2026-10-15 (`5703b27`, step 4a)** — expression types are now stored
|
|
|
+ on the AST (`SetTy` at the Expr/SimExpr/Term/Fact levels). Findings
|
|
|
+ that shape the split:
|
|
|
+ - `Lower.LowerExprFull` **constructs** types while emitting
|
|
|
+ (`NewStr`/`NewUStr`/`NewSet`/`NewSubR`) and those do **not** dedup
|
|
|
+ (`NewDesc` always allocates). A type must therefore be constructed
|
|
|
+ exactly once and cached on the node; the parser *already* computes
|
|
|
+ (and for literals constructs) the same type at parse time — now
|
|
|
+ stored — so `Lower` can read `AST.Ty(n)` instead of reconstructing,
|
|
|
+ which also removes a duplicate construction per string/set literal.
|
|
|
+ - `AST.Ty` defaults to `-1` (= `InvalidType`), so "unset/unknown" is
|
|
|
+ distinguishable from a real index; `Lower` can read it with a
|
|
|
+ fallback while the split is in progress.
|
|
|
+ - the forward **tolerance is a tested feature**: `tests/t_fwdvar.mod`
|
|
|
+ (and `Showcase22`) rely on a procedure body referencing a
|
|
|
+ module-level variable declared later — including through an
|
|
|
+ **array-index selector** (`label[0] := "o"`). An experiment that
|
|
|
+ replaced the tolerance with an immediate 201 failed exactly those
|
|
|
+ two tests. So `FwdVar*` can only go once `Design`'s binding is
|
|
|
+ genuinely late, and the walk must keep forward refs *with selectors*.
|
|
|
+ - **the missing piece of the split** is a designator *resolver*: the
|
|
|
+ type half of `LowerDesign` (~line 690), which `Check` would run
|
|
|
+ after resolving forward references and store on the node
|
|
|
+ (`AST.SetTy`) for `Lower` to read. Designator nodes are the only
|
|
|
+ expressions whose parse-time type is `-1` (forward/undefined).
|
|
|
+
|
|
|
|