Switching from overloaded type symbol to unique symbol per generic.

Reasons for the "unique symbol" approach:
- no special search operations for cross unit search needed (which is supported by Delphi) => less performance impact
- no special care needed to really find the correct generic => less increase of parser complexity

Currently all generic tests except tgeneric29.pp compile and inline specializations work as well.

The changes in detail:
* pdecl.pas/types_dec:
- The variables used to hold the final name of the symbol are now prefixed with "gen". In case of non-generics the prefixed ones are equal to the non-prefixed ones (e.g. orgtypename=genorgtypename). In case of a generic symbol the "gen"-variants contain the type parameter count suffix (e.g. '$1' in case of 'TTest<T>') as well.
- The unmodified pattern is used to insert and detect a dummy symbol with that name, so that type declarations and - more important - inline specializations can find that symbol.
- In non-Delphi modes this symbol is also used to detect whether we have a type redefinition which is not allowed currently; its typedef points to the generic def.
- In mode Delphi the def of that dummy symbol (which contains an undefineddef) is modified when a corresponding non-generic type is parsed, so that it contains the def of the real type.

* pdecsub.pas/parse_proc_head
- consume_generic_type_parameter now only parses the type parameters and picks the generic with the correct amount of parameters. The verification of the order and names of the parameters needs to be added again.
- it also does not use "def" anymore, but it sets "srsym"
- in parse_proc_head the symbol (srsym) is only searched if the symbol isn't assigned already; in case of a generic in mode FPC it will find the dummy symbol that points to the generic def

* pexpr.pas
- in factor_read_id there are three cases to handle:
 + the symbol is not assigned => error
 + a possible generic symbol (either an undefined def or the non-generic variant) => no error and no hints
 + a non-generic symbol => hints
 Point 1 is handled correctly, point 2 and 3 aren't currently and also they might be needed to be moved somewhere else
- sub_expr:
 + a node can be a tloadvmtaddrnode as well if the non-generic variant of a generic symbol is a class
 + we can only check afterwards whether the specialization was successful

* pgenutil.pas/generate_specialization
using the count of the parsed types the correct symbol can be found easily

git-svn-id: branches/svenbarth/generics@17535 -
This commit is contained in:
svenbarth 2011-05-23 19:12:50 +00:00
parent bba6e0e73f
commit 8f0583ffb2
4 changed files with 213 additions and 242 deletions

View File

