Summary
DelphiAST cannot parse a syntactically valid unit where a generic class
constructor has a parameter whose type depends on the generic parameter and a
default value, e.g. constructor Create(AFinProc: TProc<T> = nil);.
Removing = nil makes the identical unit parse fine.
Minimal reproducer (Repr.pas)
unit Repr;
interface
uses
SysUtils;
type
C<T> = class
constructor Create(AFinProc: TProc<T> = nil);
end;
implementation
end.
How to reproduce with DelphiAST
program t;
{$APPTYPE CONSOLE}
uses
DelphiAST, DelphiAST.Classes;
var
AST: TSyntaxNode;
begin
try
AST := TPasSyntaxTreeBuilder.Run('Repr.pas', False);
Writeln('parsed OK');
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message); // parse error
end;
end.
Control (Ctrl.pas, parses fine — only = nil removed)
unit Ctrl;
interface
uses
SysUtils;
type
C<T> = class
constructor Create(AFinProc: TProc<T>);
end;
implementation
end.
Narrowing (all tested individually, only the failing combo fails)
- AFinProc: TProc<T> = nil (default on generic-typed param) → fails
- AFinProc: TProc<T> (no default) → parses
- FinType: Integer = 0 (default on non-generic param) → parses
- plain generic class / generic method / record with generic field / class helper /
untyped const/out param / BOM / {$IFDEF} / {$IF CompilerVersion<36} /
(* *) comments → all parse fine
Why it matters
I discovered this through a tool (delphi-indexer) that embeds DelphiAST: real
units using this pattern parse to 0 nodes and are silently dropped from the
index (e.g. TResHolder<T> = class(TInterfacedObject, IResHolder<T>) with
constructor Create(..., AFinProc: TProc<T> = nil);), leaving whole libraries
unsearchable. I assume the fault is in how the parser handles a default value
on a parameter whose type references the enclosing generic type.
Environment: Delphi 12.3 · DelphiAST current (bundled version in delphi-indexer).
Happy to help test a fix or provide the exact DelphiAST version/commit.
Summary
DelphiAST cannot parse a syntactically valid unit where a generic class
constructor has a parameter whose type depends on the generic parameter and a
default value, e.g.
constructor Create(AFinProc: TProc<T> = nil);.Removing
= nilmakes the identical unit parse fine.Minimal reproducer (
Repr.pas)