浏览代码

compiler: implement generic procedural types
- store type parameter in parasymtable, push it to the symtablestack before parsing arguments and return type
- move procedure/function declaration parsing to procvar_dec subroutine
- don't skip parasymtable while searching types because they store type parameters now
- add TParaSymTable.ReadOnly field to prevent adding defs into symtable. Add defs to the parent symtable in this case (we are adding this symtable to stack to read type parameters only, add defs should go to parent in this case as it was before)

git-svn-id: trunk@16719 -

paul 14 年之前
父节点
当前提交
2599cc63bd
共有 6 个文件被更改,包括 161 次插入58 次删除
  1. 1 0
      .gitattributes
  2. 1 1
      compiler/pdecl.pas
  3. 1 0
      compiler/pdecobj.pas
  4. 101 49
      compiler/ptype.pas
  5. 20 8
      compiler/symtable.pas
  6. 37 0
      tests/test/tgeneric33.pp

+ 1 - 0
.gitattributes

@@ -9426,6 +9426,7 @@ tests/test/tgeneric3.pp svneol=native#text/plain
 tests/test/tgeneric30.pp svneol=native#text/pascal
 tests/test/tgeneric30.pp svneol=native#text/pascal
 tests/test/tgeneric31.pp svneol=native#text/pascal
 tests/test/tgeneric31.pp svneol=native#text/pascal
 tests/test/tgeneric32.pp svneol=native#text/pascal
 tests/test/tgeneric32.pp svneol=native#text/pascal
+tests/test/tgeneric33.pp svneol=native#text/pascal
 tests/test/tgeneric4.pp svneol=native#text/plain
 tests/test/tgeneric4.pp svneol=native#text/plain
 tests/test/tgeneric5.pp svneol=native#text/plain
 tests/test/tgeneric5.pp svneol=native#text/plain
 tests/test/tgeneric6.pp svneol=native#text/plain
 tests/test/tgeneric6.pp svneol=native#text/plain

+ 1 - 1
compiler/pdecl.pas

@@ -611,7 +611,7 @@ implementation
               end;
               end;
             end;
             end;
 
 
-           if isgeneric and not(hdef.typ in [objectdef,recorddef,arraydef]) then
+           if isgeneric and not(hdef.typ in [objectdef,recorddef,arraydef,procvardef]) then
              message(parser_e_cant_create_generics_of_this_type);
              message(parser_e_cant_create_generics_of_this_type);
 
 
            { Stop recording a generic template }
            { Stop recording a generic template }

+ 1 - 0
compiler/pdecobj.pas

@@ -602,6 +602,7 @@ implementation
         case def.typ of
         case def.typ of
           recorddef,objectdef: st:=tabstractrecorddef(def).symtable;
           recorddef,objectdef: st:=tabstractrecorddef(def).symtable;
           arraydef: st:=tarraydef(def).symtable;
           arraydef: st:=tarraydef(def).symtable;
+          procvardef: st:=tprocvardef(def).parast;
           else
           else
             internalerror(201101020);
             internalerror(201101020);
         end;
         end;

+ 101 - 49
compiler/ptype.pas

@@ -215,6 +215,8 @@ implementation
             st:=genericdef.GetSymtable(gs_record);
             st:=genericdef.GetSymtable(gs_record);
           arraydef:
           arraydef:
             st:=tarraydef(genericdef).symtable;
             st:=tarraydef(genericdef).symtable;
+          procvardef:
+            st:=genericdef.GetSymtable(gs_para);
           else
           else
             internalerror(200511182);
             internalerror(200511182);
         end;
         end;
@@ -327,17 +329,31 @@ implementation
                 read_named_type(tt,specializename,genericdef,generictypelist,false);
                 read_named_type(tt,specializename,genericdef,generictypelist,false);
                 ttypesym(srsym).typedef:=tt;
                 ttypesym(srsym).typedef:=tt;
                 tt.typesym:=srsym;
                 tt.typesym:=srsym;
