← board

A nested routine cannot capture a fixed-size array

Repro

procedure Outer;
var a: array[0..3] of Boolean;
  procedure Inner(i: Integer);
  begin
    if a[i] then WriteLn('x');       { <- refused }
  end;
begin
  a[0] := True; Inner(0);
end;
pascal26:N: error: nested routine: capture of fixed-size array 'a' not yet supported

A dynamic array in the same position compiles and works.

Where

compiler/pasparser_decl.inc:6701. Capture lifts the nested routine to top level and passes each captured local as a by-reference parameter, described by capTk / capRec / capArr / capDyn. The dynamic arm sets capArr := True; capDyn := SymDynDepth[sidx]. A fixed array has no capDyn and the descriptor set has no slot for its ArrLen / ConstVal (low bound), so the lifted parameter could be declared but not indexed correctly — hence the honest refusal rather than a wrong lowering.

Fix sketch

Add capArrLen / capArrLo alongside the existing descriptors, populate from Syms[sidx].ArrLen / Syms[sidx].ConstVal, and have the lifted-parameter synthesis emit a fixed-array var param. Three touch points: the capture descriptor here, the synthesized declaration, and the call-site argument. The refusal must stay for any shape the third point cannot express — a wrong lowering here indexes the caller's frame.

Gate

make compiler/pascal26 + the repro above compiling and printing x, + a control where the nested routine WRITES through the captured fixed array and the caller observes it (by-reference capture, not a copy), + a multi-dimensional and a non-zero-low-bound case (array[1..3]), since the low bound is the field the current descriptor set is missing.


Resolution (frankS, 2026-08-31) — a duplicate, and only three quarters of the gate

This is the same bug as feature-nested-routine-fixed-array-capture, filed 2026-07-11 from Track B. I filed this one on 2026-08-30 without noticing, then implemented it on 2026-08-31 concurrently with another Track A session that had taken the older slug — so the same bug was worked three times before anyone looked at the other's ticket. That is the finding worth keeping here, more than the fix: two of the three collisions were searchable. The older ticket's title says "fixed-size array", this one's says "fixed-size array", and neither ready nor next deduplicates by subject.

The fix landed under the other slug and matches this ticket's own fix sketch almost line for line (LiftCapFixedLen / LiftCapFixedLo alongside the existing capTk/capArr/capDyn descriptors, populated from Syms[].ArrLen / Syms[].ConstVal, replayed onto the lifted param's pFixedLen/pFixedLo).

Against this ticket's Gate, item by item

gate item status
the repro compiles and prints x met — verified at HEAD
nested routine WRITES through the capture, caller observes it metReadWrite and ParamCapture rows
non-zero low bound (array[1..3]) metLowBound row; this is the half that fails silently, exactly as this ticket predicted
multi-dimensional NOT met — still refused

The multi-dimensional refusal is deliberate and now says so:

error: nested routine: capture of multi-dimensional array 'a' not yet
supported (1-D fixed arrays are)

Nothing in either ticket's acceptance asked for it and no caller wants it: the lift channel would need a SHAPE, not just a length and a bound. Not re-filed — the diagnostic names the boundary, which is what a reader hitting it needs.

What this unblocks

refactor-a-the-durable-param-row-is-hand-copied-on-three-registration-paths, which is why I filed this in the first place: its 21 fixed-size staging arrays are the exact thing a nested helper needs to see, and the reshaping the refusal forced (a 23-arg signature of same-typed var array params, where a transposition type-checks) was a new fail-silent traded for an old one. That trade is off the table now.

Log