@ -345,7 +345,8 @@ implementation
end; end;
var var
typename,orgtypename : TIDString; typename,orgtypename,
gentypename,genorgtypename : TIDString;
newtype : ttypesym; newtype : ttypesym;
sym : tsym; sym : tsym;
hdef : tdef; hdef : tdef;
@ -360,6 +361,7 @@ implementation
generictokenbuf : tdynamicarray; generictokenbuf : tdynamicarray;
vmtbuilder : TVMTBuilder; vmtbuilder : TVMTBuilder;
i : integer; i : integer;
s : shortstring;
begin begin
old_block_type:=block_type; old_block_type:=block_type;
{ save unit container of forward declarations - { save unit container of forward declarations -
@ -393,8 +395,18 @@ implementation
consume(_LSHARPBRACKET); consume(_LSHARPBRACKET);
generictypelist:=parse_generic_parameters; generictypelist:=parse_generic_parameters;
consume(_RSHARPBRACKET); consume(_RSHARPBRACKET);
str(generictypelist.Count,s);
gentypename:=typename+'$'+s;
genorgtypename:=orgtypename+'$'+s;
end
else
begin
gentypename:=typename;
genorgtypename:=orgtypename;
end; end;
consume(_EQ); consume(_EQ);
{ support 'ttype=type word' syntax } { support 'ttype=type word' syntax }
@ -416,25 +428,19 @@ implementation
{ is the type already defined? -- must be in the current symtable, { is the type already defined? -- must be in the current symtable,
not in a nested symtable or one higher up the stack -> don't not in a nested symtable or one higher up the stack -> don't
use searchsym & frinds! } use searchsym & frinds! }
sym:=tsym(symtablestack.top.find(typename)); sym:=tsym(symtablestack.top.find(gentypename));
newtype:=nil; newtype:=nil;
{ found a symbol with this name? } { found a symbol with this name? }
if assigned(sym) then if assigned(sym) then
begin begin
if (sym.typ=typesym) then if (sym.typ=typesym) and
{ this should not be a symbol that was created by a generic
that was declared earlier }
not (
(ttypesym(sym).typedef.typ=undefineddef) and
not (sp_generic_para in sym.symoptions)
) then
begin begin
if isgeneric then
begin
{ overloading types is only allowed in mode Delphi }
if not (m_delphi in current_settings.modeswitches) then
Message1(sym_e_duplicate_id,orgtypename);
for i:=0 to ttypesym(sym).gendeflist.Count-1 do
{ TODO : check whether the count of one of the defs is
the same as that of the current declaration and
print an error if so }
;
end
else
if ((token=_CLASS) or if ((token=_CLASS) or
(token=_INTERFACE) or (token=_INTERFACE) or
(token=_DISPINTERFACE) or (token=_DISPINTERFACE) or
@ -465,17 +471,12 @@ implementation
end; end;
consume(token); consume(token);
{ we can ignore the result, the definition is modified } { we can ignore the result, the definition is modified }
object_dec(objecttype,orgtypename,nil,nil,tobjectdef(ttypesym(sym).typedef),ht_none); object_dec(objecttype,genorgtypename,nil,nil,tobjectdef(ttypesym(sym).typedef),ht_none);
newtype:=ttypesym(sym); newtype:=ttypesym(sym);
hdef:=newtype.typedef; hdef:=newtype.typedef;
end end
else else
if not (m_delphi in current_settings.modeswitches) and message1(parser_h_type_redef,genorgtypename);
(ttypesym(sym).typedef.typ=undefineddef) and
(ttypesym(sym).gendeflist.Count>0) then
message1(sym_e_duplicate_id,orgtypename)
else
message1(parser_h_type_redef,orgtypename);
end; end;
end; end;
{ no old type reused ? Then insert this new type } { no old type reused ? Then insert this new type }
@ -488,32 +489,45 @@ implementation
storetokenpos:=current_tokenpos; storetokenpos:=current_tokenpos;
if isgeneric then if isgeneric then
begin begin
if assigned(sym) then { for generics we need to check whether a non-generic type
newtype:=ttypesym(sym) already exists and if not we need to insert a symbol with
else the non-generic name (available in (org)typename) that is a
undefineddef, so that inline specializations can be used }
sym:=tsym(symtablestack.top.Find(typename));
if not assigned(sym) then
begin begin
{ add the symbol with a undefineddef, so typesym can point sym:=ttypesym.create(orgtypename,tundefineddef.create);
to this symbol } ttypesym(sym).typedef.typesym:=sym;
newtype:=ttypesym.create(orgtypename,tundefineddef.create); sym.visibility:=symtablestack.top.currentvisibility;
newtype.typedef.typesym:=newtype; symtablestack.top.insert(sym);
newtype.visibility:=symtablestack.top.currentvisibility; ttypesym(sym).typedef.owner:=sym.owner;
symtablestack.top.insert(newtype); end
newtype.typedef.owner:=newtype.owner; else
end; { this is not allowed in non-Delphi modes }
if not (m_delphi in current_settings.modeswitches) then
Message1(sym_e_duplicate_id,genorgtypename);
end end
else else
if assigned(sym) then if assigned(sym) and (sym.typ=typesym) and
newtype:=ttypesym(sym) (ttypesym(sym).typedef.typ=undefineddef) and
else not (sp_generic_para in sym.symoptions) then
begin begin
newtype:=ttypesym.create(orgtypename,hdef); { this is a symbol that was added by an earlier generic
newtype.visibility:=symtablestack.top.currentvisibility; declaration, reuse it }
symtablestack.top.insert(newtype); newtype:=ttypesym(sym);
newtype.typedef:=hdef;
end; end;
{ insert a newtype if we don't reuse an existing symbol }
if not assigned(newtype) then
begin
newtype:=ttypesym.create(genorgtypename,hdef);
newtype.visibility:=symtablestack.top.currentvisibility;
symtablestack.top.insert(newtype);
end;
current_tokenpos:=defpos; current_tokenpos:=defpos;
current_tokenpos:=storetokenpos; current_tokenpos:=storetokenpos;
{ read the type definition } { read the type definition }
read_named_type(hdef,orgtypename,nil,generictypelist,false); read_named_type(hdef,genorgtypename,nil,generictypelist,false);
{ update the definition of the type } { update the definition of the type }
if assigned(hdef) then if assigned(hdef) then
begin begin
@ -532,8 +546,8 @@ implementation
begin begin
stringdispose(objname); stringdispose(objname);
stringdispose(objrealname); stringdispose(objrealname);
objrealname:=stringdup(orgtypename); objrealname:=stringdup(genorgtypename);
objname:=stringdup(upper(orgtypename)); objname:=stringdup(upper(genorgtypename));
end; end;
include(hdef.defoptions,df_unique); include(hdef.defoptions,df_unique);
@ -544,14 +558,18 @@ implementation
if not assigned(hdef.typesym) then if not assigned(hdef.typesym) then
hdef.typesym:=newtype; hdef.typesym:=newtype;
end; end;
if isgeneric then begin { in non-Delphi modes we need a reference to the generic def
newtype.Owner.includeoption(sto_has_generic); without the generic suffix, so it can be found easily when
newtype.gendeflist.Add(hdef) parsing method implementations }
end else if isgeneric and assigned(sym) and
newtype.typedef:=hdef; not (m_delphi in current_settings.modeswitches) and
(ttypesym(sym).typedef.typ=undefineddef) then
{ TODO : check whether the undefined def needs to be freed }
ttypesym(sym).typedef:=hdef;
newtype.typedef:=hdef;
{ KAZ: handle TGUID declaration in system unit } { KAZ: handle TGUID declaration in system unit }
if (cs_compilesystem in current_settings.moduleswitches) and not assigned(rec_tguid) and if (cs_compilesystem in current_settings.moduleswitches) and not assigned(rec_tguid) and
(typename='TGUID') and { name: TGUID and size=16 bytes that is 128 bits } (gentypename='TGUID') and { name: TGUID and size=16 bytes that is 128 bits }
assigned(hdef) and (hdef.typ=recorddef) and (hdef.size=16) then assigned(hdef) and (hdef.typ=recorddef) and (hdef.size=16) then
rec_tguid:=trecorddef(hdef); rec_tguid:=trecorddef(hdef);
end; end;

View File

@ -812,7 +812,6 @@ implementation
old_current_genericdef, old_current_genericdef,
old_current_specializedef: tstoreddef; old_current_specializedef: tstoreddef;
lasttoken,lastidtoken: ttoken; lasttoken,lastidtoken: ttoken;
def : tdef;
procedure parse_operator_name; procedure parse_operator_name;
begin begin
@ -911,108 +910,60 @@ implementation
function consume_generic_type_parameter:boolean; function consume_generic_type_parameter:boolean;
var var
i,
j,
declidx,
idx : integer; idx : integer;
found : boolean;
sym:tsym;
genparalistdecl : TFPHashList; genparalistdecl : TFPHashList;
genname : tidstring;
s : shortstring;
begin begin
result:=not assigned(astruct)and(m_delphi in current_settings.modeswitches); result:=not assigned(astruct)and(m_delphi in current_settings.modeswitches);
if result then if result then
begin begin
{ is this an overloaded typesym? } { parse all parameters first so we can check whether we have
srsym:=search_object_name(sp,false); the correct generic def available }
if (srsym.typ=typesym) and genparalistdecl:=TFPHashList.Create;
(ttypesym(srsym).gendeflist.Count>0) then if try_to_consume(_LT) then
begin begin
{ parse all parameters first so we can check whether we have { start with 1, so Find can return Nil (= 0) }
the correct generic def available } idx:=1;
genparalistdecl:=TFPHashList.Create; repeat
if try_to_consume(_LT) then if token=_ID then
begin begin
{ start with 1, so Find can return Nil (= 0) } genparalistdecl.Add(pattern, Pointer(PtrInt(idx)));
idx:=1; consume(_ID);
repeat inc(idx);
if token=_ID then end
begin else
genparalistdecl.Add(pattern, Pointer(PtrInt(idx))); begin
consume(_ID); message2(scan_f_syn_expected,arraytokeninfo[_ID].str,arraytokeninfo[token].str);
inc(idx); if token<>_COMMA then
end consume(token);
else end;
begin until not try_to_consume(_COMMA);
message2(scan_f_syn_expected,arraytokeninfo[_ID].str,arraytokeninfo[token].str); if not try_to_consume(_GT) then
if token<>_COMMA then consume(_RSHARPBRACKET);
consume(token); end
end; else
until not try_to_consume(_COMMA); begin
if not try_to_consume(_GT) then { no generic }
consume(_RSHARPBRACKET); srsym:=nil;
end exit;
else end;
begin
{ no generic }
srsym:=nil;
exit;
end;
{ now search the matching generic definition } s:='';
found:=false; str(genparalistdecl.count,s);
for i:=0 to ttypesym(srsym).gendeflist.Count-1 do genname:=sp+'$'+s;
begin
def:=tdef(ttypesym(srsym).gendeflist[i]);
{ for now generic overloads are only allowed for records
and objects; later they'll also be allowed for
procedures and functions }
if not (def.typ in [objectdef,recorddef]) then
continue;
st:=def.getsymtable(gs_record);
if not assigned(st) then
InternalError(2011042901);
idx:=1;
{ check whether the generic parameters of the def have the
same count and order as the ones just scanned, if so
"found" is true }
for j:=0 to st.SymList.Count-1 do
begin
sym:=tsym(st.SymList[j]);
if sp_generic_para in sym.symoptions then
begin
if not (sym.typ=typesym) then
internalerror(2011290402);
{ too many parameters }
if idx>genparalistdecl.Count then
break;
declidx:=PtrInt(genparalistdecl.Find(sym.prettyname));
{ does the parameters' index match the current
index value? }
if (declidx=0) or (declidx<>idx) then
break;
inc(idx);
end;
if (j=st.SymList.Count-1) and (idx=genparalistdecl.Count+1) then
found:=true;
end;
{ the first found matching generic def wins } genparalistdecl.free;
if found then
break;
end;
genparalistdecl.free; srsym:=search_object_name(genname,false);
if not found then
begin
{ TODO : print a nicer typename that contains the parsed
generic types }
Message1(type_e_generic_declaration_does_not_match,sp);
srsym:=nil;
def:=nil;
exit;
end;
if not assigned(srsym) then
begin
{ TODO : print a nicer typename that contains the parsed
generic types }
Message1(type_e_generic_declaration_does_not_match,genname);
srsym:=nil;
exit;
end; end;
end; end;
end; end;
@ -1056,40 +1007,23 @@ implementation
end; end;
{ method ? } { method ? }
def:=nil; srsym:=nil;
if (consume_generic_type_parameter or not assigned(astruct)) and if (consume_generic_type_parameter or not assigned(astruct)) and
(symtablestack.top.symtablelevel=main_program_level) and (symtablestack.top.symtablelevel=main_program_level) and
try_to_consume(_POINT) then try_to_consume(_POINT) then
begin begin
repeat repeat
searchagain:=false; searchagain:=false;
if not assigned(astruct) then if not assigned(astruct) and not assigned(srsym) then
begin srsym:=search_object_name(sp,true);
if not assigned(def) then
begin
srsym:=search_object_name(sp,true);
{ in non-Delphi modes we can directly use the generic def if one
exists }
if (srsym.typ=typesym) then
if (ttypesym(srsym).gendeflist.Count>0) and
not (m_delphi in current_settings.modeswitches) then
def:=tdef(ttypesym(srsym).gendeflist[0])
else
def:=ttypesym(srsym).typedef
else
def:=nil;
end;
end
else
def:=astruct;
{ consume proc name } { consume proc name }
procstartfilepos:=current_tokenpos; procstartfilepos:=current_tokenpos;
consume_proc_name; consume_proc_name;
{ qualifier is class name ? } { qualifier is class name ? }
if (srsym.typ=typesym) and if (srsym.typ=typesym) and
(def.typ in [objectdef,recorddef]) then (ttypesym(srsym).typedef.typ in [objectdef,recorddef]) then
begin begin
astruct:=tabstractrecorddef(def); astruct:=tabstractrecorddef(ttypesym(srsym).typedef);
if (token<>_POINT) then if (token<>_POINT) then
if (potype in [potype_class_constructor,potype_class_destructor]) then if (potype in [potype_class_constructor,potype_class_destructor]) then
sp:=lower(sp) sp:=lower(sp)

View File

@ -1912,20 +1912,21 @@ implementation
consume(_ASSIGNMENT); consume(_ASSIGNMENT);
exit; exit;
end; end;
{ if nothing found give error and return errorsym }
{ TODO : adjust this check for inline specializations } { check hints if it is the final symbol that is used (e.g. in
case of generics only the dummy symbol or the non-generic one
is found here }
if assigned(srsym) and if assigned(srsym) and
not ( not (
{ in case of an overloaded generic symbol we need to
generate an error if the non-generic symbol is still
undefined and we're not doing a specialization }
typeonly and (srsym.typ=typesym) and typeonly and (srsym.typ=typesym) and
(ttypesym(srsym).typedef.typ=undefineddef) and (ttypesym(srsym).typedef.typ=undefineddef) and
(ttypesym(srsym).gendeflist.Count>0) and not (sp_generic_para in srsym.symoptions) and
not (token in [_LT, _LSHARPBRACKET]) (token in [_LT, _LSHARPBRACKET])
) then ) then
check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg) check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg);
else
{ if nothing found give error and return errorsym }
if not assigned(srsym) then
begin begin
identifier_not_found(orgstoredpattern); identifier_not_found(orgstoredpattern);
srsym:=generrorsym; srsym:=generrorsym;
@ -2842,7 +2843,7 @@ implementation
filepos : tfileposinfo; filepos : tfileposinfo;
again, again,
isgeneric : boolean; isgeneric : boolean;
def : tdef; gendef,parseddef : tdef;
begin begin
if pred_level=highest_precedence then if pred_level=highest_precedence then
p1:=factor(false,typeonly) p1:=factor(false,typeonly)
@ -2876,24 +2877,47 @@ implementation
_LT : _LT :
begin begin
isgeneric:=false; isgeneric:=false;
if (p1.nodetype=typen) and (p2.nodetype=typen) and if (
{ the left node needs to be a type node }
(p1.nodetype=typen) or
(
(p1.nodetype=loadvmtaddrn) and
(tloadvmtaddrnode(p1).left.nodetype=typen)
)
) and
(
{ the right node needs to be a type node }
(p2.nodetype=typen) or
(
(p2.nodetype=loadvmtaddrn) and
(tloadvmtaddrnode(p2).left.nodetype=typen)
)
) and
(m_delphi in current_settings.modeswitches) and (m_delphi in current_settings.modeswitches) and
(token in [_GT,_RSHARPBRACKET,_COMMA]) then (token in [_GT,_RSHARPBRACKET,_COMMA]) then
begin begin
{ this is an inline specialization } { this is an inline specialization }
if ttypenode(p1).typedef.typesym.typ<>typesym then
Internalerror(2011050301); { retrive the def of the left node }
{ TODO : search for other generics with the same name if p1.nodetype=typen then
in other units (if no unit identifier is gendef:=ttypenode(p1).typedef
given...) }
if ttypesym(ttypenode(p1).typedef.typesym).gendeflist.Count>0 then
begin
def:=ttypenode(p1).typedef;
generate_specialization(def,false,ttypenode(p2).typedef);
isgeneric:=def<>generrordef;
end
else else
; gendef:=ttypenode(tloadvmtaddrnode(p1).left).typedef;
{ retrieve the right node }
if p2.nodetype=typen then
parseddef:=ttypenode(p2).typedef
else
parseddef:=ttypenode(tloadvmtaddrnode(p2).left).typedef;
if gendef.typesym.typ<>typesym then
Internalerror(2011050301);
if parseddef.typesym.typ<>typesym then
Internalerror(2011051001);
{ generate the specialization }
generate_specialization(gendef,false,parseddef);
isgeneric:=gendef<>generrordef;
end; end;
if not isgeneric then if not isgeneric then
@ -2904,9 +2928,10 @@ implementation
p1.Free; p1.Free;
p2.Free; p2.Free;
{ in case of a class this is always a classrefdef } { in case of a class this is always a classrefdef }
if is_class_or_interface_or_object(def) or is_record(def) then if is_class_or_interface_or_object(gendef) or
def:=tclassrefdef.create(def); is_record(gendef) then
p1:=ctypenode.create(def); gendef:=tclassrefdef.create(gendef);
p1:=ctypenode.create(gendef);
again:=true; again:=true;
{ parse postfix operators } { parse postfix operators }
if postfixoperators(p1,again,false) then if postfixoperators(p1,again,false) then

View File

@ -59,13 +59,10 @@ uses
st : TSymtable; st : TSymtable;
srsym : tsym; srsym : tsym;
pt2 : tnode; pt2 : tnode;
found,
first, first,
err : boolean; err : boolean;
i, i,
j,
gencount : longint; gencount : longint;
sym : tsym;
genericdef : tstoreddef; genericdef : tstoreddef;
genericsym, genericsym,
generictype : ttypesym; generictype : ttypesym;
@ -76,12 +73,11 @@ uses
hmodule : tmodule; hmodule : tmodule;
pu : tused_unit; pu : tused_unit;
uspecializename, uspecializename,
specializename : string; countstr,genname,ugenname,specializename : string;
vmtbuilder : TVMTBuilder; vmtbuilder : TVMTBuilder;
onlyparsepara : boolean; onlyparsepara : boolean;
specializest : tsymtable; specializest : tsymtable;
item: psymtablestackitem; item: psymtablestackitem;
def : tdef;
begin begin
{ retrieve generic def that we are going to replace } { retrieve generic def that we are going to replace }
genericdef:=tstoreddef(tt); genericdef:=tstoreddef(tt);
@ -93,13 +89,6 @@ uses
internalerror(2011042701); internalerror(2011042701);
genericsym:=ttypesym(genericdef.typesym); genericsym:=ttypesym(genericdef.typesym);
if genericsym.gendeflist.Count=0 then
begin
{ TODO : search for other generics with the same name }
Message(parser_e_special_onlygenerics);
tt:=generrordef;
onlyparsepara:=true;
end;
{ only need to record the tokens, then we don't know the type yet ... } { only need to record the tokens, then we don't know the type yet ... }
if parse_generic then if parse_generic then
@ -178,63 +167,68 @@ uses
exit; exit;
end; end;
{ check whether we have a generic with the correct amount of params } { search a generic with the given count of params }
found:=false; countstr:='';
for i:=0 to genericsym.gendeflist.Count-1 do begin str(genericdeflist.Count,countstr);
def:=tdef(genericsym.gendeflist[i]); { use the name of the symbol as procvars return a user friendly version
{ select the symtable containing the params } of the name }
case def.typ of genname:=ttypesym(genericdef.typesym).realname;
procdef: { in case of non-Delphi mode the type name could already be a generic
st:=def.GetSymtable(gs_para); def (but maybe the wrong one) }
objectdef, if df_generic in genericdef.defoptions then
recorddef:
st:=def.GetSymtable(gs_record);
arraydef:
st:=tarraydef(def).symtable;
procvardef:
st:=def.GetSymtable(gs_para);
else
internalerror(200511182);
end;
gencount:=0;
for j:=0 to st.SymList.Count-1 do
begin
if sp_generic_para in tsym(st.SymList[j]).symoptions then
inc(gencount);
end;
if gencount=genericdeflist.count then
begin
found:=true;
break;
end;
end;
if not found then
begin begin
identifier_not_found(genericdef.typename); { remove the type count suffix from the generic's name }
tt:=generrordef; for i:=Length(genname) downto 1 do
if genname[i]='$' then
begin
genname:=copy(genname,1,i-1);
break;
end;
end;
genname:=genname+'$'+countstr;
ugenname:=upper(genname);
if not searchsym(ugenname,srsym,st)
or (srsym.typ<>typesym) then
begin
identifier_not_found(genname);
genericdeflist.Free;
generictypelist.Free;
exit; exit;
end; end;
{ we've found the correct def, so use it } { we've found the correct def }
genericdef:=tstoreddef(def); genericdef:=tstoreddef(ttypesym(srsym).typedef);
{ build the new type's name } { build the new type's name }
specializename:=genericdef.typesym.realname+specializename; specializename:=genname+specializename;
uspecializename:=upper(specializename); uspecializename:=upper(specializename);
{ select the symtable containing the params }
case genericdef.typ of
procdef:
st:=genericdef.GetSymtable(gs_para);
objectdef,
recorddef:
st:=genericdef.GetSymtable(gs_record);
arraydef:
st:=tarraydef(genericdef).symtable;
procvardef:
st:=genericdef.GetSymtable(gs_para);
else
internalerror(200511182);
end;
{ build the list containing the types for the generic params } { build the list containing the types for the generic params }
gencount:=0; gencount:=0;
for i:=0 to st.SymList.Count-1 do for i:=0 to st.SymList.Count-1 do
begin begin
sym:=tsym(st.SymList[i]); srsym:=tsym(st.SymList[i]);
if sp_generic_para in sym.symoptions then if sp_generic_para in srsym.symoptions then
begin begin
if gencount=genericdeflist.Count then if gencount=genericdeflist.Count then
internalerror(2011042702); internalerror(2011042702);
generictype:=ttypesym.create(sym.realname,tdef(genericdeflist[gencount])); generictype:=ttypesym.create(srsym.realname,tdef(genericdeflist[gencount]));
generictypelist.add(generictype); generictypelist.add(generictype);
inc(gencount); inc(gencount);
end; end;