← board

Length/High of a static array used directly returns garbage

Symptom

Length(a) / High(a) on a static array variable referenced directly (not through an open-array parameter, not a dynamic array) returns garbage: Length = 0, High = -1, instead of the compile-time element count.

program p;
var f: array[0..2] of Integer;
begin
  WriteLn(Length(f));   { prints 0; expected 3 }
  WriteLn(High(f));     { prints -1; expected 2 }
end.

A dynamic array and an open-array parameter both work (they have a [data-8] length header). High is Length - 1, so both follow the same root cause.

Cause

The Length lowering (x86-64 IR: ir_codegen.inc, the tkLength block; and the per-target copies in ir_codegen386/arm32/aarch64/riscv32/xtensa.inc) handles managed strings, dynamic arrays, and open-array params (read [ptr-8]), then falls through to a generic else that does mov rax, [addr] — for a static array that loads the FIRST ELEMENT, not the length. A static array has no runtime length header; its length is a compile-time constant (Syms[idx].ArrLen, the first dimension for N-D).

Fix

Fold Length/High of a whole static array to a compile-time constant at parse time (parser.inc tkLength / tkHigh): when the argument lvalue is a whole static-array AN_IDENT (idx >= 0, Syms[idx].IsArray, ArrLen >= 0), emit an AN_INT_LIT of the element count instead of the -tkLength call. Parse-time folding fixes every backend at once and matches FPC (where it is a constant). Mind multi-dimensional static arrays: Length is the FIRST dimension's count, not total ArrLen — only fold when the dimension count is known (1-D, or use the first-dim span), else leave the runtime path.

Gate

make test (self-host byte-identical) + make cross-bootstrap. Add a test for Length/High of a 1-D static array (and, if handled, a 2-D one).

Fix log

Log