Browse Source

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 -
svenbarth 14 years ago
parent
commit
8f0583ffb2
4 changed files with 211 additions and 240 deletions
  1. 66 48
      compiler/pdecl.pas
  2. 48 114
      compiler/pdecsub.pas
  3. 51 26
      compiler/pexpr.pas
  4. 46 52
      compiler/pgenutil.pas

+ 66 - 48
compiler/pdecl.pas

@@ -345,7 +345,8 @@ implementation
         end;
 
       var
-         typename,orgtypename : TIDString;
+         typename,orgtypename,
+         gentypename,genorgtypename : TIDString;
          newtype  : ttypesym;
          sym      : tsym;
          hdef     : tdef;
@@ -360,6 +361,7 @@ implementation
          generictokenbuf : tdynamicarray;
          vmtbuilder : TVMTBuilder;
          i : integer;
+         s : shortstring;
       begin
          old_block_type:=block_type;
          { save unit container of forward declarations -
@@ -393,8 +395,18 @@ implementation
                consume(_LSHARPBRACKET);
                generictypelist:=parse_generic_parameters;
                consume(_RSHARPBRACKET);
+
+               str(generictypelist.Count,s);
+               gentypename:=typename+'$'+s;
+               genorgtypename:=orgtypename+'$'+s;
+             end
+           else
+             begin
+               gentypename:=typename;
+               genorgtypename:=orgtypename;
              end;
 
+
            consume(_EQ);
 
            { support 'ttype=type word' syntax }
@@ -416,25 +428,19 @@ implementation
            { is the type already defined? -- must be in the current symtable,
              not in a nested symtable or one higher up the stack -> don't
              use searchsym & frinds! }
-           sym:=tsym(symtablestack.top.find(typename));
+           sym:=tsym(symtablestack.top.find(gentypename));
            newtype:=nil;
            { found a symbol with this name? }
            if assigned(sym) then
             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
-                 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
                      (token=_INTERFACE) or
                      (token=_DISPINTERFACE) or
@@ -465,17 +471,12 @@ implementation
                     end;
                     consume(token);
                     { 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);
                     hdef:=newtype.typedef;
                   end
                  else
-                 if not (m_delphi in current_settings.modeswitches) and
-                     (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);
+                   message1(parser_h_type_redef,genorgtypename);
                end;
             end;
            { no old type reused ? Then insert this new type }
@@ -488,32 +489,45 @@ implementation
               storetokenpos:=current_tokenpos;
               if isgeneric then
                 begin
-                  if assigned(sym) then
-                    newtype:=ttypesym(sym)
-                  else
+                  { for generics we need to check whether a non-generic type
+                    already exists and if not we need to insert a symbol with
+                    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
-                      { add the symbol with a undefineddef, so typesym can point
-                        to this symbol }
-                      newtype:=ttypesym.create(orgtypename,tundefineddef.create);
-                      newtype.typedef.typesym:=newtype;
-                      newtype.visibility:=symtablestack.top.currentvisibility;
-                      symtablestack.top.insert(newtype);
-                      newtype.typedef.owner:=newtype.owner;
-                    end;
+                      sym:=ttypesym.create(orgtypename,tundefineddef.create);
+                      ttypesym(sym).typedef.typesym:=sym;
+                      sym.visibility:=symtablestack.top.currentvisibility;
+                      symtablestack.top.insert(sym);
+                      ttypesym(sym).typedef.owner:=sym.owner;
+                    end
+                  else
+                    { this is not allowed in non-Delphi modes }
+                    if not (m_delphi in current_settings.modeswitches) then
+                      Message1(sym_e_duplicate_id,genorgtypename);
                 end
               else
-                if assigned(sym) then
-                  newtype:=ttypesym(sym)
-                else
+                if assigned(sym) and (sym.typ=typesym) and
+                    (ttypesym(sym).typedef.typ=undefineddef) and
+                    not (sp_generic_para in sym.symoptions) then
                   begin
-                    newtype:=ttypesym.create(orgtypename,hdef);
-                    newtype.visibility:=symtablestack.top.currentvisibility;
-                    symtablestack.top.insert(newtype);
+                    { this is a symbol that was added by an earlier generic
+                      declaration, reuse it }
+                    newtype:=ttypesym(sym);
+                    newtype.typedef:=hdef;
                   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:=storetokenpos;
               { 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 }
               if assigned(hdef) then
                 begin
@@ -532,8 +546,8 @@ implementation
                           begin
                             stringdispose(objname);
                             stringdispose(objrealname);
-                            objrealname:=stringdup(orgtypename);
-                            objname:=stringdup(upper(orgtypename));
+                            objrealname:=stringdup(genorgtypename);
+                            objname:=stringdup(upper(genorgtypename));
                           end;
 
                       include(hdef.defoptions,df_unique);
@@ -544,14 +558,18 @@ implementation
                   if not assigned(hdef.typesym) then
                     hdef.typesym:=newtype;
                 end;
-              if isgeneric then begin
-                newtype.Owner.includeoption(sto_has_generic);
-                newtype.gendeflist.Add(hdef)
-              end else
-                newtype.typedef:=hdef;
+              { in non-Delphi modes we need a reference to the generic def
+                without the generic suffix, so it can be found easily when
+                parsing method implementations }
+              if isgeneric and assigned(sym) and
+                  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 }
               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
                 rec_tguid:=trecorddef(hdef);
             end;

+ 48 - 114
compiler/pdecsub.pas

@@ -812,7 +812,6 @@ implementation
         old_current_genericdef,
         old_current_specializedef: tstoreddef;
         lasttoken,lastidtoken: ttoken;
-        def : tdef;
 
         procedure parse_operator_name;
          begin
@@ -911,108 +910,60 @@ implementation
 
         function consume_generic_type_parameter:boolean;
           var
-            i,
-            j,
-            declidx,
             idx : integer;
-            found : boolean;
-            sym:tsym;
             genparalistdecl : TFPHashList;
+            genname : tidstring;
+            s : shortstring;
           begin
             result:=not assigned(astruct)and(m_delphi in current_settings.modeswitches);
             if result then
               begin
-                { is this an overloaded typesym? }
-                srsym:=search_object_name(sp,false);
-                if (srsym.typ=typesym) and
-                    (ttypesym(srsym).gendeflist.Count>0) then
+                { parse all parameters first so we can check whether we have
+                  the correct generic def available }
+                genparalistdecl:=TFPHashList.Create;
+                if try_to_consume(_LT) then
                   begin
-                    { parse all parameters first so we can check whether we have
-                      the correct generic def available }
-                    genparalistdecl:=TFPHashList.Create;
-                    if try_to_consume(_LT) then
-                      begin
-                        { start with 1, so Find can return Nil (= 0) }
-                        idx:=1;
-                        repeat
-                          if token=_ID then
-                            begin
-                              genparalistdecl.Add(pattern, Pointer(PtrInt(idx)));
-                              consume(_ID);
-                              inc(idx);
-                            end
-                          else
-                            begin
-                              message2(scan_f_syn_expected,arraytokeninfo[_ID].str,arraytokeninfo[token].str);
-                              if token<>_COMMA then
-                                consume(token);
-                            end;
-                        until not try_to_consume(_COMMA);
-                        if not try_to_consume(_GT) then
-                          consume(_RSHARPBRACKET);
-                      end
-                    else
-                      begin
-                        { no generic }
-                        srsym:=nil;
-                        exit;
-                      end;
-
-                    { now search the matching generic definition }
-                    found:=false;
-                    for i:=0 to ttypesym(srsym).gendeflist.Count-1 do
-                      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;
+                    { start with 1, so Find can return Nil (= 0) }
+                    idx:=1;
+                    repeat
+                      if token=_ID then
+                        begin
+                          genparalistdecl.Add(pattern, Pointer(PtrInt(idx)));
+                          consume(_ID);
+                          inc(idx);
+                        end
+                      else
+                        begin
+                          message2(scan_f_syn_expected,arraytokeninfo[_ID].str,arraytokeninfo[token].str);
+                          if token<>_COMMA then
+                            consume(token);
+                        end;
+                    until not try_to_consume(_COMMA);
+                    if not try_to_consume(_GT) then
+                      consume(_RSHARPBRACKET);
+                  end
+                else
+                  begin
+                    { no generic }
+                    srsym:=nil;
+                    exit;
+                  end;
 
-                        { the first found matching generic def wins }
-                        if found then
-                          break;
-                      end;
+                s:='';
+                str(genparalistdecl.count,s);
+                genname:=sp+'$'+s;
 
-                    genparalistdecl.free;
+                genparalistdecl.free;
 
-                    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;
+                srsym:=search_object_name(genname,false);
 
+                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;
@@ -1056,40 +1007,23 @@ implementation
          end;
 
         { method  ? }
-        def:=nil;
+        srsym:=nil;
         if (consume_generic_type_parameter or not assigned(astruct)) and
            (symtablestack.top.symtablelevel=main_program_level) and
            try_to_consume(_POINT) then
          begin
            repeat
              searchagain:=false;
-             if not assigned(astruct) then
-               begin
-                 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;
+             if not assigned(astruct) and not assigned(srsym) then
+               srsym:=search_object_name(sp,true);
              { consume proc name }
              procstartfilepos:=current_tokenpos;
              consume_proc_name;
              { qualifier is class name ? }
              if (srsym.typ=typesym) and
-                (def.typ in [objectdef,recorddef]) then
+                (ttypesym(srsym).typedef.typ in [objectdef,recorddef]) then
               begin
-                astruct:=tabstractrecorddef(def);
+                astruct:=tabstractrecorddef(ttypesym(srsym).typedef);
                 if (token<>_POINT) then
                   if (potype in [potype_class_constructor,potype_class_destructor]) then
                     sp:=lower(sp)

+ 51 - 26
compiler/pexpr.pas

@@ -1912,20 +1912,21 @@ implementation
                     consume(_ASSIGNMENT);
                     exit;
                   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
                    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
                      (ttypesym(srsym).typedef.typ=undefineddef) and
-                     (ttypesym(srsym).gendeflist.Count>0) and
-                     not (token in [_LT, _LSHARPBRACKET])
+                     not (sp_generic_para in srsym.symoptions) and
+                     (token in [_LT, _LSHARPBRACKET])
                    ) then
