Browse Source

* merges recent class helper fixes by Sven Barth

git-svn-id: trunk@17887 -
florian 14 years ago
parent
commit
570f3c4b39

+ 7 - 0
.gitattributes

@@ -9846,6 +9846,10 @@ tests/test/tchlp51.pp svneol=native#text/pascal
 tests/test/tchlp52.pp svneol=native#text/pascal
 tests/test/tchlp52.pp svneol=native#text/pascal
 tests/test/tchlp53.pp svneol=native#text/pascal
 tests/test/tchlp53.pp svneol=native#text/pascal
 tests/test/tchlp54.pp svneol=native#text/pascal
 tests/test/tchlp54.pp svneol=native#text/pascal
+tests/test/tchlp55.pp svneol=native#text/pascal
+tests/test/tchlp56.pp svneol=native#text/pascal
+tests/test/tchlp57.pp svneol=native#text/pascal
+tests/test/tchlp58.pp svneol=native#text/pascal
 tests/test/tchlp6.pp svneol=native#text/pascal
 tests/test/tchlp6.pp svneol=native#text/pascal
 tests/test/tchlp7.pp svneol=native#text/pascal
 tests/test/tchlp7.pp svneol=native#text/pascal
 tests/test/tchlp8.pp svneol=native#text/pascal
 tests/test/tchlp8.pp svneol=native#text/pascal
@@ -10055,6 +10059,7 @@ tests/test/thlp41.pp svneol=native#text/pascal
 tests/test/thlp42.pp svneol=native#text/pascal
 tests/test/thlp42.pp svneol=native#text/pascal
 tests/test/thlp43.pp svneol=native#text/pascal
 tests/test/thlp43.pp svneol=native#text/pascal
 tests/test/thlp44.pp svneol=native#text/pascal
 tests/test/thlp44.pp svneol=native#text/pascal
+tests/test/thlp45.pp svneol=native#text/pascal
 tests/test/thlp5.pp svneol=native#text/pascal
 tests/test/thlp5.pp svneol=native#text/pascal
 tests/test/thlp6.pp svneol=native#text/pascal
 tests/test/thlp6.pp svneol=native#text/pascal
 tests/test/thlp7.pp svneol=native#text/pascal
 tests/test/thlp7.pp svneol=native#text/pascal
@@ -10364,6 +10369,8 @@ tests/test/trhlp39.pp svneol=native#text/pascal
 tests/test/trhlp4.pp svneol=native#text/pascal
 tests/test/trhlp4.pp svneol=native#text/pascal
 tests/test/trhlp40.pp svneol=native#text/pascal
 tests/test/trhlp40.pp svneol=native#text/pascal
 tests/test/trhlp41.pp svneol=native#text/pascal
 tests/test/trhlp41.pp svneol=native#text/pascal
+tests/test/trhlp42.pp svneol=native#text/pascal
+tests/test/trhlp43.pp svneol=native#text/pascal
 tests/test/trhlp5.pp svneol=native#text/pascal
 tests/test/trhlp5.pp svneol=native#text/pascal
 tests/test/trhlp6.pp svneol=native#text/pascal
 tests/test/trhlp6.pp svneol=native#text/pascal
 tests/test/trhlp7.pp svneol=native#text/pascal
 tests/test/trhlp7.pp svneol=native#text/pascal

+ 4 - 2
compiler/dbgdwarf.pas

@@ -922,7 +922,7 @@ implementation
                       internalerror(200610011);
                       internalerror(200610011);
                     def.dwarf_lab:=current_asmdata.RefAsmSymbol(make_mangledname('DBG',def.owner,symname(def.typesym)));
                     def.dwarf_lab:=current_asmdata.RefAsmSymbol(make_mangledname('DBG',def.owner,symname(def.typesym)));
                     def.dwarf_ref_lab:=current_asmdata.RefAsmSymbol(make_mangledname('DBGREF',def.owner,symname(def.typesym)));
                     def.dwarf_ref_lab:=current_asmdata.RefAsmSymbol(make_mangledname('DBGREF',def.owner,symname(def.typesym)));
