* merges recent class helper fixes by Sven Barth

git-svn-id: trunk@17887 -
This commit is contained in:
florian 2011-06-30 18:54:46 +00:00
parent c5dfa9d354
commit 570f3c4b39
14 changed files with 263 additions and 4 deletions

7
.gitattributes vendored
View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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
tests/test/tchlp55.pp Normal file
View File

@ -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
tests/test/tchlp56.pp Normal file
View File

@ -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
tests/test/tchlp57.pp Normal file
View File

@ -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
tests/test/tchlp58.pp Normal file
View File

@ -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
tests/test/thlp45.pp Normal file
View File

@ -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
tests/test/trhlp42.pp Normal file
View File

@ -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
tests/test/trhlp43.pp Normal file
View File

@ -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.