← board

@Proc / proc-value of a procedure-typed routine rejected ("unexpected token")

Symptom

A proc value whose target type is a procedure (no return) is rejected:

type TProc = procedure(x: Integer);
var p: TProc;
procedure Hello(x: Integer); begin writeln(x); end;
begin
  p := @Hello;     { pascal26: error: unexpected token () }
  p(5);
end.

The identical shape with a function type compiles and runs:

type TFn = function(x: Integer): Integer;
var p: TFn;
function Dbl(x: Integer): Integer; begin Dbl := x*2; end;
begin
  p := @Dbl;       { OK }
  writeln(p(5));   { 10 }
end.

Scope

Suggested next steps

  1. Diff how type T = function(...): R vs type T = procedure(...) register their signature (ProcSig/SymProcSig, param table) — the procedure form is probably missing a piece the @/assign path relies on.
  2. Minimal repro is the block above; add a procedure-typed proc-var test alongside the existing function-typed one once fixed.

Resolution (2026-06-22, Track A, commit e130d07)

Reframed — NOT a @procedure / proc-value bug. Procedure-typed proc values work fine (a non-colliding type name like TMyProc always compiled + called). The real cause was a name collision: the test type was named TProc, which the compiler reserves for an internal descriptor record (REC_TPROC, exposed for self-reflection). Type-name resolution checked the builtin record (IsRecordType) BEFORE the user alias (FindTypeAlias), so var p: TProc resolved to the builtin record (tyRecord), the proc var lost its signature, and the indirect call p(x) fell through to "unexpected token".

Fix: a user type X = ... alias now shadows a same-named builtin record (skip the builtin when a user alias of that name exists). FPC doesn't reserve these names. Only triggers on the user-alias-vs-builtin overlap; compiler.pas defines no such alias, so the builtins still resolve there -> self-host byte-identical, cross-bootstrap byte-identical. Test test/test_user_type_shadows_builtin.pas (matches FPC). Retires the "TProc-name collision landmine".

Log