A parameterless procedural value is only callable bare as an identifier
Measured
x86-64, HEAD, 2026-09-04. Four spellings, one compiler run each.
| statement | shape | result |
|---|---|---|
m; |
plain variable, procedure of object |
accepted, prints |
m(); |
plain variable, empty parens | accepted, prints |
h.nul(); |
record FIELD, empty parens | accepted, prints |
h.nul; |
record FIELD, bare | error: expected ':=' before ';' |
h.p; |
record FIELD, plain procedure (no of object) |
error: expected ':=' before ';' |
a[0]; |
ARRAY element, procedure of object |
error: expected ':=' before ';' |
The last three all report at the ;, with the context near: ... h . p >>> ; end .
— the statement parser has taken the designator as an assignment target and is
waiting for :=.
The boundary is not what the first example suggested
The shape turned up as h.nul; in a method-pointer test, so the obvious title
was "a method-pointer field cannot be called bare". Both halves of that are
wrong, and removing each named feature is what showed it:
- drop
of object—h.p;forp: procedurein a record fails identically, so it is not about method pointers; - drop the field —
a[0];for an array ofprocedure of objectfails identically, so it is not about record fields.
What survives both removals is: the designator is not a bare identifier.
m; is the only accepted no-parens form.
Why it is filed rather than patched
Same reason as [[bug-p-member-access-on-a-procedural-variable-call-result-is-rejected]],
and probably the same code: the statement-level path recognises the
simple-identifier spelling of a procedural value and the other spellings are
built at the several AllocNode(AN_CALL_IND) sites, each of which decides for
itself. Adding the no-parens case at whichever site produced this symptom is
the arm that stays broken — normalise-dont-special-case before the microfix
rather than after.
FPC accepts all six rows, and real Pascal writes OnClick; far more often than
OnClick(), so this is a compat item with actual source behind it rather than
an edge case only a probe reaches.
Not a blocker for the test that found it
test/test_cross_method_pointer_call.pas uses h.nul() and says in its header
why, with this slug. When this is fixed, that test is the natural place to add
the bare rows.
Log
- 2026-09-04 | frankA | filed while writing the wasm32 method-pointer cross test
(
99fa70c34). Not on the wasm32 path at all — every row above was measured on the x86-64 build. - 2026-09-04 — resolved; this names the commit that carried the resolve, which is not always the one that carried the change — commit 44c08dc66.