-                    if is_class_or_interface_or_dispinterface(def) then
+                    if is_class_or_interface_or_dispinterface(def) or is_objectpascal_helper(def) then
                       tobjectdef(def).dwarf_struct_lab:=current_asmdata.RefAsmSymbol(make_mangledname('DBG2',def.owner,symname(def.typesym)));
                       tobjectdef(def).dwarf_struct_lab:=current_asmdata.RefAsmSymbol(make_mangledname('DBG2',def.owner,symname(def.typesym)));
                     def.dbg_state:=dbg_state_written;
                     def.dbg_state:=dbg_state_written;
                   end
                   end
@@ -936,7 +936,7 @@ implementation
                       begin
                       begin
                         def.dwarf_lab:=current_asmdata.DefineAsmSymbol(make_mangledname('DBG',def.owner,symname(def.typesym)),AB_GLOBAL,AT_DATA);
                         def.dwarf_lab:=current_asmdata.DefineAsmSymbol(make_mangledname('DBG',def.owner,symname(def.typesym)),AB_GLOBAL,AT_DATA);
                         def.dwarf_ref_lab:=current_asmdata.DefineAsmSymbol(make_mangledname('DBGREF',def.owner,symname(def.typesym)),AB_GLOBAL,AT_DATA);
                         def.dwarf_ref_lab:=current_asmdata.DefineAsmSymbol(make_mangledname('DBGREF',def.owner,symname(def.typesym)),AB_GLOBAL,AT_DATA);
-                        if is_class_or_interface_or_dispinterface(def) then
+                        if is_class_or_interface_or_dispinterface(def) or is_objectpascal_helper(def) then
                           tobjectdef(def).dwarf_struct_lab:=current_asmdata.DefineAsmSymbol(make_mangledname('DBG2',def.owner,symname(def.typesym)),AB_GLOBAL,AT_DATA);
                           tobjectdef(def).dwarf_struct_lab:=current_asmdata.DefineAsmSymbol(make_mangledname('DBG2',def.owner,symname(def.typesym)),AB_GLOBAL,AT_DATA);
                         include(def.defstates,ds_dwarf_dbg_info_written);
                         include(def.defstates,ds_dwarf_dbg_info_written);
                       end
                       end
@@ -3541,6 +3541,7 @@ implementation
           odt_interfacecom,
           odt_interfacecom,
           odt_interfacecorba,
           odt_interfacecorba,
           odt_dispinterface,
           odt_dispinterface,
+          odt_helper,
           odt_class:
           odt_class:
             begin
             begin
               { implicit pointer }
               { implicit pointer }
@@ -3948,6 +3949,7 @@ implementation
               dostruct(DW_TAG_interface_type);
               dostruct(DW_TAG_interface_type);
               doparent(true);
               doparent(true);
             end;
             end;
+          odt_helper,
           odt_class:
           odt_class:
             begin
             begin
               //dostruct(DW_TAG_class_type);
               //dostruct(DW_TAG_class_type);

+ 16 - 0
compiler/htypechk.pas

@@ -1865,6 +1865,22 @@ implementation
                if not hasoverload then
                if not hasoverload then
                  break;
                  break;
              end;
              end;
+           if is_objectpascal_helper(structdef) then
+             begin
+               if not assigned(tobjectdef(structdef).extendeddef) then
+                 Internalerror(2011062601);
+               { search methods in the extended type as well }
+               srsym:=tprocsym(tobjectdef(structdef).extendeddef.symtable.FindWithHash(hashedid));
+               if assigned(srsym) and
+                  { Delphi allows hiding a property by a procedure with the same name }
+                  (srsym.typ=procsym) then
+                 begin
+                   hasoverload:=processprocsym(tprocsym(srsym));
+                   { when there is no explicit overload we stop searching }
+                   if not hasoverload then
+                     break;
+                 end;
+             end;
            { next parent }
            { next parent }
            if (structdef.typ=objectdef) then
            if (structdef.typ=objectdef) then
              structdef:=tobjectdef(structdef).childof
              structdef:=tobjectdef(structdef).childof

+ 8 - 1
compiler/ncal.pas

@@ -1638,6 +1638,7 @@ implementation
     function tcallnode.gen_self_tree:tnode;
     function tcallnode.gen_self_tree:tnode;
       var
       var
         selftree : tnode;
         selftree : tnode;
+        selfdef  : tabstractrecorddef;
       begin
       begin
         selftree:=nil;
         selftree:=nil;
 
 
