← board

N an inline cast's ^ chain answers every deref from the cast's alias

The code, verbatim, in both files

if CurTok.Kind = tkCaret then
begin
  Next;
  indexNode := AllocNode(AN_DEREF);
  ASTLeft[indexNode] := node;
  { After ^, type becomes the pointee }
  tk      := IntToTypeKind(AliasElemTk[aliasIdx]);
  recName := AliasElemRec[aliasIdx];
  ASTTk[indexNode] := StrValTk(tk);
  node := indexNode;
end

aliasIdx is the alias of the cast that OPENED the chain and never changes, so every ^ in the chain is answered from it. By the second ^ in PRec(raw)^.n^ the node is the field n, not the cast — and n's pointee is not PRec's.

Why it is worth fixing even though the bytes are right

The deref is applied; only the resulting TYPE TAG is wrong. On the Pascal side that meant Writeln printed a string's heap address as an integer, while the same chain with the cast parked in a variable printed the string — two spellings of one expression disagreeing, with no diagnostic. A ^Int64 field through the same cast looked fine because the wrong tag happened to match. That is this repo's expensive failure mode, not a crash.

Fix — take the Pascal one, do not write a new one

The Pascal fix was deliberately NOT made at the call site. It extended the shared NodePtrElem predicate (compiler/pasparser_lval.inc) with the two spellings it did not know — a pointer FIELD (UFldPtrElem* via ResolveNodeRec) and an inline AN_PTR_CAST (the alias, guarding the negative adapter markers) — and the caret arm then asks the predicate about the CURRENT node, falling back to aliasIdx only when it has no answer (which is what the -1/-2 adapter casts need). NodePtrElem is shared, so N gets the predicate for free and only the caret arm needs changing.

Copy test/test_cast_deref_pointer_field.pas and test/test_cast_deref_chain_siblings.pas into the .npy suite in whatever spelling NilPy reaches this path with. First establish that NilPy can reach it at all — if no NilPy program can express the chain, this is dead code in that file and the right outcome is deleting it, not porting a fix into it.

Gate

make test-nilpy green + self-host byte-identical, per Track N's lane rules.