Przeglądaj źródła

generics: store generic type with '<,>' symbols to prevent hiding of regular types with the same name and hiding generics with the same name but different type parameters, search them using '<,>' symbols, in inline specialization do search with look ahead.

git-svn-id: branches/paul/generics@16817 -
paul 14 lat temu
rodzic
commit
5b9adfd0df
47 zmienionych plików z 628 dodań i 507 usunięć
  1. 6 5
      compiler/pbase.pas
  2. 7 3
      compiler/pdecl.pas
  3. 1 1
      compiler/pdecobj.pas
  4. 33 65
      compiler/pdecsub.pas
  5. 7 7
      compiler/pdecvar.pas
  6. 2 2
      compiler/pexports.pas
  7. 216 107
      compiler/pexpr.pas
  8. 5 5
      compiler/pinline.pas
  9. 2 2
      compiler/pp.lpi
  10. 12 12
      compiler/pstatmnt.pas
  11. 13 13
      compiler/ptconst.pas
  12. 73 101
      compiler/ptype.pas
  13. 57 0
      compiler/scanner.pas
  14. 11 1
      compiler/symtable.pas
  15. 121 121
      rtl/objpas/fgl.pp
  16. 4 4
      tests/tbs/ub0569.pp
  17. 1 1
      tests/test/tgeneric1.pp
  18. 2 2
      tests/test/tgeneric11.pp
  19. 2 2
      tests/test/tgeneric12.pp
  20. 2 2
      tests/test/tgeneric15.pp
  21. 3 3
      tests/test/tgeneric16.pp
  22. 3 3
      tests/test/tgeneric17.pp
  23. 1 1
      tests/test/tgeneric19.pp
  24. 1 1
      tests/test/tgeneric2.pp
  25. 1 1
      tests/test/tgeneric20.pp
  26. 9 9
      tests/test/tgeneric22.pp
  27. 1 1
      tests/test/tgeneric5.pp
  28. 1 1
      tests/test/tgeneric6.pp
  29. 3 3
      tests/test/tgeneric8.pp
  30. 1 1
      tests/test/tgeneric9.pp
  31. 2 2
      tests/test/ugeneric10.pp
  32. 1 1
      tests/test/ugeneric14.pp
  33. 1 1
      tests/test/ugeneric3.pp
  34. 1 1
      tests/test/ugeneric4.pp
  35. 1 1
      tests/test/ugeneric7.pp
  36. 6 6
      tests/webtbs/tw10247.pp
  37. 2 2
      tests/webtbs/tw10247b.pp
  38. 1 1
      tests/webtbs/tw11435b.pp
  39. 2 2
      tests/webtbs/tw11435c.pp
  40. 1 1
      tests/webtbs/tw12249.pp
  41. 2 2
      tests/webtbs/tw16065.pp
  42. 1 1
      tests/webtbs/tw17193.pp
  43. 2 2
      tests/webtbs/tw6624.pp
  44. 1 1
      tests/webtbs/tw9673.pp
  45. 1 1
      tests/webtbs/tw9827.pp
  46. 1 1
      tests/webtbs/uw14124.pp
  47. 1 1
      tests/webtbs/uw15591.pp

+ 6 - 5
compiler/pbase.pas

@@ -88,7 +88,7 @@ interface
     function consume_sym(var srsym:tsym;var srsymtable:TSymtable):boolean;
     function consume_sym_orgid(var srsym:tsym;var srsymtable:TSymtable;var s : string):boolean;
 
-    function try_consume_unitsym(var srsym:tsym;var srsymtable:TSymtable;var tokentoconsume : ttoken):boolean;
+    function try_consume_unitsym(var srsym:tsym;var srsymtable:TSymtable;var tokentoconsume:ttoken;const consume_id:boolean):boolean;
 
     function try_consume_hintdirective(var symopt:tsymoptions; var deprecatedmsg:pshortstring):boolean;
 
@@ -191,7 +191,7 @@ implementation
           end;
         searchsym(pattern,srsym,srsymtable);
         { handle unit specification like System.Writeln }
-        try_consume_unitsym(srsym,srsymtable,t);
+        try_consume_unitsym(srsym,srsymtable,t,true);
         { if nothing found give error and return errorsym }
         if assigned(srsym) then
           check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg)
@@ -224,7 +224,7 @@ implementation
           end;
         searchsym(pattern,srsym,srsymtable);
         { handle unit specification like System.Writeln }
-        try_consume_unitsym(srsym,srsymtable,t);
+        try_consume_unitsym(srsym,srsymtable,t,true);
         { if nothing found give error and return errorsym }
         if assigned(srsym) then
           check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg)
@@ -240,7 +240,7 @@ implementation
       end;
 
 
-    function try_consume_unitsym(var srsym:tsym;var srsymtable:TSymtable;var tokentoconsume : ttoken):boolean;
+    function try_consume_unitsym(var srsym:tsym;var srsymtable:TSymtable;var tokentoconsume:ttoken;const consume_id:boolean):boolean;
       var
         hmodule: tmodule;
       begin
@@ -260,7 +260,8 @@ implementation
               internalerror(201001120);
             if hmodule.unit_index=current_filepos.moduleindex then
               begin
-                consume(_ID);
+                if consume_id then
+                  consume(_ID);
                 consume(_POINT);
                 case token of
                   _ID:

+ 7 - 3
compiler/pdecl.pas

@@ -91,7 +91,7 @@ implementation
         if orgname='' then
          internalerror(9584582);
         hp:=nil;
-        p:=comp_expr(true,false);
+        p:=comp_expr(true,[]);
         storetokenpos:=current_tokenpos;
         current_tokenpos:=filepos;
         case p.nodetype of
@@ -394,7 +394,7 @@ implementation
         end;
 
       var
-         typename,orgtypename : TIDString;
+         typename,orgtypename,tmp : TIDString;
          newtype  : ttypesym;
          sym      : tsym;
          srsymtable : TSymtable;
@@ -442,6 +442,10 @@ implementation
                consume(_LSHARPBRACKET);
                generictypelist:=parse_generic_parameters;
                consume(_RSHARPBRACKET);
+               { modify the type name }
+               tmp:=generate_generic_id_modifier(generictypelist.Count);
+               typename:=typename+tmp;
+               orgtypename:=orgtypename+tmp;
              end;
 
            consume(_EQ);
@@ -735,7 +739,7 @@ implementation
              _EQ:
                 begin
                    consume(_EQ);
-                   p:=comp_expr(true,false);
+                   p:=comp_expr(true,[]);
                    storetokenpos:=current_tokenpos;
                    current_tokenpos:=filepos;
                    sym:=nil;

+ 1 - 1
compiler/pdecobj.pas

@@ -328,7 +328,7 @@ implementation
         p : tnode;
         valid : boolean;
       begin
-        p:=comp_expr(true,false);
+        p:=comp_expr(true,[]);
         if p.nodetype=stringconstn then
           begin
             stringdispose(current_objectdef.iidstr);

+ 33 - 65
compiler/pdecsub.pas

@@ -902,75 +902,43 @@ implementation
 
         function consume_generic_type_parameter:boolean;
           var
-            i:integer;
-            ok:boolean;
+            typeparamcount:integer;
             sym:tsym;
+            foundname,realname:TIDString;
           begin
-            result:=not assigned(astruct)and(m_delphi in current_settings.modeswitches);
-            if result then
+            result:=not assigned(astruct);
+            if result and (token=_LT) then
               begin
-                { a generic type parameter? }
-                srsym:=search_object_name(sp,false);
+                consume(_LT);
+                { a generic type parameter }
+                typeparamcount:=0;
+                foundname:='';
+                repeat
+                  if (token=_ID)  then
+                    begin
+                      inc(typeparamcount);
+                      foundname:=foundname+pattern+',';
+                    end;
+                  consume(_ID);
+                until not try_to_consume(_COMMA);
+                consume(_GT);
+                srsym:=search_object_name(sp+generate_generic_id_modifier(typeparamcount),false);
                 if (srsym.typ=typesym) and
                    (ttypesym(srsym).typedef.typ in [objectdef,recorddef]) then
-                begin
-                  astruct:=tabstractrecorddef(ttypesym(srsym).typedef);
-                  if (df_generic in astruct.defoptions) and try_to_consume(_LT) then
-                    begin
-                      ok:=true;
-                      i:=0;
-                      repeat
-                        if ok and (token=_ID)  then
-                          begin
-                            ok:=false;
-                            while i<astruct.symtable.SymList.Count-1 do
-                              begin
-                                sym:=tsym(astruct.symtable.SymList[i]);
-                                if sp_generic_para in sym.symoptions then
-                                  begin
-                                    ok:=sym.Name=pattern;
-                                    inc(i);
-                                    break;
-                                  end;
-                                inc(i);
-                              end;
-                            if not ok then
-                              Message1(type_e_generic_declaration_does_not_match,astruct.RttiName);
-                          end;
-                        consume(_ID);
-                      until not try_to_consume(_COMMA);
-                      if ok then
-                        while i<astruct.symtable.SymList.Count-1 do
-                          begin
-                            sym:=tsym(astruct.symtable.SymList[i]);
-                            if sp_generic_para in sym.symoptions then
-                              begin
-                                Message1(type_e_generic_declaration_does_not_match,astruct.RttiName);
-                                break;
-                              end;
-                            inc(i);
-                          end;
-                      consume(_GT);
-                    end
-                  else
-                  if (df_generic in astruct.defoptions) and (token=_POINT) then
-                    begin
+                  begin
+                    astruct:=tabstractrecorddef(ttypesym(srsym).typedef);
+                    realname:='';
+                    for typeparamcount := 0 to astruct.symtable.SymList.Count-1 do
+                      begin
+                        sym:=tsym(astruct.symtable.SymList[typeparamcount]);
+                        if sp_generic_para in sym.symoptions then
+                          realname:=realname+sym.Name+',';
+                      end;
+                    if foundname<>realname then
                       Message1(type_e_generic_declaration_does_not_match,astruct.RttiName);
-                    end
-                  else
-                    begin
-                      { not a method. routine name just accidentally match some structure name }
-                      astruct:=nil;
-                      if try_to_consume(_LT) then
-                        begin
-                          Message(type_e_type_parameters_are_not_allowed_here);
-                          repeat
-                            consume(_ID);
-                          until not try_to_consume(_COMMA);
-                          consume(_GT);
-                        end;
-                    end;
-                end;
+                  end
+                else
+                  Message(type_e_type_parameters_are_not_allowed_here);
               end;
           end;
 
@@ -1707,7 +1675,7 @@ var pt:Tnode;
 begin
   if pd.typ<>procdef then
     internalerror(200604301);
-  pt:=comp_expr(true,false);
+  pt:=comp_expr(true,[]);
   if is_constintnode(pt) then
     if (Tordconstnode(pt).value<int64(low(longint))) or (Tordconstnode(pt).value>int64(high(longint))) then
       message(parser_e_range_check_error)
@@ -1769,7 +1737,7 @@ begin
       if paracnt<>1 then
         Message(parser_e_ill_msg_param);
     end;
-  pt:=comp_expr(true,false);
+  pt:=comp_expr(true,[]);
   { message is 1-character long }
   if is_constcharnode(pt) then
     begin

+ 7 - 7
compiler/pdecvar.pas

@@ -177,7 +177,7 @@ implementation
                          if def.typ=arraydef then
                           begin
                             idx:=0;
-                            p:=comp_expr(true,false);
+                            p:=comp_expr(true,[]);
                             if (not codegenerror) then
                              begin
                                if (p.nodetype=ordconstn) then
@@ -279,7 +279,7 @@ implementation
 
               if try_to_consume(_DISPID) then
                 begin
-                  pt:=comp_expr(true,false);
+                  pt:=comp_expr(true,[]);
                   if is_constintnode(pt) then
                     if (Tordconstnode(pt).value<int64(low(longint))) or (Tordconstnode(pt).value>int64(high(longint))) then
                       message(parser_e_range_check_error)
@@ -454,7 +454,7 @@ implementation
               if (idtoken=_INDEX) then
                 begin
                    consume(_INDEX);
-                   pt:=comp_expr(true,false);
+                   pt:=comp_expr(true,[]);
                    { Only allow enum and integer indexes. Convert all integer
                      values to s32int to be compatible with delphi, because the
                      procedure matching requires equal parameters }
@@ -723,14 +723,14 @@ implementation
                 begin
                   Message(parser_e_property_cant_have_a_default_value);
                   { Error recovery }
-                  pt:=comp_expr(true,false);
+                  pt:=comp_expr(true,[]);
                   pt.free;
                 end
               else
                 begin
                   { Get the result of the default, the firstpass is
                     needed to support values like -1 }
-                  pt:=comp_expr(true,false);
+                  pt:=comp_expr(true,[]);
                   if (p.propdef.typ=setdef) and
                      (pt.nodetype=arrayconstructorn) then
                     begin
@@ -1674,11 +1674,11 @@ implementation
               symtablestack.push(UnionSymtable);
               repeat
                 repeat
-                  pt:=comp_expr(true,false);
+                  pt:=comp_expr(true,[]);
                   if not(pt.nodetype=ordconstn) then
                     Message(parser_e_illegal_expression);
                   if try_to_consume(_POINTPOINT) then
-                    pt:=crangenode.create(pt,comp_expr(true,false));
+                    pt:=crangenode.create(pt,comp_expr(true,[]));
                   pt.free;
                   if token=_COMMA then
                     consume(_COMMA)

+ 2 - 2
compiler/pexports.pas

@@ -136,7 +136,7 @@ implementation
                      end;
                     if try_to_consume(_INDEX) then
                      begin
-                       pt:=comp_expr(true,false);
+                       pt:=comp_expr(true,[]);
                        if pt.nodetype=ordconstn then
                         if (Tordconstnode(pt).value<int64(low(index))) or
                            (Tordconstnode(pt).value>int64(high(index))) then
@@ -160,7 +160,7 @@ implementation
                      end;
                     if try_to_consume(_NAME) then
                      begin
-                       pt:=comp_expr(true,false);
+                       pt:=comp_expr(true,[]);
                        if pt.nodetype=stringconstn then
                          hpname:=strpas(tstringconstnode(pt).value_str)
                        else

+ 216 - 107
compiler/pexpr.pas

@@ -30,14 +30,21 @@ interface
       node,ncal,
       tokens,globtype,globals,constexp;
 
+    type
+      TExprOption=(
+        eoTypeOnly,    { search only type names }
+        eoSpecialize   { do specialization      }
+      );
+      TExprOptions = set of TExprOption;
+
     { reads a whole expression }
     function expr(dotypecheck:boolean) : tnode;
 
     { reads an expression without assignements and .. }
-    function comp_expr(accept_equal,typeonly:boolean):tnode;
+    function comp_expr(accept_equal:boolean;options:TExprOptions):tnode;
 
     { reads a single factor }
-    function factor(getaddr,typeonly:boolean) : tnode;
+    function factor(getaddr:boolean;options:TExprOptions) : tnode;
 
     procedure string_dec(var def: tdef; allowtypedef: boolean);
 
@@ -53,7 +60,7 @@ implementation
 
     uses
        { common }
-       cutils,
+       cutils,cclasses,
        { global }
        verbose,
        systems,widestr,
@@ -79,7 +86,7 @@ implementation
     const
       highest_precedence = oppower;
 
-    function sub_expr(pred_level:Toperator_precedence;accept_equal,typeonly:boolean):tnode;forward;
+    function sub_expr(pred_level:Toperator_precedence;accept_equal:boolean;options:TExprOptions):tnode;forward;
 
     const
        { true, if the inherited call is anonymous }