-                 check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg)
-               else
+                 check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg);
+
+               { if nothing found give error and return errorsym }
+               if not assigned(srsym) then
                  begin
                    identifier_not_found(orgstoredpattern);
                    srsym:=generrorsym;
@@ -2842,7 +2843,7 @@ implementation
         filepos : tfileposinfo;
         again,
         isgeneric : boolean;
-        def : tdef;
+        gendef,parseddef : tdef;
       begin
         if pred_level=highest_precedence then
           p1:=factor(false,typeonly)
@@ -2876,24 +2877,47 @@ implementation
                _LT :
                  begin
                    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
                        (token in [_GT,_RSHARPBRACKET,_COMMA]) then
                      begin
                        { this is an inline specialization }
-                       if ttypenode(p1).typedef.typesym.typ<>typesym then
-                         Internalerror(2011050301);
-                       { TODO : search for other generics with the same name
-                                in other units (if no unit identifier is
-                                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
+
+                       { retrive the def of the left node }
+                       if p1.nodetype=typen then
+                         gendef:=ttypenode(p1).typedef
+                       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;
 
                    if not isgeneric then
@@ -2904,9 +2928,10 @@ implementation
                        p1.Free;
                        p2.Free;
                        { in case of a class this is always a classrefdef }
-                       if is_class_or_interface_or_object(def) or is_record(def) then
-                         def:=tclassrefdef.create(def);
-                       p1:=ctypenode.create(def);
+                       if is_class_or_interface_or_object(gendef) or
+                           is_record(gendef) then
+                         gendef:=tclassrefdef.create(gendef);
+                       p1:=ctypenode.create(gendef);
                        again:=true;
                        { parse postfix operators }
                        if postfixoperators(p1,again,false) then

+ 46 - 52
compiler/pgenutil.pas

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