@@ -1685,7 +1686,13 @@ implementation
             begin
             begin
               if (procdefinition.typ<>procdef) then
               if (procdefinition.typ<>procdef) then
                 internalerror(200305062);
                 internalerror(200305062);
-              if (oo_has_vmt in tprocdef(procdefinition).struct.objectoptions) then
+              { if the method belongs to a helper then we need to use the
+                extended type for references to Self }
+              if is_objectpascal_helper(tprocdef(procdefinition).struct) then
+                selfdef:=tobjectdef(tprocdef(procdefinition).struct).extendeddef
+              else
+                selfdef:=tprocdef(procdefinition).struct;
+              if (oo_has_vmt in selfdef.objectoptions) then
                 begin
                 begin
                   { we only need the vmt, loading self is not required and there is no
                   { we only need the vmt, loading self is not required and there is no
                     need to check for typen, because that will always get the
                     need to check for typen, because that will always get the

+ 45 - 0
compiler/pstatmnt.pas

@@ -516,19 +516,36 @@ implementation
          hp,
          hp,
          refnode  : tnode;
          refnode  : tnode;
          hdef : tdef;
          hdef : tdef;
+         extendeddef : tabstractrecorddef;
+         helperdef : tobjectdef;
          hasimplicitderef : boolean;
          hasimplicitderef : boolean;
          withsymtablelist : TFPObjectList;
          withsymtablelist : TFPObjectList;
 
 
          procedure pushobjchild(withdef,obj:tobjectdef);
          procedure pushobjchild(withdef,obj:tobjectdef);
+         var
+           parenthelperdef : tobjectdef;
          begin
          begin
            if not assigned(obj) then
            if not assigned(obj) then
              exit;
              exit;
            pushobjchild(withdef,obj.childof);
            pushobjchild(withdef,obj.childof);
+           { we need to look for helpers that were defined for the parent
+             class as well }
+           search_last_objectpascal_helper(obj,current_structdef,parenthelperdef);
+           { push the symtables of the helper's parents in reverse order }
+           if assigned(parenthelperdef) then
+             pushobjchild(withdef,parenthelperdef.childof);
            { keep the original tobjectdef as owner, because that is used for
            { keep the original tobjectdef as owner, because that is used for
              visibility of the symtable }
              visibility of the symtable }
            st:=twithsymtable.create(withdef,obj.symtable.SymList,refnode.getcopy);
            st:=twithsymtable.create(withdef,obj.symtable.SymList,refnode.getcopy);
            symtablestack.push(st);
            symtablestack.push(st);
            withsymtablelist.add(st);
            withsymtablelist.add(st);
+           { push the symtable of the helper }
+           if assigned(parenthelperdef) then
+             begin
+               st:=twithsymtable.create(withdef,parenthelperdef.symtable.SymList,refnode.getcopy);
+               symtablestack.push(st);
+               withsymtablelist.add(st);
+             end;
          end;
          end;
 
 
 
 
@@ -625,12 +642,25 @@ implementation
                 typecheckpass(refnode);
                 typecheckpass(refnode);
               end;
               end;
 
 
+            { do we have a helper for this type? }
+            if p.resultdef.typ=classrefdef then
+              extendeddef:=tobjectdef(tclassrefdef(p.resultdef).pointeddef)
+            else
+              extendeddef:=tabstractrecorddef(p.resultdef);
+            search_last_objectpascal_helper(extendeddef,current_structdef,helperdef);
+            { Note: the symtable of the helper is pushed after the following
+                    "case", the symtables of the helper's parents are passed in
+                    the "case" branches }
+
             withsymtablelist:=TFPObjectList.create(true);
             withsymtablelist:=TFPObjectList.create(true);
             case p.resultdef.typ of
             case p.resultdef.typ of
               objectdef :
               objectdef :
                 begin
                 begin
                    { push symtables of all parents in reverse order }
                    { push symtables of all parents in reverse order }
                    pushobjchild(tobjectdef(p.resultdef),tobjectdef(p.resultdef).childof);
                    pushobjchild(tobjectdef(p.resultdef),tobjectdef(p.resultdef).childof);
+                   { push symtables of all parents of the helper in reverse order }
+                   if assigned(helperdef) then
+                     pushobjchild(helperdef,helperdef.childof);
                    { push object symtable }
                    { push object symtable }
                    st:=twithsymtable.Create(tobjectdef(p.resultdef),tobjectdef(p.resultdef).symtable.SymList,refnode);
                    st:=twithsymtable.Create(tobjectdef(p.resultdef),tobjectdef(p.resultdef).symtable.SymList,refnode);
                    symtablestack.push(st);
                    symtablestack.push(st);
@@ -640,6 +670,9 @@ implementation
                 begin
                 begin
                    { push symtables of all parents in reverse order }
                    { push symtables of all parents in reverse order }
                    pushobjchild(tobjectdef(tclassrefdef(p.resultdef).pointeddef),tobjectdef(tclassrefdef(p.resultdef).pointeddef).childof);
                    pushobjchild(tobjectdef(tclassrefdef(p.resultdef).pointeddef),tobjectdef(tclassrefdef(p.resultdef).pointeddef).childof);
+                   { push symtables of all parents of the helper in reverse order }
+                   if assigned(helperdef) then
+                     pushobjchild(helperdef,helperdef.childof);
                    { push object symtable }
                    { push object symtable }
                    st:=twithsymtable.Create(tobjectdef(tclassrefdef(p.resultdef).pointeddef),tobjectdef(tclassrefdef(p.resultdef).pointeddef).symtable.SymList,refnode);
                    st:=twithsymtable.Create(tobjectdef(tclassrefdef(p.resultdef).pointeddef),tobjectdef(tclassrefdef(p.resultdef).pointeddef).symtable.SymList,refnode);
                    symtablestack.push(st);
                    symtablestack.push(st);
@@ -647,6 +680,10 @@ implementation
                 end;
                 end;
               recorddef :
               recorddef :
                 begin
                 begin
+                   { push symtables of all parents of the helper in reverse order }
+                   if assigned(helperdef) then
+                     pushobjchild(helperdef,helperdef.childof);
+                   { push record symtable }
                    st:=twithsymtable.create(trecorddef(p.resultdef),trecorddef(p.resultdef).symtable.SymList,refnode);
                    st:=twithsymtable.create(trecorddef(p.resultdef),trecorddef(p.resultdef).symtable.SymList,refnode);
                    symtablestack.push(st);
                    symtablestack.push(st);
                    withsymtablelist.add(st);
                    withsymtablelist.add(st);
@@ -655,6 +692,14 @@ implementation
                 internalerror(200601271);
                 internalerror(200601271);
             end;
             end;
 
 
+            { push helper symtable }
+            if assigned(helperdef) then
+              begin
+                st:=twithsymtable.Create(helperdef,helperdef.symtable.SymList,refnode.getcopy);
+                symtablestack.push(st);
+                withsymtablelist.add(st);
+              end;
+
             if try_to_consume(_COMMA) then
             if try_to_consume(_COMMA) then
               p:=_with_statement()
               p:=_with_statement()
             else
             else

+ 1 - 1
compiler/symdef.pas

@@ -5783,7 +5783,7 @@ implementation
         result:=
         result:=
           assigned(def) and
           assigned(def) and
           (def.typ=objectdef) and
           (def.typ=objectdef) and
-          (tobjectdef(def).objecttype in [odt_class,odt_interfacecom,odt_interfacecorba,odt_dispinterface,odt_objcclass,odt_objcprotocol]);
+          (tobjectdef(def).objecttype in [odt_class,odt_interfacecom,odt_interfacecorba,odt_dispinterface,odt_objcclass,odt_objcprotocol,odt_helper]);
       end;
       end;
 
 
     function is_class_or_object(def: tdef): boolean;
     function is_class_or_object(def: tdef): boolean;

+ 1 - 0
compiler/symtable.pas

@@ -2560,6 +2560,7 @@ implementation
         st: tsymtable;
         st: tsymtable;
       begin
       begin
         result:=false;
         result:=false;
+        odef:=nil;
         { when there are no helpers active currently then we don't need to do
         { when there are no helpers active currently then we don't need to do
           anything }
           anything }
         if current_module.extendeddefs.count=0 then
         if current_module.extendeddefs.count=0 then

+ 21 - 0
tests/test/tchlp55.pp

@@ -0,0 +1,21 @@
+{ %NORUN }
+
+{ This tests that methods introduced by a helper can be found in 
+  with-Statements as well - Case 1: normal method in current helper }
+program tchlp55;
+
+{$mode objfpc}
+
+type
+  TObjectHelper = class helper for TObject
+    procedure Test;
+  end;
+
+procedure TObjectHelper.Test;
+begin
+end;
+
+begin
+  with TObject.Create do
+    Test;
+end.

+ 21 - 0
tests/test/tchlp56.pp

@@ -0,0 +1,21 @@
+{ %NORUN }
+
+{ This tests that methods introduced by a helper can be found in 
+  with-Statements as well - Case 2: class method in current helper }
+program tchlp56;
+
+{$mode objfpc}
+
+type
+  TObjectHelper = class helper for TObject
+    class procedure Test;
+  end;
+
+class procedure TObjectHelper.Test;
+begin
+end;
+
+begin
+  with TObject do
+    Test;
+end.

+ 24 - 0
tests/test/tchlp57.pp

@@ -0,0 +1,24 @@
+{ %NORUN }
+
+{ This tests that methods introduced by a helper can be found in 
+  with-Statements as well - Case 3: normal method in parent's helper }
+program tchlp57;
+
+{$mode objfpc}
+
+type
+  TObjectHelper = class helper for TObject
+    procedure Test;
+  end;
+
+  TTest = class
+  end;
+
+procedure TObjectHelper.Test;
+begin
+end;
+
+begin
+  with TTest.Create do
+    Test;
+end.

+ 24 - 0
tests/test/tchlp58.pp

@@ -0,0 +1,24 @@
+{ %NORUN }
+
+{ This tests that methods introduced by a helper can be found in 
+  with-Statements as well - Case 4: class method in parent's helper }
+program tchlp58;
+
+{$mode objfpc}
+
+type
+  TObjectHelper = class helper for TObject
+    class procedure Test;
+  end;
+
+  TTest = class
+  end;
+
+class procedure TObjectHelper.Test;
+begin
+end;
+
+begin
+  with TTest do
+    Test;
+end.

+ 39 - 0
tests/test/thlp45.pp

@@ -0,0 +1,39 @@
+{ this tests that the correct method is called if a helper overloads an
+  existing function and calls the original one recursively }
+program thlp45;
+
+{$mode objfpc}{$H+}
+
+type
+  TTest = class
+    function Test(aRecurse: Boolean; aTest: String): Integer;
+  end;
+
+  TTestHelper = class helper for TTest
+    function Test(aRecurse: Boolean; aTest: array of String): Integer; overload;
+  end;
+
+function TTest.Test(aRecurse: Boolean; aTest: String): Integer;
+begin
+  Result := 1;
+end;
+
+function TTestHelper.Test(aRecurse: Boolean; aTest: array of String): Integer;
+begin
+  if aRecurse then
+    Result := Test(False, aTest[0])
+  else
+    Result := 2;  
+end;
+
+var
+  t: TTest;
+  res: Integer;
+begin
+  t := TTest.Create;
+  res := t.Test(True, ['Test']);
+  Writeln('t.Test: ', res);
+  if res <> 1 then
+    Halt(1);
+  Writeln('ok');
+end.

+ 27 - 0
tests/test/trhlp42.pp

@@ -0,0 +1,27 @@
+{ %NORUN }
+
+{ This tests that methods introduced by a helper can be found in 
+  with-Statements as well - Case 1: normal method in current helper }
+program trhlp42;
+
+{$mode objfpc}
+{$modeswitch advancedrecords}
+
+type
+  TTest = record
+  end;
+
+  TTestHelper = record helper for TTest
+    procedure Test;
+  end;
+
+procedure TTestHelper.Test;
+begin
+end;
+
+var
+  t: TTest;
+begin
+  with t do
+    Test;
+end.

+ 25 - 0
tests/test/trhlp43.pp

@@ -0,0 +1,25 @@
+{ %NORUN }
+
+{ This tests that methods introduced by a helper can be found in 
+  with-Statements as well - Case 2: class method in current helper }
+program trhlp43;
+
+{$mode objfpc}
+{$modeswitch advancedrecords}
+
+type
+  TTest = record
+  end;
+
+  TTestHelper = record helper for TTest
+    class procedure Test; static;
+  end;
+
+class procedure TTestHelper.Test;
+begin
+end;
+
+begin
+  with TTest do
+    Test;
+end.