@@ -101,7 +108,7 @@ implementation
               if not(allowtypedef) then
                 Message(parser_e_no_local_para_def);
               consume(_LECKKLAMMER);
-              p:=comp_expr(true,false);
+              p:=comp_expr(true,[]);
               if not is_constintnode(p) then
                 begin
                   Message(parser_e_illegal_expression);
@@ -172,12 +179,12 @@ implementation
                else
                  begin
                    named_args_allowed:=true;
-                   p1:=comp_expr(true,false);
+                   p1:=comp_expr(true,[]);
                    named_args_allowed:=false;
                    if found_arg_name then
                      begin
                        argname:=p1;
-                       p1:=comp_expr(true,false);
+                       p1:=comp_expr(true,[]);
                        p2:=ccallparanode.create(p1,p2);
                        tcallparanode(p2).parametername:=argname;
                      end
@@ -188,19 +195,19 @@ implementation
              end
            else
              begin
-               p1:=comp_expr(true,false);
+               p1:=comp_expr(true,[]);
                p2:=ccallparanode.create(p1,p2);
              end;
            { it's for the str(l:5,s); }
            if __colon and (token=_COLON) then
              begin
                consume(_COLON);
-               p1:=comp_expr(true,false);
+               p1:=comp_expr(true,[]);
                p2:=ccallparanode.create(p1,p2);
                include(tcallparanode(p2).callparaflags,cpf_is_colon_para);
                if try_to_consume(_COLON) then
                  begin
-                   p1:=comp_expr(true,false);
+                   p1:=comp_expr(true,[]);
                    p2:=ccallparanode.create(p1,p2);
                    include(tcallparanode(p2).callparaflags,cpf_is_colon_para);
                  end
@@ -282,7 +289,7 @@ implementation
             begin
               consume(_LKLAMMER);
               in_args:=true;
-              p1:=comp_expr(true,false);
+              p1:=comp_expr(true,[]);
               consume(_RKLAMMER);
               p1:=geninlinenode(in_ord_x,false,p1);
               statement_syssym := p1;
@@ -296,7 +303,7 @@ implementation
                     begin
                       if not(try_to_consume(_RKLAMMER)) then
                         begin
-                          p1:=comp_expr(true,false);
+                          p1:=comp_expr(true,[]);
                           consume(_RKLAMMER);
                           if (not assigned(current_procinfo) or
                               is_void(current_procinfo.procdef.returndef)) then
@@ -360,7 +367,7 @@ implementation
             begin
               consume(_LKLAMMER);
               in_args:=true;
-              p1:=comp_expr(true,false);
+              p1:=comp_expr(true,[]);
               consume(_RKLAMMER);
               if p1.nodetype=typen then
                 ttypenode(p1).allowed:=true;
@@ -386,7 +393,7 @@ implementation
             begin
               consume(_LKLAMMER);
               in_args:=true;
-              p1:=comp_expr(true,false);
+              p1:=comp_expr(true,[]);
               consume(_RKLAMMER);
               if (p1.nodetype<>typen) and
                  (
@@ -431,7 +438,7 @@ implementation
                 begin
                   consume(_LKLAMMER);
                   in_args:=true;
-                  p1:=comp_expr(true,false);
+                  p1:=comp_expr(true,[]);
                   { When reading a class type it is parsed as loadvmtaddrn,
                     typeinfo only needs the type so we remove the loadvmtaddrn }
                   if p1.nodetype=loadvmtaddrn then
@@ -465,7 +472,7 @@ implementation
               err:=false;
               consume(_LKLAMMER);
               in_args:=true;
-              p1:=comp_expr(true,false);
+              p1:=comp_expr(true,[]);
               p2:=ccallparanode.create(p1,nil);
               p2:=geninlinenode(in_unaligned_x,false,p2);
               consume(_RKLAMMER);
@@ -477,7 +484,7 @@ implementation
               err:=false;
               consume(_LKLAMMER);
               in_args:=true;
-              p1:=comp_expr(true,false);
+              p1:=comp_expr(true,[]);
               { When reading a class type it is parsed as loadvmtaddrn,
                 typeinfo only needs the type so we remove the loadvmtaddrn }
               if p1.nodetype=loadvmtaddrn then
@@ -533,7 +540,7 @@ implementation
             begin
               consume(_LKLAMMER);
               in_args:=true;
-              p1:=comp_expr(true,false);
+              p1:=comp_expr(true,[]);
               p1:=caddrnode.create(p1);
               consume(_RKLAMMER);
               statement_syssym:=p1;
@@ -543,7 +550,7 @@ implementation
             begin
               consume(_LKLAMMER);
               in_args:=true;
-              p1:=comp_expr(true,false);
+              p1:=comp_expr(true,[]);
               p1:=caddrnode.create(p1);
               do_typecheckpass(p1);
               { Ofs() returns a cardinal/qword, not a pointer }
@@ -556,7 +563,7 @@ implementation
             begin
               consume(_LKLAMMER);
               in_args:=true;
-              p1:=comp_expr(true,false);
+              p1:=comp_expr(true,[]);
               p1:=geninlinenode(in_seg_x,false,p1);
               consume(_RKLAMMER);
               statement_syssym:=p1;
@@ -567,7 +574,7 @@ implementation
             begin
               consume(_LKLAMMER);
               in_args:=true;
-              p1:=comp_expr(true,false);
+              p1:=comp_expr(true,[]);
               p2:=geninlinenode(l,false,p1);
               consume(_RKLAMMER);
               statement_syssym:=p2;
@@ -578,7 +585,7 @@ implementation
             begin
               consume(_LKLAMMER);
               in_args:=true;
-              p1:=comp_expr(true,false);
+              p1:=comp_expr(true,[]);
               p2:=geninlinenode(l,false,p1);
               consume(_RKLAMMER);
               statement_syssym:=p2;
@@ -589,9 +596,9 @@ implementation
             begin
               consume(_LKLAMMER);
               in_args:=true;
-              p1:=comp_expr(true,false);
+              p1:=comp_expr(true,[]);
               if try_to_consume(_COMMA) then
-                p2:=ccallparanode.create(comp_expr(true,false),nil)
+                p2:=ccallparanode.create(comp_expr(true,[]),nil)
               else
                 p2:=nil;
               p2:=ccallparanode.create(p1,p2);
@@ -606,9 +613,9 @@ implementation
                   message(parser_e_illegal_slice);
                   consume(_LKLAMMER);
                   in_args:=true;
-                  comp_expr(true,false).free;
+                  comp_expr(true,[]).free;
                   if try_to_consume(_COMMA) then
-                    comp_expr(true,false).free;
+                    comp_expr(true,[]).free;
                   statement_syssym:=cerrornode.create;
                   consume(_RKLAMMER);
                 end
@@ -616,10 +623,10 @@ implementation
                 begin
                   consume(_LKLAMMER);
                   in_args:=true;
-                  p1:=comp_expr(true,false);
+                  p1:=comp_expr(true,[]);
                   Consume(_COMMA);
                   if not(codegenerror) then
-                    p2:=ccallparanode.create(comp_expr(true,false),nil)
+                    p2:=ccallparanode.create(comp_expr(true,[]),nil)
                   else
                     p2:=cerrornode.create;
                   p2:=ccallparanode.create(p1,p2);
@@ -651,7 +658,7 @@ implementation
                 type checking }
               p2:=nil;
               repeat
-                p1:=comp_expr(true,false);
+                p1:=comp_expr(true,[]);
                 if p2<>nil then
                   p2:=caddnode.create(addn,p2,p1)
                 else
@@ -697,7 +704,7 @@ implementation
                   consume(_LKLAMMER);
                   in_args:=true;
                   { don't turn procsyms into calls (getaddr = true) }
-                  p1:=factor(true,false);
+                  p1:=factor(true,[]);
                   p2:=geninlinenode(l,false,p1);
                   consume(_RKLAMMER);
                   statement_syssym:=p2;
@@ -712,7 +719,7 @@ implementation
             begin
               consume(_LKLAMMER);
               in_args:=true;
-              p1:=comp_expr(true,false);
+              p1:=comp_expr(true,[]);
               p2:=geninlinenode(l,false,p1);
               consume(_RKLAMMER);
               statement_syssym:=p2;
@@ -746,11 +753,11 @@ implementation
             Begin
               consume(_LKLAMMER);
               in_args := true;
-              p1:= ccallparanode.create(comp_expr(true,false), nil);
+              p1:= ccallparanode.create(comp_expr(true,[]), nil);
               consume(_COMMA);
-              p2 := ccallparanode.create(comp_expr(true,false),p1);
+              p2 := ccallparanode.create(comp_expr(true,[]),p1);
               if try_to_consume(_COMMA) then
-                p2 := ccallparanode.create(comp_expr(true,false),p2);
+                p2 := ccallparanode.create(comp_expr(true,[]),p2);
               consume(_RKLAMMER);
               p2 := geninlinenode(l,false,p2);
               statement_syssym := p2;
@@ -761,9 +768,9 @@ implementation
             begin
               consume(_LKLAMMER);
               in_args:=true;
-              p1:=comp_expr(true,false);
+              p1:=comp_expr(true,[]);
               consume(_COMMA);
-              p2:=comp_expr(true,false);
+              p2:=comp_expr(true,[]);
               statement_syssym:=geninlinenode(l,false,ccallparanode.create(p1,ccallparanode.create(p2,nil)));
               consume(_RKLAMMER);
             end;
@@ -773,11 +780,11 @@ implementation
             begin
               consume(_LKLAMMER);
               in_args:=true;
-              p1:=comp_expr(true,false);
+              p1:=comp_expr(true,[]);
               consume(_COMMA);
-              p2:=comp_expr(true,false);
+              p2:=comp_expr(true,[]);
               consume(_COMMA);
-              paras:=comp_expr(true,false);
+              paras:=comp_expr(true,[]);
               statement_syssym:=geninlinenode(l,false,ccallparanode.create(p1,ccallparanode.create(p2,ccallparanode.create(paras,nil))));
               consume(_RKLAMMER);
             end;
@@ -786,9 +793,9 @@ implementation
             begin
               consume(_LKLAMMER);
               in_args:=true;
-              p1:=comp_expr(true,false);
+              p1:=comp_expr(true,[]);
               if try_to_consume(_COMMA) then
-                 p2:=comp_expr(true,false)
+                 p2:=comp_expr(true,[])
               else
                begin
                  { then insert an empty string }
@@ -1093,7 +1100,7 @@ implementation
                          { read the expression }
                          if propsym.propdef.typ=procvardef then
                            getprocvardef:=tprocvardef(propsym.propdef);
-                         p2:=comp_expr(true,false);
+                         p2:=comp_expr(true,[]);
                          if assigned(getprocvardef) then
                            handle_procvar(getprocvardef,p2);
                          tcallnode(p1).left:=ccallparanode.create(p2,tcallnode(p1).left);
@@ -1109,7 +1116,7 @@ implementation
                          include(p1.flags,nf_isproperty);
                          consume(_ASSIGNMENT);
                          { read the expression }
-                         p2:=comp_expr(true,false);
+                         p2:=comp_expr(true,[]);
                          p1:=cassignmentnode.create(p1,p2);
                       end
                     else
@@ -1121,8 +1128,8 @@ implementation
                 end
               else
                 begin
-                   p1:=cerrornode.create;
-                   Message(parser_e_no_procedure_to_access_property);
+                  p1:=cerrornode.create;
+                  Message(parser_e_no_procedure_to_access_property);
                 end;
            end
          else
@@ -1240,7 +1247,7 @@ implementation
                      p1.free;
                      if try_to_consume(_LKLAMMER) then
                       begin
-                        p1:=comp_expr(true,false);
+                        p1:=comp_expr(true,[]);
                         consume(_RKLAMMER);
                         p1:=ctypeconvnode.create_explicit(p1,ttypesym(sym).typedef);
                       end
@@ -1318,9 +1325,43 @@ implementation
         end;
       end;
 
+    function get_generic_id_modifier:TIDString;
+      var
+        savedstate:tscannerstate;
+        typeparamcount:integer;
+      begin
+        { this functions test the token stream that it contains a valid
+          <TypeParam1, TypeParam2> sequence and if it so it returns that
+          sequence mask like <,> for the given example. if the sequence
+          is not valid the return value is an empty string }
+        result:='';
+        { to safely search the token stream we need to save it state and restore
+          it later }
+        savedstate:=current_scanner.savestate;
+        try
+          { sequnce must start with '<' symbol which under different conditions
+            maps either to _LSHARPBRACKET or to _LT token }
+          if not (try_to_consume(_LSHARPBRACKET) or try_to_consume(_LT)) then
+            exit;
+          typeparamcount:=0;
+          repeat
+            inc(typeparamcount);
+            { stop sequnce search if token is suspicious }
+            while not (token in ([_RSHARPBRACKET,_GT,_COMMA,_EOF] + endtokens)) do
+              consume(token);
+          until not try_to_consume(_COMMA);
+          { sequnce must finish with '>' symbol wich similar maps to 2 tokens }
+          if not (try_to_consume(_RSHARPBRACKET) or try_to_consume(_GT)) then
+            exit;
+          result:=generate_generic_id_modifier(typeparamcount);
+        finally
+          current_scanner.restorestate(savedstate);
+        end;
+      end;
+
   {$maxfpuregisters 0}
 
-    function factor(getaddr,typeonly:boolean) : tnode;
+    function factor(getaddr:boolean;options:TExprOptions) : tnode;
 
          {---------------------------------------------
                          Factor_read_id
@@ -1332,13 +1373,16 @@ implementation
            srsymtable : TSymtable;
            hdef  : tdef;
            orgstoredpattern,
-           storedpattern : string;
+           storedpattern, generic_id_modifier : string;
            callflags: tcallnodeflags;
            t : ttoken;
            unit_found : boolean;
+           structdef : tabstractrecorddef;
+           typeparams: TFPObjectList;
          begin
            { allow post fix operators }
            again:=true;
+           typeparams:=nil;
 
            { first check for identifier }
            if token<>_ID then
@@ -1349,17 +1393,65 @@ implementation
              end
            else
              begin
-               if typeonly then
-                 searchsym_type(pattern,srsym,srsymtable)
-               else
-                 searchsym(pattern,srsym,srsymtable);
-
-               { handle unit specification like System.Writeln }
-               unit_found:=try_consume_unitsym(srsym,srsymtable,t);
                storedpattern:=pattern;
                orgstoredpattern:=orgpattern;
-               consume(t);
+               consume(_ID);
+               if eoTypeOnly in options then
+                 begin
+                   { searching a generic }
+                   if (eoSpecialize in options) or
+                      ((m_delphi in current_settings.modeswitches) and  (token=_LSHARPBRACKET)) then
+                     begin
+                       typeparams:=TFPObjectList.Create(true);
+                       consume(_LSHARPBRACKET);
+                       repeat
+                         typeparams.add(factor(false,[eoTypeOnly]));
+                       until not try_to_consume(_COMMA);
+                       consume(_RSHARPBRACKET);
+                       generic_id_modifier:=generate_generic_id_modifier(typeparams.count);
+                       { modify patterns }
+                       storedpattern:=storedpattern+generic_id_modifier;
+                       orgstoredpattern:=orgstoredpattern+generic_id_modifier;
+                     end;
+                   searchsym_type(storedpattern,srsym,srsymtable);
+                 end
+               else
+                 begin
+                   srsym:=nil;
+                   { this can be a generic }
+                   if (eoSpecialize in options) or
+                      ((token=_LT) and (m_delphi in current_settings.modeswitches)) then
+                     begin
+                       generic_id_modifier:=get_generic_id_modifier;
+                       if generic_id_modifier<>'' then
+                         begin
+                           searchsym(storedpattern+generic_id_modifier,srsym,srsymtable);
+                           if assigned(srsym) then
+                             begin
+                               typeparams:=TFPObjectList.Create(true);
+                               consume(_LT);
+                               repeat
+                                 typeparams.add(factor(false,[eoTypeOnly]));
+                               until not try_to_consume(_COMMA);
+                               consume(_GT);
+                               { modify patterns }
+                               storedpattern:=storedpattern+generic_id_modifier;
+                               orgstoredpattern:=orgstoredpattern+generic_id_modifier;
+                             end;
+                         end;
+                     end;
+                   if not assigned(srsym) then
+                     searchsym(storedpattern,srsym,srsymtable);
+                 end;
 
+               { handle unit specification like System.Writeln }
+               unit_found:=try_consume_unitsym(srsym,srsymtable,t,false);
+               if unit_found then
+                 begin
+                   storedpattern:=pattern;
+                   orgstoredpattern:=orgpattern;
+                   consume(t);
+                 end;
                { named parameter support }
                found_arg_name:=false;
 
@@ -1370,6 +1462,7 @@ implementation
                     found_arg_name:=true;
                     p1:=cstringconstnode.createstr(storedpattern);
                     consume(_ASSIGNMENT);
+                    typeparams.free;
                     exit;
                   end;
                { if nothing found give error and return errorsym }
@@ -1475,18 +1568,33 @@ implementation
                      end
                     else
                      begin
+                       if hdef.typ=errordef then
+                         begin
+                           structdef:=current_structdef;
+                           while assigned(structdef) and (structdef.typ in [objectdef,recorddef]) do
+                             begin
+                               if (structdef.objname^=storedpattern) then
+                                 begin
+                                   hdef:=structdef;
+                                   if assigned(typeparams) then
+                                     generate_specialization(hdef,typeparams,false);
+                                   p1:=ctypenode.create(hdef);
+                                   typeparams.free;
+                                   exit;
+                                 end;
+                               structdef:=tabstractrecorddef(structdef.owner.defowner);
+                             end;
+                         end;
                        { We need to know if this unit uses Variants }
                        if (hdef=cvarianttype) and
                           not(cs_compilesystem in current_settings.moduleswitches) then
                          current_module.flags:=current_module.flags or uf_uses_variants;
                        { if we get a generic then check that it is not an inline specialization }
-                       if (df_generic in hdef.defoptions) and
-                          (token=_LT) and
-                          (m_delphi in current_settings.modeswitches) then
-                          generate_specialization(hdef,false);
+                       if assigned(typeparams) then
+                          generate_specialization(hdef,typeparams,false);
                        if try_to_consume(_LKLAMMER) then
                         begin
-                          p1:=comp_expr(true,false);
+                          p1:=comp_expr(true,[]);
                           consume(_RKLAMMER);
                           p1:=ctypeconvnode.create_explicit(p1,hdef);
                         end
@@ -1687,6 +1795,7 @@ implementation
                   end;
               end; { end case }
             end;
+            typeparams.free;
          end;
 
          {---------------------------------------------
@@ -1711,10 +1820,10 @@ implementation
               { nested array constructors are not allowed, see also tests/webtbs/tw17213.pp }
               old_allow_array_constructor:=allow_array_constructor;
               allow_array_constructor:=false;
-              p1:=comp_expr(true,false);
+              p1:=comp_expr(true,[]);
               if try_to_consume(_POINTPOINT) then
                 begin
-                  p2:=comp_expr(true,false);
+                  p2:=comp_expr(true,[]);
                   p1:=carrayconstructorrangenode.create(p1,p2);
                 end;
                { insert at the end of the tree, to get the correct order }
@@ -1752,14 +1861,14 @@ implementation
                 else if try_to_consume(_LECKKLAMMER) then
                   begin
                     repeat
-                      comp_expr(true,false);
+                      comp_expr(true,[]);
                     until not try_to_consume(_COMMA);
                     consume(_RECKKLAMMER);
                   end
                 else if try_to_consume(_LKLAMMER) then
                   begin
                     repeat
-                      comp_expr(true,false);
+                      comp_expr(true,[]);
                     until not try_to_consume(_COMMA);
                     consume(_RKLAMMER);
                   end
@@ -1790,7 +1899,7 @@ implementation
 
             countindices:=0;
             repeat
-              p4:=comp_expr(true,false);
+              p4:=comp_expr(true,[]);
 
               addstatement(newstatement,cassignmentnode.create(
                 ctemprefnode.create_offset(temp,countindices*s32inttype.size),p4));
@@ -1806,7 +1915,7 @@ implementation
             if token=_ASSIGNMENT then
               begin
                 consume(_ASSIGNMENT);
-                p4:=comp_expr(true,false);
+                p4:=comp_expr(true,[]);
 
                 { create call to fpc_vararray_put }
                 paras:=ccallparanode.create(cordconstnode.create
@@ -1937,10 +2046,10 @@ implementation
                                  if (tpointerdef(p1.resultdef).pointeddef.typ=arraydef) and
                                     (m_autoderef in current_settings.modeswitches) then
                                    p1:=cderefnode.create(p1);
-                                 p2:=comp_expr(true,false);
+                                 p2:=comp_expr(true,[]);
                                  { Support Pbytevar[0..9] which returns array [0..9].}
                                  if try_to_consume(_POINTPOINT) then
-                                   p2:=crangenode.create(p2,comp_expr(true,false));
+                                   p2:=crangenode.create(p2,comp_expr(true,[]));
                                  p1:=cvecnode.create(p1,p2);
                               end;
                             variantdef:
@@ -1951,15 +2060,15 @@ implementation
                               end;
                             stringdef :
                               begin
-                                p2:=comp_expr(true,false);
+                                p2:=comp_expr(true,[]);
                                 { Support string[0..9] which returns array [0..9] of char.}
                                 if try_to_consume(_POINTPOINT) then
-                                  p2:=crangenode.create(p2,comp_expr(true,false));
+                                  p2:=crangenode.create(p2,comp_expr(true,[]));
                                 p1:=cvecnode.create(p1,p2);
                               end;
                             arraydef:
                               begin
-                                p2:=comp_expr(true,false);
+                                p2:=comp_expr(true,[]);
                                 { support SEG:OFS for go32v2 Mem[] }
                                 if (target_info.system in [system_i386_go32v2,system_i386_watcom]) and
                                    (p1.nodetype=loadn) and
@@ -1973,11 +2082,11 @@ implementation
                                     if try_to_consume(_COLON) then
                                      begin
                                        p3:=caddnode.create(muln,cordconstnode.create($10,s32inttype,false),p2);
-                                       p2:=comp_expr(true,false);
+                                       p2:=comp_expr(true,[]);
                                        p2:=caddnode.create(addn,p2,p3);
                                        if try_to_consume(_POINTPOINT) then
                                          { Support mem[$a000:$0000..$07ff] which returns array [0..$7ff] of memtype.}
-                                         p2:=crangenode.create(p2,caddnode.create(addn,comp_expr(true,false),p3.getcopy));
+                                         p2:=crangenode.create(p2,caddnode.create(addn,comp_expr(true,[]),p3.getcopy));
                                        p1:=cvecnode.create(p1,p2);
                                        include(tvecnode(p1).flags,nf_memseg);
                                        include(tvecnode(p1).flags,nf_memindex);
@@ -1986,7 +2095,7 @@ implementation
                                      begin
                                        if try_to_consume(_POINTPOINT) then
                                          { Support mem[$80000000..$80000002] which returns array [0..2] of memtype.}
-                                         p2:=crangenode.create(p2,comp_expr(true,false));
+                                         p2:=crangenode.create(p2,comp_expr(true,[]));
                                        p1:=cvecnode.create(p1,p2);
                                        include(tvecnode(p1).flags,nf_memindex);
                                      end;
@@ -1995,7 +2104,7 @@ implementation
                                   begin
                                     if try_to_consume(_POINTPOINT) then
                                       { Support arrayvar[0..9] which returns array [0..9] of arraytype.}
-                                      p2:=crangenode.create(p2,comp_expr(true,false));
+                                      p2:=crangenode.create(p2,comp_expr(true,[]));
                                     p1:=cvecnode.create(p1,p2);
                                   end;
                               end;
@@ -2005,7 +2114,7 @@ implementation
                                   Message(parser_e_invalid_qualifier);
                                 p1.destroy;
                                 p1:=cerrornode.create;
-                                comp_expr(true,false);
+                                comp_expr(true,[]);
                                 again:=false;
                               end;
                           end;
@@ -2096,7 +2205,7 @@ implementation
                                  begin
                                    consume(_ASSIGNMENT);
                                    { read the expression }
-                                   p3:=comp_expr(true,false);
+                                   p3:=comp_expr(true,[]);
                                    { concat value parameter too }
                                    p2:=ccallparanode.create(p3,p2);
                                    p1:=translate_disp_call(p1,p2,dct_propput,dispatchstring,0,voidtype);
@@ -2216,7 +2325,7 @@ implementation
                          begin
                            if try_to_consume(_LKLAMMER) then
                              begin
-                               p1:=comp_expr(true,false);
+                               p1:=comp_expr(true,[]);
                                consume(_RKLAMMER);
                                p1:=ctypeconvnode.create_explicit(p1,p1.resultdef);
                              end
@@ -2277,7 +2386,7 @@ implementation
          filepos    : tfileposinfo;
          again,
          updatefpos,
-         nodechanged  : boolean;
+         nodechanged : boolean;
       begin
         { can't keep a copy of p1 and compare pointers afterwards, because
           p1 may be freed and reallocated in the same place!  }
@@ -2319,7 +2428,7 @@ implementation
                 begin
                   consume(_RETURN);
                   if not(token in [_SEMICOLON,_ELSE,_END]) then
-                    p1 := cexitnode.create(comp_expr(true,false))
+                    p1 := cexitnode.create(comp_expr(true,[]))
                   else
                     p1 := cexitnode.create(nil);
                 end;
@@ -2506,7 +2615,7 @@ implementation
                  { STRING can be also a type cast }
                  if try_to_consume(_LKLAMMER) then
                   begin
-                    p1:=comp_expr(true,false);
+                    p1:=comp_expr(true,[]);
                     consume(_RKLAMMER);
                     p1:=ctypeconvnode.create_explicit(p1,hdef);
                     { handle postfix operators here e.g. string(a)[10] }
@@ -2524,7 +2633,7 @@ implementation
                  { FILE can be also a type cast }
                  if try_to_consume(_LKLAMMER) then
                   begin
-                    p1:=comp_expr(true,false);
+                    p1:=comp_expr(true,[]);
                     consume(_RKLAMMER);
                     p1:=ctypeconvnode.create_explicit(p1,hdef);
                     { handle postfix operators here e.g. string(a)[10] }
@@ -2568,7 +2677,7 @@ implementation
                  { support both @<x> and @(<x>) }
                  if try_to_consume(_LKLAMMER) then
                   begin
-                    p1:=factor(true,false);
+                    p1:=factor(true,[]);
                     if token in [_CARET,_POINT,_LECKKLAMMER] then
                      begin
                        again:=true;
@@ -2578,7 +2687,7 @@ implementation
                     consume(_RKLAMMER);
                   end
                  else
-                  p1:=factor(true,false);
+                  p1:=factor(true,[]);
                  if token in [_CARET,_POINT,_LECKKLAMMER] then
                   begin
                     again:=true;
@@ -2600,7 +2709,7 @@ implementation
              _LKLAMMER :
                begin
                  consume(_LKLAMMER);
-                 p1:=comp_expr(true,false);
+                 p1:=comp_expr(true,[]);
                  consume(_RKLAMMER);
                  { it's not a good solution     }
                  { but (a+b)^ makes some problems  }
@@ -2621,7 +2730,7 @@ implementation
              _PLUS :
                begin
                  consume(_PLUS);
-                 p1:=factor(false,false);
+                 p1:=factor(false,[]);
                  p1:=cunaryplusnode.create(p1);
                end;
 
@@ -2633,7 +2742,7 @@ implementation
                       { ugly hack, but necessary to be able to parse }
                       { -9223372036854775808 as int64 (JM)           }
                       pattern := '-'+pattern;
-                      p1:=sub_expr(oppower,false,false);
+                      p1:=sub_expr(oppower,false,[]);
                       {  -1 ** 4 should be - (1 ** 4) and not
                          (-1) ** 4
                          This was the reason of tw0869.pp test failure PM }
@@ -2656,7 +2765,7 @@ implementation
                     end
                  else
                    begin
-                     p1:=sub_expr(oppower,false,false);
+                     p1:=sub_expr(oppower,false,[]);
                      p1:=cunaryminusnode.create(p1);
                    end;
                end;
@@ -2664,7 +2773,7 @@ implementation
              _OP_NOT :
                begin
                  consume(_OP_NOT);
-                 p1:=factor(false,false);
+                 p1:=factor(false,[]);
                  p1:=cnotnode.create(p1);
                end;
 
@@ -2702,7 +2811,7 @@ implementation
                }
                consume(_OBJCPROTOCOL);
                consume(_LKLAMMER);
-               p1:=factor(false,false);
+               p1:=factor(false,[]);
                consume(_RKLAMMER);
                p1:=cinlinenode.create(in_objc_protocol_x,false,p1);
              end;
@@ -2753,7 +2862,7 @@ implementation
            _OP_AS,_OP_IS,_OP_AND,_AMPERSAND,_OP_DIV,_OP_MOD,_OP_SHL,_OP_SHR],
           [_STARSTAR] );
 
-    function sub_expr(pred_level:Toperator_precedence;accept_equal,typeonly:boolean):tnode;
+    function sub_expr(pred_level:Toperator_precedence;accept_equal:boolean;options:TExprOptions):tnode;
     {Reads a subexpression while the operators are of the current precedence
      level, or any higher level. Replaces the old term, simpl_expr and
      simpl2_expr.}
@@ -2763,9 +2872,9 @@ implementation
         filepos : tfileposinfo;
       begin
         if pred_level=highest_precedence then
-          p1:=factor(false,typeonly)
+          p1:=factor(false,options)
         else
-          p1:=sub_expr(succ(pred_level),true,typeonly);
+          p1:=sub_expr(succ(pred_level),true,options);
         repeat
           if (token in operator_levels[pred_level]) and
              ((token<>_EQ) or accept_equal) then
@@ -2774,9 +2883,9 @@ implementation
              filepos:=current_tokenpos;
              consume(token);
              if pred_level=highest_precedence then
-               p2:=factor(false,false)
+               p2:=factor(false,[])
              else
-               p2:=sub_expr(succ(pred_level),true,typeonly);
+               p2:=sub_expr(succ(pred_level),true,options);
              case oldt of
                _PLUS :
                  p1:=caddnode.create(addn,p1,p2);
@@ -2846,14 +2955,14 @@ implementation
       end;
 
 
-    function comp_expr(accept_equal,typeonly:boolean):tnode;
+    function comp_expr(accept_equal:boolean;options:TExprOptions):tnode;
       var
          oldafterassignment : boolean;
          p1 : tnode;
       begin
          oldafterassignment:=afterassignment;
          afterassignment:=true;
-         p1:=sub_expr(opcompare,accept_equal,typeonly);
+         p1:=sub_expr(opcompare,accept_equal,options);
          { get the resultdef for this expression }
          if not assigned(p1.resultdef) then
           do_typecheckpass(p1);
@@ -2872,7 +2981,7 @@ implementation
 
       begin
          oldafterassignment:=afterassignment;
-         p1:=sub_expr(opcompare,true,false);
+         p1:=sub_expr(opcompare,true,[]);
          { get the resultdef for this expression }
          if not assigned(p1.resultdef) and
             dotypecheck then
@@ -2885,7 +2994,7 @@ implementation
            _POINTPOINT :
              begin
                 consume(_POINTPOINT);
-                p2:=sub_expr(opcompare,true,false);
+                p2:=sub_expr(opcompare,true,[]);
                 p1:=crangenode.create(p1,p2);
              end;
            _ASSIGNMENT :
@@ -2893,7 +3002,7 @@ implementation
                 consume(_ASSIGNMENT);
                 if (p1.resultdef.typ=procvardef) then
                   getprocvardef:=tprocvardef(p1.resultdef);
-                p2:=sub_expr(opcompare,true,false);
+                p2:=sub_expr(opcompare,true,[]);
                 if assigned(getprocvardef) then
                   handle_procvar(getprocvardef,p2);
                 getprocvardef:=nil;
@@ -2902,25 +3011,25 @@ implementation
            _PLUSASN :
              begin
                consume(_PLUSASN);
-               p2:=sub_expr(opcompare,true,false);
+               p2:=sub_expr(opcompare,true,[]);
                p1:=gen_c_style_operator(addn,p1,p2);
             end;
           _MINUSASN :
             begin
                consume(_MINUSASN);
-               p2:=sub_expr(opcompare,true,false);
+               p2:=sub_expr(opcompare,true,[]);
                p1:=gen_c_style_operator(subn,p1,p2);
             end;
           _STARASN :
             begin
                consume(_STARASN  );
-               p2:=sub_expr(opcompare,true,false);
+               p2:=sub_expr(opcompare,true,[]);
                p1:=gen_c_style_operator(muln,p1,p2);
             end;
           _SLASHASN :
             begin
                consume(_SLASHASN  );
-               p2:=sub_expr(opcompare,true,false);
+               p2:=sub_expr(opcompare,true,[]);
                p1:=gen_c_style_operator(slashn,p1,p2);
             end;
           else
@@ -2943,7 +3052,7 @@ implementation
       p:tnode;
     begin
       result:=0;
-      p:=comp_expr(true,false);
+      p:=comp_expr(true,[]);
       if not codegenerror then
        begin
          if (p.nodetype<>ordconstn) or
@@ -2963,7 +3072,7 @@ implementation
       p:tnode;
     begin
       get_stringconst:='';
-      p:=comp_expr(true,false);
+      p:=comp_expr(true,[]);
       if p.nodetype<>stringconstn then
         begin
           if (p.nodetype=ordconstn) and is_char(p.resultdef) then

+ 5 - 5
compiler/pinline.pas

@@ -76,7 +76,7 @@ implementation
         storepos : tfileposinfo;
       begin
         consume(_LKLAMMER);
-        p:=comp_expr(true,false);
+        p:=comp_expr(true,[]);
         { calc return type }
         if is_new then
           begin
@@ -161,7 +161,7 @@ implementation
               begin
                  Message1(type_e_pointer_type_expected,p.resultdef.typename);
                  p.free;
-                 p:=factor(false,false);
+                 p:=factor(false,[]);
                  p.free;
                  consume(_RKLAMMER);
                  new_dispose_statement:=cerrornode.create;
@@ -172,7 +172,7 @@ implementation
               begin
                  Message(parser_e_pointer_to_class_expected);
                  p.free;
-                 new_dispose_statement:=factor(false,false);
+                 new_dispose_statement:=factor(false,[]);
                  consume_all_until(_RKLAMMER);
                  consume(_RKLAMMER);
                  exit;
@@ -182,7 +182,7 @@ implementation
             if is_class(classh) then
               begin
                  Message(parser_e_no_new_or_dispose_for_classes);
-                 new_dispose_statement:=factor(false,false);
+                 new_dispose_statement:=factor(false,[]);
                  consume_all_until(_RKLAMMER);
                  consume(_RKLAMMER);
                  exit;
@@ -353,7 +353,7 @@ implementation
         again  : boolean; { dummy for do_proc_call }
       begin
         consume(_LKLAMMER);
-        p1:=factor(false,false);
+        p1:=factor(false,[]);
         if p1.nodetype<>typen then
          begin
            Message(type_e_type_id_expected);

+ 2 - 2
compiler/pp.lpi

@@ -25,7 +25,7 @@
     <RunParams>
       <local>
         <FormatVersion Value="1"/>
-        <CommandLineParams Value="-n @\home\florian\bin\fpc.cfg \home\florian\fpc\tests\test\cg\tsar1.pp"/>
+        <CommandLineParams Value="-B  -MObjFPC -Scghi -O1 -gl -vewnhi -l -Fic:\programming\mytest\fpctest\extended_records\operators\lib\i86-win32 -FuC:\programming\mytest\fpctest\generics\bootstrap\ -Fu. -FUc:\programming\mytest\fpctest\extended_records\operators\lib\i386-win32\ -oextended_records1.exe C:\programming\mytest\fpctest\generics\bootstrap\project1.lpr"/>
         <LaunchingApplication PathPlusParams="\usr\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/>
       </local>
     </RunParams>
@@ -78,7 +78,7 @@
       <CompilerMessages>
         <UseMsgFile Value="True"/>
       </CompilerMessages>
-      <CustomOptions Value="-di386"/>
+      <CustomOptions Value="-di386 -godwarfsets"/>
       <CompilerPath Value="$(CompPath)"/>
     </Other>
   </CompilerOptions>

+ 12 - 12
compiler/pstatmnt.pas

@@ -71,7 +71,7 @@ implementation
          ex,if_a,else_a : tnode;
       begin
          consume(_IF);
-         ex:=comp_expr(true,false);
+         ex:=comp_expr(true,[]);
          consume(_THEN);
          if token<>_ELSE then
            if_a:=statement
@@ -125,7 +125,7 @@ implementation
          casenode : tcasenode;
       begin
          consume(_CASE);
-         caseexpr:=comp_expr(true,false);
+         caseexpr:=comp_expr(true,[]);
          { determines result type }
          do_typecheckpass(caseexpr);
          { variants must be accepted, but first they must be converted to integer }
@@ -300,7 +300,7 @@ implementation
          consume(_UNTIL);
 
          first:=cblocknode.create(first);
-         p_e:=comp_expr(true,false);
+         p_e:=comp_expr(true,[]);
          result:=cwhilerepeatnode.create(p_e,first,false,true);
       end;
 
@@ -312,7 +312,7 @@ implementation
 
       begin
          consume(_WHILE);
-         p_e:=comp_expr(true,false);
+         p_e:=comp_expr(true,[]);
          consume(_DO);
          p_a:=statement;
          result:=cwhilerepeatnode.create(p_e,p_a,true,false);
@@ -424,7 +424,7 @@ implementation
              else
                MessagePos(hloopvar.fileinfo,type_e_illegal_count_var);
 
-             hfrom:=comp_expr(true,false);
+             hfrom:=comp_expr(true,[]);
 
              if try_to_consume(_DOWNTO) then
                backward:=true
@@ -434,7 +434,7 @@ implementation
                  backward:=false;
                end;
 
-             hto:=comp_expr(true,false);
+             hto:=comp_expr(true,[]);
              consume(_DO);
 
              { Check if the constants fit in the range }
@@ -471,7 +471,7 @@ implementation
             var
               expr: tnode;
             begin
-              expr:=comp_expr(true,false);
+              expr:=comp_expr(true,[]);
 
               consume(_DO);
 
@@ -490,7 +490,7 @@ implementation
          { parse loop header }
          consume(_FOR);
 
-         hloopvar:=factor(false,false);
+         hloopvar:=factor(false,[]);
          valid_for_loopvar(hloopvar,true);
 
          if try_to_consume(_ASSIGNMENT) then
@@ -533,7 +533,7 @@ implementation
 
 
       begin
-         p:=comp_expr(true,false);
+         p:=comp_expr(true,[]);
          do_typecheckpass(p);
 
          if (p.nodetype=vecn) and
@@ -725,12 +725,12 @@ implementation
          if not(token in endtokens) then
            begin
               { object }
-              pobj:=comp_expr(true,false);
+              pobj:=comp_expr(true,[]);
               if try_to_consume(_AT) then
                 begin
-                   paddr:=comp_expr(true,false);
+                   paddr:=comp_expr(true,[]);
                    if try_to_consume(_COMMA) then
-                     pframe:=comp_expr(true,false);
+                     pframe:=comp_expr(true,[]);
                 end;
            end
          else

+ 13 - 13
compiler/ptconst.pas

@@ -191,7 +191,7 @@ implementation
           end;
 
         begin
-           n:=comp_expr(true,false);
+           n:=comp_expr(true,[]);
            { for C-style booleans, true=-1 and false=0) }
            if is_cbool(def) then
              inserttypeconv(n,def);
@@ -291,7 +291,7 @@ implementation
           n : tnode;
           value : bestreal;
         begin
-          n:=comp_expr(true,false);
+          n:=comp_expr(true,[]);
           if is_constrealnode(n) then
             value:=trealconstnode(n).value_real
           else if is_constintnode(n) then
@@ -332,7 +332,7 @@ implementation
         var
           n : tnode;
         begin
-          n:=comp_expr(true,false);
+          n:=comp_expr(true,[]);
           case n.nodetype of
             loadvmtaddrn:
               begin
@@ -369,7 +369,7 @@ implementation
           ll        : tasmlabel;
           varalign  : shortint;
         begin
-          p:=comp_expr(true,false);
+          p:=comp_expr(true,[]);
           { remove equal typecasts for pointer/nil addresses }
           if (p.nodetype=typeconvn) then
             with Ttypeconvnode(p) do
@@ -587,7 +587,7 @@ implementation
           p : tnode;
           i : longint;
         begin
-          p:=comp_expr(true,false);
+          p:=comp_expr(true,[]);
           if p.nodetype=setconstn then
             begin
               { be sure to convert to the correct result, else
@@ -622,7 +622,7 @@ implementation
         var
           p : tnode;
         begin
-          p:=comp_expr(true,false);
+          p:=comp_expr(true,[]);
           if p.nodetype=ordconstn then
             begin
               if equal_defs(p.resultdef,def) or
@@ -653,7 +653,7 @@ implementation
           ca        : pchar;
           winlike   : boolean;
         begin
-          n:=comp_expr(true,false);
+          n:=comp_expr(true,[]);
           { load strval and strlength of the constant tree }
           if (n.nodetype=stringconstn) or is_wide_or_unicode_string(def) or is_constwidecharnode(n) or
             ((n.nodetype=typen) and is_interfacecorba(ttypenode(n).typedef)) then
@@ -772,7 +772,7 @@ implementation
             n : tnode;
           begin
             result:=true;
-            n:=comp_expr(true,false);
+            n:=comp_expr(true,[]);
             if (n.nodetype <> ordconstn) or
                (not equal_defs(n.resultdef,def) and
                 not is_subequal(n.resultdef,def)) then
@@ -873,7 +873,7 @@ implementation
           else if is_anychar(def.elementdef) then
             begin
                char_size:=def.elementdef.size;
-               n:=comp_expr(true,false);
+               n:=comp_expr(true,[]);
                if n.nodetype=stringconstn then
                  begin
                    len:=tstringconstnode(n).len;
@@ -970,7 +970,7 @@ implementation
             Message(parser_e_no_procvarobj_const);
           { parse the rest too, so we can continue with error checking }
           getprocvardef:=def;
-          n:=comp_expr(true,false);
+          n:=comp_expr(true,[]);
           getprocvardef:=nil;
           if codegenerror then
             begin
@@ -1062,7 +1062,7 @@ implementation
           { GUID }
           if (def=rec_tguid) and (token=_ID) then
             begin
-              n:=comp_expr(true,false);
+              n:=comp_expr(true,[]);
               if n.nodetype=stringconstn then
                 handle_stringconstn
               else
@@ -1085,7 +1085,7 @@ implementation
             end;
           if (def=rec_tguid) and ((token=_CSTRING) or (token=_CCHAR)) then
             begin
-              n:=comp_expr(true,false);
+              n:=comp_expr(true,[]);
               inserttypeconv(n,cshortstringtype);
               if n.nodetype=stringconstn then
                 handle_stringconstn
@@ -1278,7 +1278,7 @@ implementation
           { only allow nil for implicit pointer object types }
           if is_implicit_pointer_object_type(def) then
             begin
-              n:=comp_expr(true,false);
+              n:=comp_expr(true,[]);
               if n.nodetype<>niln then
                 begin
                   Message(parser_e_type_const_not_possible);

+ 73 - 101
compiler/ptype.pas

@@ -40,9 +40,6 @@ interface
 
     procedure resolve_forward_types;
 
-    { reads a type identifier }
-    procedure id_type(var def : tdef;isforwarddef:boolean);
-
     { reads a string, file type or a type identifier }
     procedure single_type(var def:tdef;options:TSingleTypeOptions);
 
@@ -50,12 +47,12 @@ interface
     procedure read_named_type(var def:tdef;const name : TIDString;genericdef:tstoreddef;genericlist:TFPObjectList;parseprocvardir:boolean);
 
     { reads any type declaration }
-    procedure read_anon_type(var def : tdef;parseprocvardir:boolean);
+    procedure read_anon_type(var def:tdef;parseprocvardir:boolean);
 
     { generate persistent type information like VMT, RTTI and inittables }
     procedure write_persistent_type_info(st:tsymtable);
 
-    procedure generate_specialization(var tt:tdef;parse_class_parent:boolean);
+    procedure generate_specialization(var tt:tdef;typeparams:TFPObjectList;parse_class_parent:boolean);
 
 implementation
 
@@ -146,14 +143,13 @@ implementation
       end;
 
 
-    procedure generate_specialization(var tt:tdef;parse_class_parent:boolean);
+    procedure generate_specialization(var tt:tdef;typeparams:TFPObjectList;parse_class_parent:boolean);
       var
         st  : TSymtable;
         srsym : tsym;
         pt2 : tnode;
-        first,
         err : boolean;
-        i   : longint;
+        i,j : longint;
         sym : tsym;
         genericdef : tstoreddef;
         generictype : ttypesym;
@@ -192,25 +188,12 @@ implementation
             onlyparsepara:=true;
           end;
 
-        { Only parse the parameters for recovery or
-          for recording in genericbuf }
         if onlyparsepara then
-          begin
-            consume(_LSHARPBRACKET);
-            repeat
-              pt2:=factor(false,true);
-              pt2.free;
-            until not try_to_consume(_COMMA);
-            consume(_RSHARPBRACKET);
-            exit;
-          end;
+          exit;
 
-        if not try_to_consume(_LT) then
-          consume(_LSHARPBRACKET);
         { Parse generic parameters, for each undefineddef in the symtable of
           the genericdef we need to have a new def }
         err:=false;
-        first:=true;
         generictypelist:=TFPObjectList.create(false);
         case genericdef.typ of
           procdef:
@@ -230,16 +213,13 @@ implementation
         if not assigned(genericdef.typesym) then
           internalerror(200710173);
         specializename:=genericdef.typesym.realname;
+        j:=0;
         for i:=0 to st.SymList.Count-1 do
           begin
             sym:=tsym(st.SymList[i]);
             if (sp_generic_para in sym.symoptions) then
               begin
-                if not first then
-                  consume(_COMMA)
-                else
-                  first:=false;
-                pt2:=factor(false,true);
+                pt2:=tnode(typeparams[j]);
                 if pt2.nodetype=typen then
                   begin
                     if df_generic in pt2.resultdef.defoptions then
@@ -256,13 +236,10 @@ implementation
                     Message(type_e_type_id_expected);
                     err:=true;
                   end;
-                pt2.free;
+                inc(j);
               end;
           end;
         uspecializename:=upper(specializename);
-        { force correct error location if too much type parameters are passed }
-        if not (token in [_RSHARPBRACKET,_GT]) then
-          consume(_RSHARPBRACKET);
 
         { Special case if we are referencing the current defined object }
         if assigned(current_structdef) and
@@ -384,12 +361,9 @@ implementation
           end;
 
         generictypelist.free;
-        if not try_to_consume(_GT) then
-          consume(_RSHARPBRACKET);
       end;
 
-
-    procedure id_type(var def : tdef;isforwarddef:boolean);
+    procedure id_type(var def:tdef;options:TSingleTypeOptions;dospecialize:boolean;out typeparams:TFPObjectList);
     { reads a type definition }
     { to a appropriating tdef, s gets the name of   }
     { the type to allow name mangling          }
@@ -398,21 +372,43 @@ implementation
         pos : tfileposinfo;
         srsym : tsym;
         srsymtable : TSymtable;
-        s,sorg : TIDString;
+        s,sorg,generic_id_modifier : TIDString;
         t : ttoken;
         structdef : tabstractrecorddef;
       begin
          s:=pattern;
          sorg:=orgpattern;
+         consume(_ID);
          pos:=current_tokenpos;
+         { searching a generic ? }
+         if dospecialize or
+            ((m_delphi in current_settings.modeswitches) and
+             ([stoAllowSpecialization,stoAllowTypeDef]*options<>[]) and
+             (token in [_LSHARPBRACKET,_LT])
+            ) then
+           begin
+             typeparams:=TFPObjectList.Create(true);
+             if not try_to_consume(_LSHARPBRACKET) then
+               consume(_LT);
+             repeat
+               typeparams.add(factor(false,[eoTypeOnly]));
+             until not try_to_consume(_COMMA);
+             if not try_to_consume(_RSHARPBRACKET) then
+               consume(_GT);
+             generic_id_modifier:=generate_generic_id_modifier(typeparams.count);
+             { modify patterns }
+             s:=s+generic_id_modifier;
+             sorg:=sorg+generic_id_modifier;
+           end
+         else
+           typeparams:=nil;
          { use of current parsed object:
            classes, objects, records can be used also in themself }
          structdef:=current_structdef;
          while assigned(structdef) and (structdef.typ in [objectdef,recorddef]) do
            begin
-             if (structdef.objname^=pattern) then
+             if (structdef.objname^=s) then
                begin
-                 consume(_ID);
                  def:=structdef;
                  exit;
                end;
@@ -421,8 +417,9 @@ implementation
          { Use the special searchsym_type that search only types }
          searchsym_type(s,srsym,srsymtable);
          { handle unit specification like System.Writeln }
-         is_unit_specific:=try_consume_unitsym(srsym,srsymtable,t);
-         consume(t);
+         is_unit_specific:=try_consume_unitsym(srsym,srsymtable,t,false);
+         if is_unit_specific then
+           consume(t);
          { Types are first defined with an error def before assigning
            the real type so check if it's an errordef. if so then
            give an error. Only check for typesyms in the current symbol
@@ -436,7 +433,7 @@ implementation
             exit;
           end;
          { are we parsing a possible forward def ? }
-         if isforwarddef and
+         if (stoIsForwardDef in options) and
             not(is_unit_specific) then
            begin
              def:=tforwarddef.create(sorg,pos);
@@ -469,11 +466,12 @@ implementation
 
     procedure single_type(var def:tdef;options:TSingleTypeOptions);
        var
-         t2 : tdef;
-         dospecialize,
-         again : boolean;
+         t2: tdef;
+         dospecialize,again: boolean;
+         typeparams: TFPObjectList;
        begin
          dospecialize:=false;
+         typeparams:=nil;
          repeat
            again:=false;
              case token of
@@ -518,7 +516,7 @@ implementation
                      end
                    else
                      begin
-                       id_type(def,stoIsForwardDef in options);
+                       id_type(def,options,dospecialize,typeparams);
                        { handle types inside classes, e.g. TNode.TLongint }
                        while (token=_POINT) do
                          begin
@@ -531,7 +529,7 @@ implementation
                               begin
                                 symtablestack.push(tabstractrecorddef(def).symtable);
                                 consume(_POINT);
-                                id_type(t2,stoIsForwardDef in options);
+                                id_type(t2,options,dospecialize,typeparams);
                                 symtablestack.pop(tabstractrecorddef(def).symtable);
                                 def:=t2;
                               end
@@ -548,11 +546,8 @@ implementation
                  end;
             end;
         until not again;
-        if ([stoAllowSpecialization,stoAllowTypeDef] * options <> []) and
-           (m_delphi in current_settings.modeswitches) then
-          dospecialize:=token=_LSHARPBRACKET;
-        if dospecialize then
-          generate_specialization(def,stoParseClassParent in options)
+        if assigned(typeparams) then
+          generate_specialization(def,typeparams,stoParseClassParent in options)
         else
           begin
             if assigned(current_specializedef) and (def=current_specializedef.genericdef) then
@@ -574,6 +569,7 @@ implementation
                 def:=generrordef
               end
           end;
+        typeparams.free;
       end;
 
     procedure parse_record_members;
@@ -933,40 +929,24 @@ implementation
         defpos,storepos : tfileposinfo;
 
         procedure expr_type;
+        const
+          expr_options:array[boolean]of TExprOptions=([eoTypeOnly],[eoTypeOnly,eoSpecialize]);
         var
            pt1,pt2 : tnode;
            lv,hv   : TConstExprInt;
            old_block_type : tblock_type;
-           dospecialize : boolean;
-           structdef: tabstractrecorddef;
+           options: TExprOptions;
         begin
            old_block_type:=block_type;
-           dospecialize:=false;
-           { use of current parsed object:
-             classes, objects, records can be used also in themself }
-           if (token=_ID) then
-             begin
-               structdef:=current_structdef;
-               while assigned(structdef) and (structdef.typ in [objectdef,recorddef]) do
-                 begin
-                   if (structdef.objname^=pattern) then
-                     begin
-                       consume(_ID);
-                       def:=structdef;
-                       exit;
-                     end;
-                   structdef:=tabstractrecorddef(structdef.owner.defowner);
-                 end;
-             end;
            { Generate a specialization in FPC mode? }
-           dospecialize:=not(m_delphi in current_settings.modeswitches) and try_to_consume(_SPECIALIZE);
+           options:=expr_options[not(m_delphi in current_settings.modeswitches) and try_to_consume(_SPECIALIZE)];
            { we can't accept a equal in type }
-           pt1:=comp_expr(false,true);
-           if not dospecialize and
+           pt1:=comp_expr(false,options);
+           if not (eoSpecialize in options) and
               try_to_consume(_POINTPOINT) then
              begin
                { get high value of range }
-               pt2:=comp_expr(false,false);
+               pt2:=comp_expr(false,[]);
                { make both the same type or give an error. This is not
                  done when both are integer values, because typecasting
                  between -3200..3200 will result in a signed-unsigned
@@ -1015,32 +995,24 @@ implementation
                if (pt1.nodetype=typen) then
                  begin
                    def:=ttypenode(pt1).resultdef;
-                   { Delphi mode specialization? }
-                   if (m_delphi in current_settings.modeswitches) then
-                     dospecialize:=token=_LSHARPBRACKET;
-                   if dospecialize then
-                     generate_specialization(def,false)
-                   else
+                   if assigned(current_specializedef) and (def=current_specializedef.genericdef) then
                      begin
-                       if assigned(current_specializedef) and (def=current_specializedef.genericdef) then
-                         begin
-                           def:=current_specializedef
-                         end
-                       else if (def=current_genericdef) then
-                         begin
-                           def:=current_genericdef
-                         end
-                       else if (df_generic in def.defoptions) then
-                         begin
-                           Message(parser_e_no_generics_as_types);
-                           def:=generrordef;
-                         end
-                       else if is_objccategory(def) then
-                         begin
-                           Message(parser_e_no_category_as_types);
-                           def:=generrordef
-                         end
-                     end;
+                       def:=current_specializedef
+                     end
+                   else if (def=current_genericdef) then
+                     begin
+                       def:=current_genericdef
+                     end
+                   else if (df_generic in def.defoptions) then
+                     begin
+                       Message(parser_e_no_generics_as_types);
+                       def:=generrordef;
+                     end
+                   else if is_objccategory(def) then
+                     begin
+                       Message(parser_e_no_category_as_types);
+                       def:=generrordef
+                     end
                  end
                else
                  Message(sym_e_error_in_type_def);
@@ -1411,7 +1383,7 @@ implementation
                     begin
                        oldlocalswitches:=current_settings.localswitches;
                        include(current_settings.localswitches,cs_allow_enum_calc);
-                       p:=comp_expr(true,false);
+                       p:=comp_expr(true,[]);
                        current_settings.localswitches:=oldlocalswitches;
                        if (p.nodetype=ordconstn) then
                         begin
@@ -1616,7 +1588,7 @@ implementation
       end;
 
 
-    procedure read_anon_type(var def : tdef;parseprocvardir:boolean);
+    procedure read_anon_type(var def:tdef;parseprocvardir:boolean);
       begin
         read_named_type(def,'',nil,nil,parseprocvardir);
       end;

+ 57 - 0
compiler/scanner.pas

@@ -74,6 +74,22 @@ interface
          constructor Create(atoken: ttoken;asettings:tsettings;atokenbuf:tdynamicarray;anext:treplaystack);
        end;
 
+       tscannerstate = record
+         token: ttoken;
+         idtoken: ttoken;
+         settings: tsettings;
+         orgpattern: string;
+         pattern: string;
+         lasttokenpos: longint;
+         current_filepos: tfileposinfo;
+         current_tokenpos: tfileposinfo;
+         line_no: longint;
+         lastlinepos: longint;
+         bufstart: longint;
+         inputpos: longint;
+         c: char;
+       end;
+
        tcompile_time_predicate = function(var valuedescr: String) : Boolean;
 
        tspecialgenerictoken = (ST_LOADSETTINGS,ST_LINE,ST_COLUMN,ST_FILEINDEX);
@@ -181,6 +197,9 @@ interface
           function  readpreproc:ttoken;
           function  asmgetcharstart : char;
           function  asmgetchar:char;
+          { state save restore }
+          function savestate:tscannerstate;
+          procedure restorestate(state:tscannerstate);
        end;
 
 {$ifdef PREPROCWRITE}
@@ -4318,6 +4337,44 @@ exit_label:
          until false;
       end;
 
+    function tscannerfile.savestate:tscannerstate;
+      begin
+        result.settings:=current_settings;
+        result.token:=token;
+        result.idtoken:=idtoken;
+        result.pattern:=pattern;
+        result.orgpattern:=orgpattern;
+        result.lasttokenpos:=lasttokenpos;
+        result.current_filepos:=current_filepos;
+        result.current_tokenpos:=current_tokenpos;
+        result.line_no:=line_no;
+        result.lastlinepos:=lastlinepos;
+        result.bufstart:=inputfile.bufstart;
+        result.inputpos:=inputpointer-inputbuffer;
+        result.c:=c;
+      end;
+
+    procedure tscannerfile.restorestate(state:tscannerstate);
+      begin
+        current_settings:=state.settings;
+        token:=state.token;
+        idtoken:=state.idtoken;
+        pattern:=state.pattern;
+        orgpattern:=state.orgpattern;
+        lasttokenpos:=state.lasttokenpos;
+        current_filepos:=state.current_filepos;
+        current_tokenpos:=state.current_tokenpos;
+        line_no:=state.line_no;
+        lastlinepos:=state.lastlinepos;
+        c:=state.c;
+        if inputfile.bufstart<>state.bufstart then
+          begin
+            inputfile.seekbuf(state.bufstart);
+            inputfile.readbuf;
+            inputbuffer:=inputfile.buf;
+          end;
+        inputpointer:=inputbuffer+state.inputpos;
+      end;
 
 {*****************************************************************************
                                    Helpers

+ 11 - 1
compiler/symtable.pas

@@ -206,6 +206,7 @@ interface
 {*** Misc ***}
     function  FullTypeName(def,otherdef:tdef):string;
     function generate_nested_name(symtable:tsymtable;delimiter:string):string;
+    function generate_generic_id_modifier(const typeparamcount:integer):string;
     procedure incompatibletypes(def1,def2:tdef);
     procedure hidesym(sym:TSymEntry);
     procedure duplicatesym(var hashedid:THashedIDString;dupsym,origsym:TSymEntry);
@@ -1700,6 +1701,15 @@ implementation
           end;
       end;
 
+    function generate_generic_id_modifier(const typeparamcount:integer):string;
+      begin
+        SetLength(Result,typeparamcount+1);
+        if typeparamcount>1 then
+          FillChar(Result[2],typeparamcount-1,',');
+        Result[1]:='<';
+        Result[typeparamcount+1]:='>';
+      end;
+
     procedure incompatibletypes(def1,def2:tdef);
       begin
         { When there is an errordef there is already an error message show }
@@ -2003,7 +2013,7 @@ implementation
       end;
 
 
-    function searchsym_in_module(pm:pointer;const s : TIDString;out srsym:tsym;out srsymtable:TSymtable):boolean;
+    function searchsym_in_module(pm:pointer;const s:TIDString;out srsym:tsym;out srsymtable:TSymtable):boolean;
       var
         pmod : tmodule;
       begin

+ 121 - 121
rtl/objpas/fgl.pp

@@ -124,9 +124,9 @@ type
     function IndexOf(const Item: T): Integer;
     procedure Insert(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
     function Last: T; {$ifdef CLASSESINLINE} inline; {$endif}
-{$ifndef VER2_4}
-    procedure Assign(Source: TFPGList);
-{$endif VER2_4}
+{$ifndef OldSyntax}
+    procedure Assign(Source: specialize TFPGList<T>);
+{$endif OldSyntax}
     function Remove(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
     procedure Sort(Compare: TCompareFunc);
     property Items[Index: Integer]: T read Get write Put; default;
@@ -159,9 +159,9 @@ type
     function IndexOf(const Item: T): Integer;
     procedure Insert(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
     function Last: T; {$ifdef CLASSESINLINE} inline; {$endif}
-{$ifndef VER2_4}
-    procedure Assign(Source: TFPGObjectList);
-{$endif VER2_4}
+{$ifndef OldSyntax}
+    procedure Assign(Source: specialize TFPGObjectList<T>);
+{$endif OldSyntax}
     function Remove(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
     procedure Sort(Compare: TCompareFunc);
     property Items[Index: Integer]: T read Get write Put; default;
@@ -194,9 +194,9 @@ type
     function IndexOf(const Item: T): Integer;
     procedure Insert(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
     function Last: T; {$ifdef CLASSESINLINE} inline; {$endif}
-{$ifndef VER2_4}
-    procedure Assign(Source: TFPGInterfacedObjectList);
-{$endif VER2_4}
+{$ifndef OldSyntax}
+    procedure Assign(Source: specialize TFPGInterfacedObjectList<T>);
+{$endif OldSyntax}
     function Remove(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
     procedure Sort(Compare: TCompareFunc);
     property Items[Index: Integer]: T read Get write Put; default;
@@ -694,19 +694,19 @@ end;
 {*             TFPGListEnumerator                                           *}
 {****************************************************************************}
 
-function TFPGListEnumerator.GetCurrent: T;
+function TFPGListEnumerator{$ifndef OldSyntax}<T>{$endif}.GetCurrent: T;
 begin
   Result := T(FList.Items[FPosition]^);
 end;
 
-constructor TFPGListEnumerator.Create(AList: TFPSList);
+constructor TFPGListEnumerator{$ifndef OldSyntax}<T>{$endif}.Create(AList: TFPSList);
 begin
   inherited Create;
   FList := AList;
   FPosition := -1;
 end;
 
-function TFPGListEnumerator.MoveNext: Boolean;
+function TFPGListEnumerator{$ifndef OldSyntax}<T>{$endif}.MoveNext: Boolean;
 begin
   inc(FPosition);
   Result := FPosition < FList.Count;
@@ -716,47 +716,47 @@ end;
 {*                TFPGList                                                  *}
 {****************************************************************************}
 
-constructor TFPGList.Create;
+constructor TFPGList{$ifndef OldSyntax}<T>{$endif}.Create;
 begin
   inherited Create(sizeof(T));
 end;
 
-procedure TFPGList.CopyItem(Src, Dest: Pointer);
+procedure TFPGList{$ifndef OldSyntax}<T>{$endif}.CopyItem(Src, Dest: Pointer);
 begin
   T(Dest^) := T(Src^);
 end;
 
-procedure TFPGList.Deref(Item: Pointer);
+procedure TFPGList{$ifndef OldSyntax}<T>{$endif}.Deref(Item: Pointer);
 begin
   Finalize(T(Item^));
 end;
 
-function TFPGList.Get(Index: Integer): T;
+function TFPGList{$ifndef OldSyntax}<T>{$endif}.Get(Index: Integer): T;
 begin
   Result := T(inherited Get(Index)^);
 end;
 
-function TFPGList.GetList: PTypeList;
+function TFPGList{$ifndef OldSyntax}<T>{$endif}.GetList: PTypeList;
 begin
   Result := PTypeList(FList);
 end;
 
-function TFPGList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
+function TFPGList{$ifndef OldSyntax}<T>{$endif}.ItemPtrCompare(Item1, Item2: Pointer): Integer;
 begin
   Result := FOnCompare(T(Item1^), T(Item2^));
 end;
 
-procedure TFPGList.Put(Index: Integer; const Item: T);
+procedure TFPGList{$ifndef OldSyntax}<T>{$endif}.Put(Index: Integer; const Item: T);
 begin
   inherited Put(Index, @Item);
 end;
 
-function TFPGList.Add(const Item: T): Integer;
+function TFPGList{$ifndef OldSyntax}<T>{$endif}.Add(const Item: T): Integer;
 begin
   Result := inherited Add(@Item);
 end;
 
-function TFPGList.Extract(const Item: T): T;
+function TFPGList{$ifndef OldSyntax}<T>{$endif}.Extract(const Item: T): T;
 var
   ResPtr: Pointer;
 begin
@@ -767,17 +767,17 @@ begin
     FillByte(Result, sizeof(T), 0);
 end;
 
-function TFPGList.First: T;
+function TFPGList{$ifndef OldSyntax}<T>{$endif}.First: T;
 begin
   Result := T(inherited First^);
 end;
 
-function TFPGList.GetEnumerator: TFPGListEnumeratorSpec;
+function TFPGList{$ifndef OldSyntax}<T>{$endif}.GetEnumerator: TFPGListEnumeratorSpec;
 begin
   Result := TFPGListEnumeratorSpec.Create(Self);
 end;
 
-function TFPGList.IndexOf(const Item: T): Integer;
+function TFPGList{$ifndef OldSyntax}<T>{$endif}.IndexOf(const Item: T): Integer;
 begin
   Result := 0;
   {$info TODO: fix inlining to work! InternalItems[Result]^}
@@ -787,18 +787,18 @@ begin
     Result := -1;
 end;
 
-procedure TFPGList.Insert(Index: Integer; const Item: T);
+procedure TFPGList{$ifndef OldSyntax}<T>{$endif}.Insert(Index: Integer; const Item: T);
 begin
   T(inherited Insert(Index)^) := Item;
 end;
 
-function TFPGList.Last: T;
+function TFPGList{$ifndef OldSyntax}<T>{$endif}.Last: T;
 begin
   Result := T(inherited Last^);
 end;
 
-{$ifndef VER2_4}
-procedure TFPGList.Assign(Source: TFPGList);
+{$ifndef OldSyntax}
+procedure TFPGList<T>.Assign(Source: specialize TFPGList<T>);
 var
   i: Integer;
 begin
@@ -806,16 +806,16 @@ begin
   for I := 0 to Source.Count - 1 do
     Add(Source[i]);
 end;
-{$endif VER2_4}
+{$endif OldSyntax}
 
-function TFPGList.Remove(const Item: T): Integer;
+function TFPGList{$ifndef OldSyntax}<T>{$endif}.Remove(const Item: T): Integer;
 begin
   Result := IndexOf(Item);
   if Result >= 0 then
     Delete(Result);
 end;
 
-procedure TFPGList.Sort(Compare: TCompareFunc);
+procedure TFPGList{$ifndef OldSyntax}<T>{$endif}.Sort(Compare: TCompareFunc);
 begin
   FOnCompare := Compare;
   inherited Sort(@ItemPtrCompare);
@@ -826,49 +826,49 @@ end;
 {*                TFPGObjectList                                            *}
 {****************************************************************************}
 
-constructor TFPGObjectList.Create(FreeObjects: Boolean);
+constructor TFPGObjectList{$ifndef OldSyntax}<T>{$endif}.Create(FreeObjects: Boolean);
 begin
   inherited Create;
   FFreeObjects := FreeObjects;
 end;
 
-procedure TFPGObjectList.CopyItem(Src, Dest: Pointer);
+procedure TFPGObjectList{$ifndef OldSyntax}<T>{$endif}.CopyItem(Src, Dest: Pointer);
 begin
   T(Dest^) := T(Src^);
 end;
 
-procedure TFPGObjectList.Deref(Item: Pointer);
+procedure TFPGObjectList{$ifndef OldSyntax}<T>{$endif}.Deref(Item: Pointer);
 begin
   if FFreeObjects then
     T(Item^).Free;
 end;
 
-function TFPGObjectList.Get(Index: Integer): T;
+function TFPGObjectList{$ifndef OldSyntax}<T>{$endif}.Get(Index: Integer): T;
 begin
   Result := T(inherited Get(Index)^);
 end;
 
-function TFPGObjectList.GetList: PTypeList;
+function TFPGObjectList{$ifndef OldSyntax}<T>{$endif}.GetList: PTypeList;
 begin
   Result := PTypeList(FList);
 end;
 
-function TFPGObjectList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
+function TFPGObjectList{$ifndef OldSyntax}<T>{$endif}.ItemPtrCompare(Item1, Item2: Pointer): Integer;
 begin
   Result := FOnCompare(T(Item1^), T(Item2^));
 end;
 
-procedure TFPGObjectList.Put(Index: Integer; const Item: T);
+procedure TFPGObjectList{$ifndef OldSyntax}<T>{$endif}.Put(Index: Integer; const Item: T);
 begin
   inherited Put(Index, @Item);
 end;
 
-function TFPGObjectList.Add(const Item: T): Integer;
+function TFPGObjectList{$ifndef OldSyntax}<T>{$endif}.Add(const Item: T): Integer;
 begin
   Result := inherited Add(@Item);
 end;
 
-function TFPGObjectList.Extract(const Item: T): T;
+function TFPGObjectList{$ifndef OldSyntax}<T>{$endif}.Extract(const Item: T): T;
 var
   ResPtr: Pointer;
 begin
@@ -879,17 +879,17 @@ begin
     FillByte(Result, sizeof(T), 0);
 end;
 
-function TFPGObjectList.First: T;
+function TFPGObjectList{$ifndef OldSyntax}<T>{$endif}.First: T;
 begin
   Result := T(inherited First^);
 end;
 
-function TFPGObjectList.GetEnumerator: TFPGListEnumeratorSpec;
+function TFPGObjectList{$ifndef OldSyntax}<T>{$endif}.GetEnumerator: TFPGListEnumeratorSpec;
 begin
   Result := TFPGListEnumeratorSpec.Create(Self);
 end;
 
-function TFPGObjectList.IndexOf(const Item: T): Integer;
+function TFPGObjectList{$ifndef OldSyntax}<T>{$endif}.IndexOf(const Item: T): Integer;
 begin
   Result := 0;
   {$info TODO: fix inlining to work! InternalItems[Result]^}
@@ -899,18 +899,18 @@ begin
     Result := -1;
 end;
 
-procedure TFPGObjectList.Insert(Index: Integer; const Item: T);
+procedure TFPGObjectList{$ifndef OldSyntax}<T>{$endif}.Insert(Index: Integer; const Item: T);
 begin
   T(inherited Insert(Index)^) := Item;
 end;
 
-function TFPGObjectList.Last: T;
+function TFPGObjectList{$ifndef OldSyntax}<T>{$endif}.Last: T;
 begin
   Result := T(inherited Last^);
 end;
 
-{$ifndef VER2_4}
-procedure TFPGObjectList.Assign(Source: TFPGObjectList);
+{$ifndef OldSyntax}
+procedure TFPGObjectList<T>.Assign(Source: specialize TFPGObjectList<T>);
 var
   i: Integer;
 begin
@@ -918,16 +918,16 @@ begin
   for I := 0 to Source.Count - 1 do
     Add(Source[i]);
 end;
-{$endif VER2_4}
+{$endif OldSyntax}
 
-function TFPGObjectList.Remove(const Item: T): Integer;
+function TFPGObjectList{$ifndef OldSyntax}<T>{$endif}.Remove(const Item: T): Integer;
 begin
   Result := IndexOf(Item);
   if Result >= 0 then
     Delete(Result);
 end;
 
-procedure TFPGObjectList.Sort(Compare: TCompareFunc);
+procedure TFPGObjectList{$ifndef OldSyntax}<T>{$endif}.Sort(Compare: TCompareFunc);
 begin
   FOnCompare := Compare;
   inherited Sort(@ItemPtrCompare);
@@ -938,12 +938,12 @@ end;
 {*                TFPGInterfacedObjectList                                  *}
 {****************************************************************************}
 
-constructor TFPGInterfacedObjectList.Create;
+constructor TFPGInterfacedObjectList{$ifndef OldSyntax}<T>{$endif}.Create;
 begin
   inherited Create;
 end;
 
-procedure TFPGInterfacedObjectList.CopyItem(Src, Dest: Pointer);
+procedure TFPGInterfacedObjectList{$ifndef OldSyntax}<T>{$endif}.CopyItem(Src, Dest: Pointer);
 begin
   if Assigned(Pointer(Dest^)) then
     T(Dest^)._Release;
@@ -952,38 +952,38 @@ begin
     T(Dest^)._AddRef;
 end;
 
-procedure TFPGInterfacedObjectList.Deref(Item: Pointer);
+procedure TFPGInterfacedObjectList{$ifndef OldSyntax}<T>{$endif}.Deref(Item: Pointer);
 begin
   if Assigned(Pointer(Item^)) then
     T(Item^)._Release;
 end;
 
-function TFPGInterfacedObjectList.Get(Index: Integer): T;
+function TFPGInterfacedObjectList{$ifndef OldSyntax}<T>{$endif}.Get(Index: Integer): T;
 begin
   Result := T(inherited Get(Index)^);
 end;
 
-function TFPGInterfacedObjectList.GetList: PTypeList;
+function TFPGInterfacedObjectList{$ifndef OldSyntax}<T>{$endif}.GetList: PTypeList;
 begin
   Result := PTypeList(FList);
 end;
 
-function TFPGInterfacedObjectList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
+function TFPGInterfacedObjectList{$ifndef OldSyntax}<T>{$endif}.ItemPtrCompare(Item1, Item2: Pointer): Integer;
 begin
   Result := FOnCompare(T(Item1^), T(Item2^));
 end;
 
-procedure TFPGInterfacedObjectList.Put(Index: Integer; const Item: T);
+procedure TFPGInterfacedObjectList{$ifndef OldSyntax}<T>{$endif}.Put(Index: Integer; const Item: T);
 begin
   inherited Put(Index, @Item);
 end;
 
-function TFPGInterfacedObjectList.Add(const Item: T): Integer;
+function TFPGInterfacedObjectList{$ifndef OldSyntax}<T>{$endif}.Add(const Item: T): Integer;
 begin
   Result := inherited Add(@Item);
 end;
 
-function TFPGInterfacedObjectList.Extract(const Item: T): T;
+function TFPGInterfacedObjectList{$ifndef OldSyntax}<T>{$endif}.Extract(const Item: T): T;
 var
   ResPtr: Pointer;
 begin
@@ -994,17 +994,17 @@ begin
     FillByte(Result, sizeof(T), 0);
 end;
 
-function TFPGInterfacedObjectList.First: T;
+function TFPGInterfacedObjectList{$ifndef OldSyntax}<T>{$endif}.First: T;
 begin
   Result := T(inherited First^);
 end;
 
-function TFPGInterfacedObjectList.GetEnumerator: TFPGListEnumeratorSpec;
+function TFPGInterfacedObjectList{$ifndef OldSyntax}<T>{$endif}.GetEnumerator: TFPGListEnumeratorSpec;
 begin
   Result := TFPGListEnumeratorSpec.Create(Self);
 end;
 
-function TFPGInterfacedObjectList.IndexOf(const Item: T): Integer;
+function TFPGInterfacedObjectList{$ifndef OldSyntax}<T>{$endif}.IndexOf(const Item: T): Integer;
 begin
   Result := 0;
   {$info TODO: fix inlining to work! InternalItems[Result]^}
@@ -1014,18 +1014,18 @@ begin
     Result := -1;
 end;
 
-procedure TFPGInterfacedObjectList.Insert(Index: Integer; const Item: T);
+procedure TFPGInterfacedObjectList{$ifndef OldSyntax}<T>{$endif}.Insert(Index: Integer; const Item: T);
 begin
   T(inherited Insert(Index)^) := Item;
 end;
 
-function TFPGInterfacedObjectList.Last: T;
+function TFPGInterfacedObjectList{$ifndef OldSyntax}<T>{$endif}.Last: T;
 begin
   Result := T(inherited Last^);
 end;
 
-{$ifndef VER2_4}
-procedure TFPGInterfacedObjectList.Assign(Source: TFPGInterfacedObjectList);
+{$ifndef OldSyntax}
+procedure TFPGInterfacedObjectList<T>.Assign(Source: specialize TFPGInterfacedObjectList<T>);
 var
   i: Integer;
 begin
@@ -1033,16 +1033,16 @@ begin
   for I := 0 to Source.Count - 1 do
     Add(Source[i]);
 end;
-{$endif VER2_4}
+{$endif OldSyntax}
 
-function TFPGInterfacedObjectList.Remove(const Item: T): Integer;
+function TFPGInterfacedObjectList{$ifndef OldSyntax}<T>{$endif}.Remove(const Item: T): Integer;
 begin
   Result := IndexOf(Item);
   if Result >= 0 then
     Delete(Result);
 end;
 
-procedure TFPGInterfacedObjectList.Sort(Compare: TCompareFunc);
+procedure TFPGInterfacedObjectList{$ifndef OldSyntax}<T>{$endif}.Sort(Compare: TCompareFunc);
 begin
   FOnCompare := Compare;
   inherited Sort(@ItemPtrCompare);
@@ -1283,49 +1283,49 @@ end;
                              TFPGMap
  ****************************************************************************}
 
-constructor TFPGMap.Create;
+constructor TFPGMap{$ifndef OldSyntax}<TKey, TData>{$endif}.Create;
 begin
   inherited Create(SizeOf(TKey), SizeOf(TData));
 end;
 
-procedure TFPGMap.CopyItem(Src, Dest: Pointer);
+procedure TFPGMap{$ifndef OldSyntax}<TKey, TData>{$endif}.CopyItem(Src, Dest: Pointer);
 begin
   CopyKey(Src, Dest);
   CopyData(PByte(Src)+KeySize, PByte(Dest)+KeySize);
 end;
 
-procedure TFPGMap.CopyKey(Src, Dest: Pointer);
+procedure TFPGMap{$ifndef OldSyntax}<TKey, TData>{$endif}.CopyKey(Src, Dest: Pointer);
 begin
   TKey(Dest^) := TKey(Src^);
 end;
 
-procedure TFPGMap.CopyData(Src, Dest: Pointer);
+procedure TFPGMap{$ifndef OldSyntax}<TKey, TData>{$endif}.CopyData(Src, Dest: Pointer);
 begin
   TData(Dest^) := TData(Src^);
 end;
 
-procedure TFPGMap.Deref(Item: Pointer);
+procedure TFPGMap{$ifndef OldSyntax}<TKey, TData>{$endif}.Deref(Item: Pointer);
 begin
   Finalize(TKey(Item^));
   Finalize(TData(Pointer(PByte(Item)+KeySize)^));
 end;
 
-function TFPGMap.GetKey(Index: Integer): TKey;
+function TFPGMap{$ifndef OldSyntax}<TKey, TData>{$endif}.GetKey(Index: Integer): TKey;
 begin
   Result := TKey(inherited GetKey(Index)^);
 end;
 
-function TFPGMap.GetData(Index: Integer): TData;
+function TFPGMap{$ifndef OldSyntax}<TKey, TData>{$endif}.GetData(Index: Integer): TData;
 begin
   Result := TData(inherited GetData(Index)^);
 end;
 
-function TFPGMap.GetKeyData(const AKey: TKey): TData;
+function TFPGMap{$ifndef OldSyntax}<TKey, TData>{$endif}.GetKeyData(const AKey: TKey): TData;
 begin
   Result := TData(inherited GetKeyData(@AKey)^);
 end;
 
-function TFPGMap.KeyCompare(Key1, Key2: Pointer): Integer;
+function TFPGMap{$ifndef OldSyntax}<TKey, TData>{$endif}.KeyCompare(Key1, Key2: Pointer): Integer;
 begin
   if PKey(Key1)^ < PKey(Key2)^ then
     Result := -1
@@ -1335,7 +1335,7 @@ begin
     Result := 0;
 end;
 
-{function TFPGMap.DataCompare(Data1, Data2: Pointer): Integer;
+{function TFPGMap<TKey, TData>.DataCompare(Data1, Data2: Pointer): Integer;
 begin
   if PData(Data1)^ < PData(Data2)^ then
     Result := -1
@@ -1345,17 +1345,17 @@ begin
     Result := 0;
 end;}
 
-function TFPGMap.KeyCustomCompare(Key1, Key2: Pointer): Integer;
+function TFPGMap{$ifndef OldSyntax}<TKey, TData>{$endif}.KeyCustomCompare(Key1, Key2: Pointer): Integer;
 begin
   Result := FOnKeyCompare(TKey(Key1^), TKey(Key2^));
 end;
 
-function TFPGMap.DataCustomCompare(Data1, Data2: Pointer): Integer;
+function TFPGMap{$ifndef OldSyntax}<TKey, TData>{$endif}.DataCustomCompare(Data1, Data2: Pointer): Integer;
 begin
   Result := FOnDataCompare(TData(Data1^), TData(Data2^));
 end;
 
-procedure TFPGMap.SetOnKeyCompare(NewCompare: TKeyCompareFunc);
+procedure TFPGMap{$ifndef OldSyntax}<TKey, TData>{$endif}.SetOnKeyCompare(NewCompare: TKeyCompareFunc);
 begin
   FOnKeyCompare := NewCompare;
   if NewCompare <> nil then
@@ -1364,7 +1364,7 @@ begin
     OnKeyPtrCompare := @KeyCompare;
 end;
 
-procedure TFPGMap.SetOnDataCompare(NewCompare: TDataCompareFunc);
+procedure TFPGMap{$ifndef OldSyntax}<TKey, TData>{$endif}.SetOnDataCompare(NewCompare: TDataCompareFunc);
 begin
   FOnDataCompare := NewCompare;
   if NewCompare <> nil then
@@ -1373,64 +1373,64 @@ begin
     OnDataPtrCompare := nil;
 end;
 
-procedure TFPGMap.InitOnPtrCompare;
+procedure TFPGMap{$ifndef OldSyntax}<TKey, TData>{$endif}.InitOnPtrCompare;
 begin
   SetOnKeyCompare(nil);
   SetOnDataCompare(nil);
 end;
 
-procedure TFPGMap.PutKey(Index: Integer; const NewKey: TKey);
+procedure TFPGMap{$ifndef OldSyntax}<TKey, TData>{$endif}.PutKey(Index: Integer; const NewKey: TKey);
 begin
   inherited PutKey(Index, @NewKey);
 end;
 
-procedure TFPGMap.PutData(Index: Integer; const NewData: TData);
+procedure TFPGMap{$ifndef OldSyntax}<TKey, TData>{$endif}.PutData(Index: Integer; const NewData: TData);
 begin
   inherited PutData(Index, @NewData);
 end;
 
-procedure TFPGMap.PutKeyData(const AKey: TKey; const NewData: TData);
+procedure TFPGMap{$ifndef OldSyntax}<TKey, TData>{$endif}.PutKeyData(const AKey: TKey; const NewData: TData);
 begin
   inherited PutKeyData(@AKey, @NewData);
 end;
 
-function TFPGMap.Add(const AKey: TKey): Integer;
+function TFPGMap{$ifndef OldSyntax}<TKey, TData>{$endif}.Add(const AKey: TKey): Integer;
 begin
   Result := inherited Add(@AKey);
 end;
 
-function TFPGMap.Add(const AKey: TKey; const AData: TData): Integer;
+function TFPGMap{$ifndef OldSyntax}<TKey, TData>{$endif}.Add(const AKey: TKey; const AData: TData): Integer;
 begin
   Result := inherited Add(@AKey, @AData);
 end;
 
-function TFPGMap.Find(const AKey: TKey; out Index: Integer): Boolean;
+function TFPGMap{$ifndef OldSyntax}<TKey, TData>{$endif}.Find(const AKey: TKey; out Index: Integer): Boolean;
 begin
   Result := inherited Find(@AKey, Index);
 end;
 
-function TFPGMap.IndexOf(const AKey: TKey): Integer;
+function TFPGMap{$ifndef OldSyntax}<TKey, TData>{$endif}.IndexOf(const AKey: TKey): Integer;
 begin
   Result := inherited IndexOf(@AKey);
 end;
 
-function TFPGMap.IndexOfData(const AData: TData): Integer;
+function TFPGMap{$ifndef OldSyntax}<TKey, TData>{$endif}.IndexOfData(const AData: TData): Integer;
 begin
   { TODO: loop ? }
   Result := inherited IndexOfData(@AData);
 end;
 
-procedure TFPGMap.InsertKey(Index: Integer; const AKey: TKey);
+procedure TFPGMap{$ifndef OldSyntax}<TKey, TData>{$endif}.InsertKey(Index: Integer; const AKey: TKey);
 begin
   inherited InsertKey(Index, @AKey);
 end;
 
-procedure TFPGMap.InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
+procedure TFPGMap{$ifndef OldSyntax}<TKey, TData>{$endif}.InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
 begin
   inherited InsertKeyData(Index, @AKey, @AData);
 end;
 
-function TFPGMap.Remove(const AKey: TKey): Integer;
+function TFPGMap{$ifndef OldSyntax}<TKey, TData>{$endif}.Remove(const AKey: TKey): Integer;
 begin
   Result := inherited Remove(@AKey);
 end;
@@ -1439,23 +1439,23 @@ end;
                              TFPGMapInterfacedObjectData
  ****************************************************************************}
 
-constructor TFPGMapInterfacedObjectData.Create;
+constructor TFPGMapInterfacedObjectData{$ifndef OldSyntax}<TKey, TData>{$endif}.Create;
 begin
   inherited Create(SizeOf(TKey), SizeOf(TData));
 end;
 
-procedure TFPGMapInterfacedObjectData.CopyItem(Src, Dest: Pointer);
+procedure TFPGMapInterfacedObjectData{$ifndef OldSyntax}<TKey, TData>{$endif}.CopyItem(Src, Dest: Pointer);
 begin
   CopyKey(Src, Dest);
   CopyData(PByte(Src)+KeySize, PByte(Dest)+KeySize);
 end;
 
-procedure TFPGMapInterfacedObjectData.CopyKey(Src, Dest: Pointer);
+procedure TFPGMapInterfacedObjectData{$ifndef OldSyntax}<TKey, TData>{$endif}.CopyKey(Src, Dest: Pointer);
 begin
   TKey(Dest^) := TKey(Src^);
 end;
 
-procedure TFPGMapInterfacedObjectData.CopyData(Src, Dest: Pointer);
+procedure TFPGMapInterfacedObjectData{$ifndef OldSyntax}<TKey, TData>{$endif}.CopyData(Src, Dest: Pointer);
 begin
   if Assigned(Pointer(Dest^)) then
     TData(Dest^)._Release;
@@ -1464,29 +1464,29 @@ begin
     TData(Dest^)._AddRef;
 end;
 
-procedure TFPGMapInterfacedObjectData.Deref(Item: Pointer);
+procedure TFPGMapInterfacedObjectData{$ifndef OldSyntax}<TKey, TData>{$endif}.Deref(Item: Pointer);
 begin
   Finalize(TKey(Item^));
   if Assigned(PPointer(PByte(Item)+KeySize)^) then
     TData(Pointer(PByte(Item)+KeySize)^)._Release;
 end;
 
-function TFPGMapInterfacedObjectData.GetKey(Index: Integer): TKey;
+function TFPGMapInterfacedObjectData{$ifndef OldSyntax}<TKey, TData>{$endif}.GetKey(Index: Integer): TKey;
 begin
   Result := TKey(inherited GetKey(Index)^);
 end;
 
-function TFPGMapInterfacedObjectData.GetData(Index: Integer): TData;
+function TFPGMapInterfacedObjectData{$ifndef OldSyntax}<TKey, TData>{$endif}.GetData(Index: Integer): TData;
 begin
   Result := TData(inherited GetData(Index)^);
 end;
 
-function TFPGMapInterfacedObjectData.GetKeyData(const AKey: TKey): TData;
+function TFPGMapInterfacedObjectData{$ifndef OldSyntax}<TKey, TData>{$endif}.GetKeyData(const AKey: TKey): TData;
 begin
   Result := TData(inherited GetKeyData(@AKey)^);
 end;
 
-function TFPGMapInterfacedObjectData.KeyCompare(Key1, Key2: Pointer): Integer;
+function TFPGMapInterfacedObjectData{$ifndef OldSyntax}<TKey, TData>{$endif}.KeyCompare(Key1, Key2: Pointer): Integer;
 begin
   if PKey(Key1)^ < PKey(Key2)^ then
     Result := -1
@@ -1496,7 +1496,7 @@ begin
     Result := 0;
 end;
 
-{function TFPGMapInterfacedObjectData.DataCompare(Data1, Data2: Pointer): Integer;
+{function TFPGMapInterfacedObjectData<TKey, TData>.DataCompare(Data1, Data2: Pointer): Integer;
 begin
   if PData(Data1)^ < PData(Data2)^ then
     Result := -1
@@ -1506,17 +1506,17 @@ begin
     Result := 0;
 end;}
 
-function TFPGMapInterfacedObjectData.KeyCustomCompare(Key1, Key2: Pointer): Integer;
+function TFPGMapInterfacedObjectData{$ifndef OldSyntax}<TKey, TData>{$endif}.KeyCustomCompare(Key1, Key2: Pointer): Integer;
 begin
   Result := FOnKeyCompare(TKey(Key1^), TKey(Key2^));
 end;
 
-function TFPGMapInterfacedObjectData.DataCustomCompare(Data1, Data2: Pointer): Integer;
+function TFPGMapInterfacedObjectData{$ifndef OldSyntax}<TKey, TData>{$endif}.DataCustomCompare(Data1, Data2: Pointer): Integer;
 begin
   Result := FOnDataCompare(TData(Data1^), TData(Data2^));
 end;
 
-procedure TFPGMapInterfacedObjectData.SetOnKeyCompare(NewCompare: TKeyCompareFunc);
+procedure TFPGMapInterfacedObjectData{$ifndef OldSyntax}<TKey, TData>{$endif}.SetOnKeyCompare(NewCompare: TKeyCompareFunc);
 begin
   FOnKeyCompare := NewCompare;
   if NewCompare <> nil then
@@ -1525,7 +1525,7 @@ begin
     OnKeyPtrCompare := @KeyCompare;
 end;
 
-procedure TFPGMapInterfacedObjectData.SetOnDataCompare(NewCompare: TDataCompareFunc);
+procedure TFPGMapInterfacedObjectData{$ifndef OldSyntax}<TKey, TData>{$endif}.SetOnDataCompare(NewCompare: TDataCompareFunc);
 begin
   FOnDataCompare := NewCompare;
   if NewCompare <> nil then
@@ -1534,64 +1534,64 @@ begin
     OnDataPtrCompare := nil;
 end;
 
-procedure TFPGMapInterfacedObjectData.InitOnPtrCompare;
+procedure TFPGMapInterfacedObjectData{$ifndef OldSyntax}<TKey, TData>{$endif}.InitOnPtrCompare;
 begin
   SetOnKeyCompare(nil);
   SetOnDataCompare(nil);
 end;
 
-procedure TFPGMapInterfacedObjectData.PutKey(Index: Integer; const NewKey: TKey);
+procedure TFPGMapInterfacedObjectData{$ifndef OldSyntax}<TKey, TData>{$endif}.PutKey(Index: Integer; const NewKey: TKey);
 begin
   inherited PutKey(Index, @NewKey);
 end;
 
-procedure TFPGMapInterfacedObjectData.PutData(Index: Integer; const NewData: TData);
+procedure TFPGMapInterfacedObjectData{$ifndef OldSyntax}<TKey, TData>{$endif}.PutData(Index: Integer; const NewData: TData);
 begin
   inherited PutData(Index, @NewData);
 end;
 
-procedure TFPGMapInterfacedObjectData.PutKeyData(const AKey: TKey; const NewData: TData);
+procedure TFPGMapInterfacedObjectData{$ifndef OldSyntax}<TKey, TData>{$endif}.PutKeyData(const AKey: TKey; const NewData: TData);
 begin
   inherited PutKeyData(@AKey, @NewData);
 end;
 
-function TFPGMapInterfacedObjectData.Add(const AKey: TKey): Integer;
+function TFPGMapInterfacedObjectData{$ifndef OldSyntax}<TKey, TData>{$endif}.Add(const AKey: TKey): Integer;
 begin
   Result := inherited Add(@AKey);
 end;
 
-function TFPGMapInterfacedObjectData.Add(const AKey: TKey; const AData: TData): Integer;
+function TFPGMapInterfacedObjectData{$ifndef OldSyntax}<TKey, TData>{$endif}.Add(const AKey: TKey; const AData: TData): Integer;
 begin
   Result := inherited Add(@AKey, @AData);
 end;
 
-function TFPGMapInterfacedObjectData.Find(const AKey: TKey; out Index: Integer): Boolean;
+function TFPGMapInterfacedObjectData{$ifndef OldSyntax}<TKey, TData>{$endif}.Find(const AKey: TKey; out Index: Integer): Boolean;
 begin
   Result := inherited Find(@AKey, Index);
 end;
 
-function TFPGMapInterfacedObjectData.IndexOf(const AKey: TKey): Integer;
+function TFPGMapInterfacedObjectData{$ifndef OldSyntax}<TKey, TData>{$endif}.IndexOf(const AKey: TKey): Integer;
 begin
   Result := inherited IndexOf(@AKey);
 end;
 
-function TFPGMapInterfacedObjectData.IndexOfData(const AData: TData): Integer;
+function TFPGMapInterfacedObjectData{$ifndef OldSyntax}<TKey, TData>{$endif}.IndexOfData(const AData: TData): Integer;
 begin
   { TODO: loop ? }
   Result := inherited IndexOfData(@AData);
 end;
 
-procedure TFPGMapInterfacedObjectData.InsertKey(Index: Integer; const AKey: TKey);
+procedure TFPGMapInterfacedObjectData{$ifndef OldSyntax}<TKey, TData>{$endif}.InsertKey(Index: Integer; const AKey: TKey);
 begin
   inherited InsertKey(Index, @AKey);
 end;
 
-procedure TFPGMapInterfacedObjectData.InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
+procedure TFPGMapInterfacedObjectData{$ifndef OldSyntax}<TKey, TData>{$endif}.InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
 begin
   inherited InsertKeyData(Index, @AKey, @AData);
 end;
 
-function TFPGMapInterfacedObjectData.Remove(const AKey: TKey): Integer;
+function TFPGMapInterfacedObjectData{$ifndef OldSyntax}<TKey, TData>{$endif}.Remove(const AKey: TKey): Integer;
 begin
   Result := inherited Remove(@AKey);
 end;

+ 4 - 4
tests/tbs/ub0569.pp

@@ -14,26 +14,26 @@ unit ub0569;
 
   implementation
 
-    function TGen.getstring : string;
+    function TGen<T>.getstring : string;
       begin
         result:='Free Pascal';
       end;
 
 
-    function TGen.getwidestring : widestring;
+    function TGen<T>.getwidestring : widestring;
       begin
         { force widestring }
         result:='Free Pascal'#1234;
       end;
 
 
-    function TGen.getint : int64;
+    function TGen<T>.getint : int64;
       begin
         result:=1234123412341234;
       end;
 
 
-    function TGen.getreal : real;
+    function TGen<T>.getreal : real;
       begin
         result:=333.0;
       end;

+ 1 - 1
tests/test/tgeneric1.pp

@@ -6,7 +6,7 @@ type
      procedure Add(item: _T);
    end;
 
-procedure TList.Add(item: _T);
+procedure TList<_T>.Add(item: _T);
 begin
   data:=item;
 end;

+ 2 - 2
tests/test/tgeneric11.pp

@@ -9,12 +9,12 @@ type
      procedure Assign(Source: specialize TList<_T>);
    end;
 
-procedure TList.Add(item: _T);
+procedure TList<_T>.Add(item: _T);
 begin
   data:=item;
 end;
 
-procedure TList.Assign(Source: specialize TList<_T>);
+procedure TList<_T>.Assign(Source: specialize TList<_T>);
 begin
   data:=Source.data;
 end;

+ 2 - 2
tests/test/tgeneric12.pp

@@ -19,12 +19,12 @@ begin
   halt(1);
 end;
 
-procedure TList.Add(item: _T);
+procedure TList<_T>.Add(item: _T);
 begin
   data:=item;
 end;
 
-procedure TList.Test;
+procedure TList<_T>.Test;
 begin
   if data <> 10 then
     halt(1);

+ 2 - 2
tests/test/tgeneric15.pp

@@ -47,12 +47,12 @@ end;
 
 { TStack }
 
-procedure TStack.Clear;
+procedure TStack<T>.Clear;
 begin
   Writeln('old clear');
 end;
 
-destructor TStack.Destroy;
+destructor TStack<T>.Destroy;
 begin
   Writeln('old destroy');
   Clear;

+ 3 - 3
tests/test/tgeneric16.pp

@@ -36,7 +36,7 @@ var
 
 { TAdvStack }
 
-procedure TAdvStack.Clear;
+procedure TAdvStack<T>.Clear;
 begin
   Writeln('new clear');
   Idx:=Idx or 1;
@@ -52,12 +52,12 @@ end;
 
 { TStack }
 
-procedure TStack.Clear;
+procedure TStack<T>.Clear;
 begin
   Writeln('old clear');
 end;
 
-destructor TStack.Destroy;
+destructor TStack<T>.Destroy;
 begin
   Writeln('old destroy');
   Clear;

+ 3 - 3
tests/test/tgeneric17.pp

@@ -3,11 +3,11 @@
 type
   generic TGListItem<T> = class(TObject)
   public
-    FNext: TGListItem;
-    procedure Assign(Source: TGListItem);
+    FNext: specialize TGListItem<T>;
+    procedure Assign(Source: specialize TGListItem<T>);
   end;
 
-procedure TGListItem.Assign(Source: TGListItem);
+procedure TGListItem<T>.Assign(Source: specialize TGListItem<T>);
 begin
   FNext := Source;
 end;

+ 1 - 1
tests/test/tgeneric19.pp

@@ -6,7 +6,7 @@ type
 
   tc1 = specialize tc<string>;
 
-procedure tc.p(data : T);
+procedure tc<T>.p(data : T);
   begin
     readln(data);
     writeln(data);

+ 1 - 1
tests/test/tgeneric2.pp

@@ -8,7 +8,7 @@ type
      procedure Add(item: _T);
    end;
 
-procedure TList.Add(item: _T);
+procedure TList<_T>.Add(item: _T);
 var
   i : integer;
 begin

+ 1 - 1
tests/test/tgeneric20.pp

@@ -10,7 +10,7 @@ type
 
   tc1 = specialize tc<tr>;
 
-procedure tc.p(data : T);
+procedure tc<T>.p(data : T);
   begin
     readln(data);
     writeln(data);

+ 9 - 9
tests/test/tgeneric22.pp

@@ -4,33 +4,33 @@ type
   generic TGListItem<T> = class(TObject)
   public var
     FValue: T;
-    FNext: TGListItem;
+    FNext: specialize TGListItem<T>;
     procedure SetValue(Value: T);
     function GetValue: T;
-    procedure Assign(Source: TGListItem);
-    function Merge(Other: TGListItem): TGListItem;
+    procedure Assign(Source: specialize TGListItem<T>);
+    function Merge(Other: specialize TGListItem<T>): specialize TGListItem<T>;
   end;
 
-procedure TGListItem.SetValue(Value: T);
+procedure TGListItem<T>.SetValue(Value: T);
 begin
   FValue := Value;
 end;
 
-function TGListItem.GetValue: T;
+function TGListItem<T>.GetValue: T;
 begin
   Result := FValue;
 end;
 
-procedure TGListItem.Assign(Source: TGListItem);
+procedure TGListItem<T>.Assign(Source: specialize TGListItem<T>);
 begin
   FNext := Source;
 end;
 
-function TGListItem.Merge(Other: TGListItem): TGListItem;
+function TGListItem<T>.Merge(Other: specialize TGListItem<T>): specialize TGListItem<T>;
 var
-  Temp: TGListItem;
+  Temp: specialize TGListItem<T>;
 begin
-  Temp := TGListItem.Create;
+  Temp := specialize TGListItem<T>.Create;
   Temp.SetValue(FNext.GetValue + Other.FNext.GetValue);
   Result := Temp;
 end;

+ 1 - 1
tests/test/tgeneric5.pp

@@ -12,7 +12,7 @@ type
 var
   err : boolean;
 
-procedure TList.Add(item: _T);
+procedure TList<_T>.Add(item: _T);
 var
   i : integer;
   p : pointer;

+ 1 - 1
tests/test/tgeneric6.pp

@@ -13,7 +13,7 @@ type
      procedure Add(item: _T);
    end;
 
-procedure TList.Add(item: _T);
+procedure TList<_T>.Add(item: _T);
 var
   newitem : PListItem;
 begin

+ 3 - 3
tests/test/tgeneric8.pp

@@ -17,7 +17,7 @@ type
      procedure Add(item: _T);
    end;
 
-procedure TList.Add(item: _T);
+procedure TList<_T>.Add(item: _T);
 var
   newitem : PListItem;
 begin
@@ -28,13 +28,13 @@ begin
 end;
 
 
-function TList.GetFirst : TIterator; inline;
+function TList<_T>.GetFirst : TIterator; inline;
   begin
     result:=first;
   end;
 
 
-function TList.GetNext(i : TIterator) : TIterator; inline;
+function TList<_T>.GetNext(i : TIterator) : TIterator; inline;
   begin
     result:=i^.next;
   end;

+ 1 - 1
tests/test/tgeneric9.pp

@@ -7,7 +7,7 @@ type
     procedure Add(const AKey: TK; const AData: TD);
   end;
 
-procedure TMap.Add(const AKey: TK; const AData: TD);
+procedure TMap<TK, TD>.Add(const AKey: TK; const AData: TD);
 begin
   Key := AKey;
   Data := AData;

+ 2 - 2
tests/test/ugeneric10.pp

@@ -18,12 +18,12 @@ type
 
 implementation
 
-procedure TList.Add(item: _T);
+procedure TList<_T>.Add(item: _T);
 begin
   data:=item;
 end;
 
-procedure TList.Sort(compare: TCompareFunc);
+procedure TList<_T>.Sort(compare: TCompareFunc);
 begin
   if compare(data, 20) <= 0 then
     halt(1);

+ 1 - 1
tests/test/ugeneric14.pp

@@ -19,7 +19,7 @@ begin
   Result := 1;
 end;
 
-procedure TGTest.DoSomething;
+procedure TGTest<T>.DoSomething;
 begin
   data := Foo;
 end;

+ 1 - 1
tests/test/ugeneric3.pp

@@ -12,7 +12,7 @@ type
 
 implementation
 
-procedure TList.Add(item: _T);
+procedure TList<_T>.Add(item: _T);
 begin
   data:=item;
 end;

+ 1 - 1
tests/test/ugeneric4.pp

@@ -21,7 +21,7 @@ begin
 end;
 
 
-procedure TList.Fill;
+procedure TList<_T>.Fill;
 begin
   LocalFill;
   data:=globaldata;

+ 1 - 1
tests/test/ugeneric7.pp

@@ -13,7 +13,7 @@ unit ugeneric7;
   implementation
 
 {$R-}
-    procedure tgeneric.test;
+    procedure tgeneric<t>.test;
       var
         l : longint;
       begin

+ 6 - 6
tests/webtbs/tw10247.pp

@@ -28,33 +28,33 @@ type
     procedure SetV(v: TTNode.T);
   end;
 
-constructor TNode.Create;
+constructor TNode<T>.Create;
 begin
 end;
 
-destructor TNode.Destroy;
+destructor TNode<T>.Destroy;
 begin
   inherited Destroy;
 end;
 
-constructor TContainer.Create;
+constructor TContainer<T>.Create;
 begin
   Data:=TTNode.Create;
 end;
 
-destructor TContainer.Destroy;
+destructor TContainer<T>.Destroy;
 begin
   Data.Free;
         inherited Destroy;
 end;
 
-function TContainer.GetAddr: TTNode.PT;
+function TContainer<T>.GetAddr: TTNode.PT;
 begin
         result := @Data.Data;
 end;
 
 
-procedure TContainer.SetV(v: TTNode.T);
+procedure TContainer<T>.SetV(v: TTNode.T);
 begin
   Data.Data:=v;
 end;

+ 2 - 2
tests/webtbs/tw10247b.pp

@@ -16,11 +16,11 @@ type
 
   TTNodeString = specialize TNode<String>;
 
-constructor TNode.Create;
+constructor TNode<T>.Create;
 begin
 end;
 
-destructor TNode.Destroy;
+destructor TNode<T>.Destroy;
 begin
   inherited Destroy;
 end;

+ 1 - 1
tests/webtbs/tw11435b.pp

@@ -12,7 +12,7 @@ type
 
 implementation
 
-function gCBla.add( item: _T) : integer;
+function gCBla<_T>.add( item: _T) : integer;
 begin
   result := 0;
 end;

+ 2 - 2
tests/webtbs/tw11435c.pp

@@ -21,12 +21,12 @@ type
 
 implementation
 
-procedure TList.Add(item: _T);
+procedure TList<_T>.Add(item: _T);
 begin
   data:=item;
 end;
 
-procedure TList.Sort(compare: TCompareFunc);
+procedure TList<_T>.Sort(compare: TCompareFunc);
 begin
   if compare(data, 20) <= 0 then
     halt(1);

+ 1 - 1
tests/webtbs/tw12249.pp

@@ -19,7 +19,7 @@ implementation
 
 { TG2 }
 
-destructor TG2.Destroy;
+destructor TG2<T>.Destroy;
 begin
   inherited Destroy;
 end;

+ 2 - 2
tests/webtbs/tw16065.pp

@@ -8,9 +8,9 @@ type
 
   TSpec = specialize TGen<Integer>;
 
-function TGen.Check(ASource: TObject): Boolean;
+function TGen<_T>.Check(ASource: TObject): Boolean;
 begin
-  Result := (ASource is TGen)   // this line breaks the compiler...
+  Result := (ASource is specialize TGen<_T>)   // this line breaks the compiler...
   and (ASource is ClassType);   // ...it should be equivelent to this line
 end;
 

+ 1 - 1
tests/webtbs/tw17193.pp

@@ -18,7 +18,7 @@ type
   
   S = specialize G2<Integer>;
 
-procedure G2.P;
+procedure G2<T>.P;
 begin
 end;
 

+ 2 - 2
tests/webtbs/tw6624.pp

@@ -9,12 +9,12 @@ type
     function Two: T;
   end;
 
-procedure TGenTest1.One(const a: T);
+procedure TGenTest1<T>.One(const a: T);
 begin
 
 end;
 
-function TGenTest1.Two: T; // fails here
+function TGenTest1<T>.Two: T; // fails here
 begin
 end;
 

+ 1 - 1
tests/webtbs/tw9673.pp

@@ -12,7 +12,7 @@ type
   end;
 	    
 var
-  b : Testclass.TList;
+  b : Testclass<T>.TList;
 	      
 	    
 implementation

+ 1 - 1
tests/webtbs/tw9827.pp

@@ -8,7 +8,7 @@ type
     function some_func(): integer;
   end;
 
-function GList.some_func(): integer;
+function GList<_T>.some_func(): integer;
 begin
   i := -1;
   Result := -1;

+ 1 - 1
tests/webtbs/uw14124.pp

@@ -16,7 +16,7 @@ type
 
 implementation
 
-procedure TGenericType.P;
+procedure TGenericType<TParamType>.P;
 begin
   F := FDefault; // <====== unit1.pas(21,16) Fatal: Internal error 200108121
 end;

+ 1 - 1
tests/webtbs/uw15591.pp

@@ -14,7 +14,7 @@ type
 
 implementation
 
-function GSmartArray.Length() :Integer;
+function GSmartArray<TSomeType>.Length() :Integer;
 begin
   Result := System.Length(fItems);
 end;