+
+                case tt.typ of
+                  { Build VMT indexes for classes }
+                  objectdef:
+                    begin
+                      vmtbuilder:=TVMTBuilder.Create(tobjectdef(tt));
+                      vmtbuilder.generate_vmt;
+                      vmtbuilder.free;
+                    end;
+                  { handle params, calling convention, etc }
+                  procvardef:
+                    begin
+                      if not check_proc_directive(true) then
+                        begin
+                          try_consume_hintdirective(ttypesym(srsym).symoptions,ttypesym(srsym).deprecatedmsg);
+                          consume(_SEMICOLON);
+                        end;
+                      parse_var_proc_directives(ttypesym(srsym));
+                      handle_calling_convention(tprocvardef(tt));
+                      if try_consume_hintdirective(ttypesym(srsym).symoptions,ttypesym(srsym).deprecatedmsg) then
+                        consume(_SEMICOLON);
+                    end;
+                end;
                 { Consume the semicolon if it is also recorded }
                 { Consume the semicolon if it is also recorded }
                 try_to_consume(_SEMICOLON);
                 try_to_consume(_SEMICOLON);
-
-
-                { Build VMT indexes for classes }
-                if (tt.typ=objectdef) then
-                  begin
-                    vmtbuilder:=TVMTBuilder.Create(tobjectdef(tt));
-                    vmtbuilder.generate_vmt;
-                    vmtbuilder.free;
-                  end;
               end;
               end;
 
 
             { Restore symtablestack }
             { Restore symtablestack }
@@ -1247,15 +1263,87 @@ implementation
            current_genericdef:=old_current_genericdef;
            current_genericdef:=old_current_genericdef;
            current_specializedef:=old_current_specializedef;
            current_specializedef:=old_current_specializedef;
         end;
         end;
