← board

Two generic templates cannot both declare a nested type of the same name

Repro

type
  generic TA<K, V> = class
  public type TPair = record aa: K; bb: V; end;
  private FA: array of TPair;
  public procedure Put(const a: K; const b: V);
  end;
  generic TB<K, V> = class
  public type TPair = record cc: K; dd: V; end;   { same nested NAME }
  private FA: array of TPair;
  public procedure Put(const a: K; const b: V);
  end;

TB.Put's FA[High(FA)].cc := apascal26: error: "cc": no such member on this record/class. TB's TPair resolved to TA's, whose fields are aa/bb. FPC 3.2.2 compiles and runs it (prints 11).

No type-parameter name collision is involved — the field names here are all distinct from K/V, which is what separates this from the ticket it was found under.

Why it matters

TPair is not an arbitrary example. Every dictionary-shaped generic in Generics.Collections declares a nested TPair, so corpus rung 6 (rtl-generics) cannot pass while this stands — and the failure mode is a member-not-found error pointing at the second template, with nothing naming the first.

Where to look

Nested types inside a template are presumably registered under a name derived from the nested identifier without the enclosing template's identity, so the second registration collides with (or is shadowed by) the first. Compare how EmitSpecDecl / FindSpecialization build alias names for the specialization itself — those DO carry the template name (TBase$Integer), which is the shape the nested type wants too.

Gate

Track P: make compiler/pascal26 (self-host fixedpoint) + the repro matching fpc -O2 output, plus tools/run_fgl_corpus.sh still 7/7. Add the repro as a test with an .expected.

Log