+
+        function procvar_dec(genericdef:tstoreddef;genericlist:TFPObjectList):tdef;
+          var
+            is_func:boolean;
+            pd:tabstractprocdef;
+            newtype:ttypesym;
+            old_current_genericdef,
+            old_current_specializedef: tstoreddef;
+            old_parse_generic: boolean;
+          begin
+            old_current_genericdef:=current_genericdef;
+            old_current_specializedef:=current_specializedef;
+            old_parse_generic:=parse_generic;
+
+            current_genericdef:=nil;
+            current_specializedef:=nil;
+
+            is_func:=(token=_FUNCTION);
+            consume(token);
+            pd:=tprocvardef.create(normal_function_level);
+
+            { usage of specialized type inside its generic template }
+            if assigned(genericdef) then
+              current_specializedef:=pd
+            { reject declaration of generic class inside generic class }
+            else if assigned(genericlist) then
+              current_genericdef:=pd;
+            symtablestack.push(pd.parast);
+            insert_generic_parameter_types(pd,genericdef,genericlist);
+            parse_generic:=(df_generic in pd.defoptions);
+            { don't allow to add defs to the symtable - use it for type param search only }
+            tparasymtable(pd.parast).readonly:=true;
+
+            if token=_LKLAMMER then
+              parse_parameter_dec(pd);
+            if is_func then
+              begin
+                consume(_COLON);
+                single_type(pd.returndef,[]);
+              end;
+            if try_to_consume(_OF) then
+              begin
+                consume(_OBJECT);
+                include(pd.procoptions,po_methodpointer);
+              end
+            else if (m_nested_procvars in current_settings.modeswitches) and
+                    try_to_consume(_IS) then
+              begin
+                consume(_NESTED);
+                pd.parast.symtablelevel:=normal_function_level+1;
+                pd.check_mark_as_nested;
+              end;
+            symtablestack.pop(pd.parast);
+            tparasymtable(pd.parast).readonly:=false;
+            result:=pd;
+            { possible proc directives }
+            if parseprocvardir then
+              begin
+                if check_proc_directive(true) then
+                  begin
+                    newtype:=ttypesym.create('unnamed',result);
+                    parse_var_proc_directives(tsym(newtype));
+                    newtype.typedef:=nil;
+                    result.typesym:=nil;
+                    newtype.free;
+                  end;
+                { Add implicit hidden parameters and function result }
+                handle_calling_convention(pd);
+              end;
+            { restore old state }
+            parse_generic:=old_parse_generic;
+            current_genericdef:=old_current_genericdef;
+            current_specializedef:=old_current_specializedef;
+          end;
+
       const
       const
         SingleTypeOptionsInTypeBlock:array[Boolean] of TSingleTypeOptions = ([],[stoIsForwardDef]);
         SingleTypeOptionsInTypeBlock:array[Boolean] of TSingleTypeOptions = ([],[stoIsForwardDef]);
       var
       var
         p  : tnode;
         p  : tnode;
         hdef : tdef;
         hdef : tdef;
-        pd : tabstractprocdef;
-        is_func,
         enumdupmsg, first, is_specialize : boolean;
         enumdupmsg, first, is_specialize : boolean;
-        newtype : ttypesym;
         oldlocalswitches : tlocalswitches;
         oldlocalswitches : tlocalswitches;
         bitpacking: boolean;
         bitpacking: boolean;
         stitem: psymtablestackitem;
         stitem: psymtablestackitem;
@@ -1506,43 +1594,7 @@ implementation
             _PROCEDURE,
             _PROCEDURE,
             _FUNCTION:
             _FUNCTION:
               begin
               begin
-                is_func:=(token=_FUNCTION);
-                consume(token);
-                pd:=tprocvardef.create(normal_function_level);
-                if token=_LKLAMMER then
-                  parse_parameter_dec(pd);
-                if is_func then
-                 begin
-                   consume(_COLON);
-                   single_type(pd.returndef,[]);
-                 end;
-                if try_to_consume(_OF) then
-                  begin
-                    consume(_OBJECT);
-                    include(pd.procoptions,po_methodpointer);
-                  end
-                else if (m_nested_procvars in current_settings.modeswitches) and
-                        try_to_consume(_IS) then
-                  begin
-                    consume(_NESTED);
-                    pd.parast.symtablelevel:=normal_function_level+1;
-                    pd.check_mark_as_nested;
-                  end;
-                def:=pd;
-                { possible proc directives }
-                if parseprocvardir then
-                  begin
-                    if check_proc_directive(true) then
-                      begin
-                         newtype:=ttypesym.create('unnamed',def);
-                         parse_var_proc_directives(tsym(newtype));
-                         newtype.typedef:=nil;
-                         def.typesym:=nil;
-                         newtype.free;
-                      end;
-                    { Add implicit hidden parameters and function result }
-                    handle_calling_convention(pd);
-                  end;
+                def:=procvar_dec(genericdef,genericlist);
               end;
               end;
             else
             else
               if (token=_KLAMMERAFFE) and (m_iso in current_settings.modeswitches) then
               if (token=_KLAMMERAFFE) and (m_iso in current_settings.modeswitches) then

+ 20 - 8
compiler/symtable.pas

@@ -125,13 +125,17 @@ interface
        tlocalsymtable = class(tabstractlocalsymtable)
        tlocalsymtable = class(tabstractlocalsymtable)
        public
        public
           constructor create(adefowner:tdef;level:byte);
           constructor create(adefowner:tdef;level:byte);
-          function  checkduplicate(var hashedid:THashedIDString;sym:TSymEntry):boolean;override;
+          function checkduplicate(var hashedid:THashedIDString;sym:TSymEntry):boolean;override;
        end;
        end;
 
 
+       { tparasymtable }
+
        tparasymtable = class(tabstractlocalsymtable)
        tparasymtable = class(tabstractlocalsymtable)
        public
        public
+          readonly: boolean;
           constructor create(adefowner:tdef;level:byte);
           constructor create(adefowner:tdef;level:byte);
-          function  checkduplicate(var hashedid:THashedIDString;sym:TSymEntry):boolean;override;
+          function checkduplicate(var hashedid:THashedIDString;sym:TSymEntry):boolean;override;
+          procedure insertdef(def:TDefEntry);override;
        end;
        end;
 
 
        tabstractuniTSymtable = class(tstoredsymtable)
        tabstractuniTSymtable = class(tstoredsymtable)
@@ -1373,6 +1377,7 @@ implementation
     constructor tparasymtable.create(adefowner:tdef;level:byte);
     constructor tparasymtable.create(adefowner:tdef;level:byte);
       begin
       begin
         inherited create('');
         inherited create('');
+        readonly:=false;
         defowner:=adefowner;
         defowner:=adefowner;
         symtabletype:=parasymtable;
         symtabletype:=parasymtable;
         symtablelevel:=level;
         symtablelevel:=level;
@@ -1395,6 +1400,14 @@ implementation
           result:=tprocdef(defowner).struct.symtable.checkduplicate(hashedid,sym);
           result:=tprocdef(defowner).struct.symtable.checkduplicate(hashedid,sym);
       end;
       end;
 
 
+    procedure tparasymtable.insertdef(def: TDefEntry);
+      begin
+        if readonly then
+          defowner.owner.insertdef(def)
+        else
+          inherited insertdef(def);
+      end;
+
 
 
 {****************************************************************************
 {****************************************************************************
                          TAbstractUniTSymtable
                          TAbstractUniTSymtable
@@ -1952,11 +1965,11 @@ implementation
                 while assigned(classh) do
                 while assigned(classh) do
                   begin
                   begin
                     srsymtable:=classh.symtable;
                     srsymtable:=classh.symtable;
-                srsym:=tsym(srsymtable.FindWithHash(hashedid));
-                if assigned(srsym) and
-                       not(srsym.typ in [fieldvarsym,paravarsym,propertysym,procsym,labelsym]) and
-                       is_visible_for_object(srsym,current_structdef) then
-                  begin
+                    srsym:=tsym(srsymtable.FindWithHash(hashedid));
+                     if assigned(srsym) and
+                        not(srsym.typ in [fieldvarsym,paravarsym,propertysym,procsym,labelsym]) and
+                        is_visible_for_object(srsym,current_structdef) then
+                       begin
                         addsymref(srsym);
                         addsymref(srsym);
                         result:=true;
                         result:=true;
                         exit;
                         exit;
@@ -1965,7 +1978,6 @@ implementation
                   end;
                   end;
               end
               end
             else
             else
-            if srsymtable.symtabletype<>parasymtable then
               begin
               begin
                 srsym:=tsym(srsymtable.FindWithHash(hashedid));
                 srsym:=tsym(srsymtable.FindWithHash(hashedid));
                 if assigned(srsym) and 
                 if assigned(srsym) and 

+ 37 - 0
tests/test/tgeneric33.pp

@@ -0,0 +1,37 @@
+program tgeneric33;
+
+{$mode objfpc}{$H+}
+type
+  // regular procdef
+  generic TProc1<T> = function(Value: T): T;
+  // object procdef
+  generic TProc2<T> = function(Value: T): T of object;
+
+  TFoo = class
+    function Test2(Value: Integer): Integer;
+  end;
+
+function Test1(Value: Integer): Integer;
+begin
+  Result := Value + 1;
+end;
+
+function TFoo.Test2(Value: Integer): Integer;
+begin
+  Result := Value - 1;
+end;
+
+var
+  Foo: TFoo;
+  Proc1: specialize TProc1<Integer>;
+  Proc2: specialize TProc2<Integer>;
+begin
+  Proc1 := @Test1;
+  if Proc1(1) <> 2 then
+    halt(1);
+  Foo := TFoo.Create;
+  Proc2 := @Foo.Test2;
+  if Proc2(2) <> 1 then
+    halt(2);
+  Foo.Free;
+end.