mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-06-05 00:58:55 +02:00
Correctly specialize generics if locally declared types are used (e.g. two procedures could both define a different "TRec" type which is used to specialize a generic inside the procedures).
symtype.pas, tdef: + add method "fullownerhierarchyname" which allows to retrieve the owner hierarchy name including procedure/function/method names + add method "fulltypename" which uses "fullownerhierarchyname" to return a full type name symdef.pas, tstoreddef: * implement "fullownerhierarchyname" (including caching of the result) pgenutil.pas, parse_generic_specialization_types_internal: * use "tdef.fulltypename" instead of "tdef.typename" to have unique values for each parsed type and thus for the specialization itself + tests git-svn-id: trunk@25175 -
This commit is contained in:
parent
a4ef523461
commit
53ea24a0b1
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -11253,6 +11253,8 @@ tests/test/tgeneric90.pp svneol=native#text/pascal
|
|||||||
tests/test/tgeneric91.pp svneol=native#text/pascal
|
tests/test/tgeneric91.pp svneol=native#text/pascal
|
||||||
tests/test/tgeneric92.pp svneol=native#text/pascal
|
tests/test/tgeneric92.pp svneol=native#text/pascal
|
||||||
tests/test/tgeneric93.pp svneol=native#text/pascal
|
tests/test/tgeneric93.pp svneol=native#text/pascal
|
||||||
|
tests/test/tgeneric94.pp svneol=native#text/pascal
|
||||||
|
tests/test/tgeneric95.pp svneol=native#text/pascal
|
||||||
tests/test/tgoto.pp svneol=native#text/plain
|
tests/test/tgoto.pp svneol=native#text/plain
|
||||||
tests/test/theap.pp svneol=native#text/plain
|
tests/test/theap.pp svneol=native#text/plain
|
||||||
tests/test/theapthread.pp svneol=native#text/plain
|
tests/test/theapthread.pp svneol=native#text/plain
|
||||||
|
@ -278,7 +278,7 @@ uses
|
|||||||
if assigned(parsedtype) then
|
if assigned(parsedtype) then
|
||||||
begin
|
begin
|
||||||
genericdeflist.Add(parsedtype);
|
genericdeflist.Add(parsedtype);
|
||||||
specializename:='$'+parsedtype.typename;
|
specializename:='$'+parsedtype.fulltypename;
|
||||||
prettyname:=parsedtype.typesym.prettyname;
|
prettyname:=parsedtype.typesym.prettyname;
|
||||||
if assigned(poslist) then
|
if assigned(poslist) then
|
||||||
begin
|
begin
|
||||||
@ -315,11 +315,11 @@ uses
|
|||||||
message(type_e_generics_cannot_reference_itself)
|
message(type_e_generics_cannot_reference_itself)
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
specializename:=specializename+'$'+typeparam.resultdef.typename;
|
{ we use the full name of the type to uniquely identify it }
|
||||||
if first then
|
specializename:=specializename+'$'+typeparam.resultdef.fulltypename;
|
||||||
prettyname:=prettyname+typeparam.resultdef.typesym.prettyname
|
if not first then
|
||||||
else
|
prettyname:=prettyname+',';
|
||||||
prettyname:=prettyname+','+typeparam.resultdef.typesym.prettyname;
|
prettyname:=prettyname+typeparam.resultdef.fullownerhierarchyname+typeparam.resultdef.typesym.prettyname;
|
||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
@ -66,6 +66,8 @@ interface
|
|||||||
{ tstoreddef }
|
{ tstoreddef }
|
||||||
|
|
||||||
tstoreddef = class(tdef)
|
tstoreddef = class(tdef)
|
||||||
|
private
|
||||||
|
_fullownerhierarchyname : pshortstring;
|
||||||
protected
|
protected
|
||||||
typesymderef : tderef;
|
typesymderef : tderef;
|
||||||
procedure fillgenericparas(symtable:tsymtable);
|
procedure fillgenericparas(symtable:tsymtable);
|
||||||
@ -100,6 +102,7 @@ interface
|
|||||||
function needs_inittable : boolean;override;
|
function needs_inittable : boolean;override;
|
||||||
function rtti_mangledname(rt:trttitype):string;override;
|
function rtti_mangledname(rt:trttitype):string;override;
|
||||||
function OwnerHierarchyName: string; override;
|
function OwnerHierarchyName: string; override;
|
||||||
|
function fullownerhierarchyname:string;override;
|
||||||
function needs_separate_initrtti:boolean;override;
|
function needs_separate_initrtti:boolean;override;
|
||||||
function in_currentunit: boolean;
|
function in_currentunit: boolean;
|
||||||
{ regvars }
|
{ regvars }
|
||||||
@ -1532,6 +1535,7 @@ implementation
|
|||||||
end;
|
end;
|
||||||
genericparas.free;
|
genericparas.free;
|
||||||
genconstraintdata.free;
|
genconstraintdata.free;
|
||||||
|
stringdispose(_fullownerhierarchyname);
|
||||||
inherited destroy;
|
inherited destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -1621,6 +1625,36 @@ implementation
|
|||||||
until tmp=nil;
|
until tmp=nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function tstoreddef.fullownerhierarchyname: string;
|
||||||
|
var
|
||||||
|
tmp: tdef;
|
||||||
|
begin
|
||||||
|
if assigned(_fullownerhierarchyname) then
|
||||||
|
begin
|
||||||
|
result:=_fullownerhierarchyname^;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
{ the def can only reside inside structured types or
|
||||||
|
procedures/functions/methods }
|
||||||
|
tmp:=self;
|
||||||
|
result:='';
|
||||||
|
repeat
|
||||||
|
{ can be not assigned in case of a forwarddef }
|
||||||
|
if not assigned(tmp.owner) then
|
||||||
|
break
|
||||||
|
else
|
||||||
|
tmp:=tdef(tmp.owner.defowner);
|
||||||
|
if not assigned(tmp) then
|
||||||
|
break;
|
||||||
|
if tmp.typ in [recorddef,objectdef] then
|
||||||
|
result:=tabstractrecorddef(tmp).objrealname^+'.'+result
|
||||||
|
else
|
||||||
|
if tmp.typ=procdef then
|
||||||
|
result:=tprocdef(tmp).customprocname([pno_paranames,pno_proctypeoption])+'.'+result;
|
||||||
|
until tmp=nil;
|
||||||
|
_fullownerhierarchyname:=stringdup(result);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
function tstoreddef.in_currentunit: boolean;
|
function tstoreddef.in_currentunit: boolean;
|
||||||
var
|
var
|
||||||
|
@ -68,12 +68,14 @@ interface
|
|||||||
procedure deref;virtual;abstract;
|
procedure deref;virtual;abstract;
|
||||||
procedure derefimpl;virtual;abstract;
|
procedure derefimpl;virtual;abstract;
|
||||||
function typename:string;
|
function typename:string;
|
||||||
|
function fulltypename:string;
|
||||||
function GetTypeName:string;virtual;
|
function GetTypeName:string;virtual;
|
||||||
function typesymbolprettyname:string;virtual;
|
function typesymbolprettyname:string;virtual;
|
||||||
function mangledparaname:string;
|
function mangledparaname:string;
|
||||||
function getmangledparaname:TSymStr;virtual;
|
function getmangledparaname:TSymStr;virtual;
|
||||||
function rtti_mangledname(rt:trttitype):string;virtual;abstract;
|
function rtti_mangledname(rt:trttitype):string;virtual;abstract;
|
||||||
function OwnerHierarchyName: string; virtual; abstract;
|
function OwnerHierarchyName: string; virtual; abstract;
|
||||||
|
function fullownerhierarchyname:string;virtual;abstract;
|
||||||
function size:asizeint;virtual;abstract;
|
function size:asizeint;virtual;abstract;
|
||||||
function packedbitsize:asizeint;virtual;
|
function packedbitsize:asizeint;virtual;
|
||||||
function alignment:shortint;virtual;abstract;
|
function alignment:shortint;virtual;abstract;
|
||||||
@ -274,11 +276,21 @@ implementation
|
|||||||
result:=result+GetTypeName;
|
result:=result+GetTypeName;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function tdef.fulltypename:string;
|
||||||
|
begin
|
||||||
|
result:=fullownerhierarchyname;
|
||||||
|
if assigned(typesym) and
|
||||||
|
not(typ in [procvardef,procdef]) and
|
||||||
|
(typesym.realname[1]<>'$') then
|
||||||
|
result:=result+typesym.realname
|
||||||
|
else
|
||||||
|
result:=result+GetTypeName;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
function tdef.GetTypeName : string;
|
function tdef.GetTypeName : string;
|
||||||
begin
|
begin
|
||||||
GetTypeName:='<unknown type>'
|
GetTypeName:='<unknown type>' end;
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
function tdef.typesymbolprettyname:string;
|
function tdef.typesymbolprettyname:string;
|
||||||
|
66
tests/test/tgeneric94.pp
Normal file
66
tests/test/tgeneric94.pp
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
program tgeneric94;
|
||||||
|
|
||||||
|
{$mode objfpc}
|
||||||
|
|
||||||
|
type
|
||||||
|
generic TTest<T> = record
|
||||||
|
f: T;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TRec = record
|
||||||
|
x, y: LongInt;
|
||||||
|
end;
|
||||||
|
|
||||||
|
type
|
||||||
|
TTestTRec_Global = specialize TTest<TRec>;
|
||||||
|
const
|
||||||
|
TRecSize_Global = SizeOf(TRec);
|
||||||
|
|
||||||
|
procedure DoTest;
|
||||||
|
type
|
||||||
|
TRec = packed record
|
||||||
|
a, b: Byte;
|
||||||
|
end;
|
||||||
|
TTestTRec_DoTest = specialize TTest<TRec>;
|
||||||
|
const
|
||||||
|
TRecSize_DoTest = SizeOf(TRec);
|
||||||
|
|
||||||
|
procedure Nested(out aActual, aExpected: LongInt);
|
||||||
|
type
|
||||||
|
TRec = packed record
|
||||||
|
f1, f2: Word;
|
||||||
|
end;
|
||||||
|
TTestTRec_Nested = specialize TTest<TRec>;
|
||||||
|
const
|
||||||
|
TRecSize_Nested = SizeOf(TRec);
|
||||||
|
var
|
||||||
|
t: TTestTRec_Nested;
|
||||||
|
begin
|
||||||
|
aActual := SizeOf(t.f);
|
||||||
|
aExpected := TRecSize_Nested;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DoError(const aMessage: String);
|
||||||
|
begin
|
||||||
|
Writeln(aMessage);
|
||||||
|
ExitCode := 1;
|
||||||
|
Halt;
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
tg: TTestTRec_Global;
|
||||||
|
tt: TTestTRec_DoTest;
|
||||||
|
act, expt: LongInt;
|
||||||
|
begin
|
||||||
|
if SizeOf(tg.f) <> TRecSize_Global then
|
||||||
|
DoError('Unexpected size of global TRec');
|
||||||
|
if SizeOf(tt.f) <> TRecSize_DoTest then
|
||||||
|
DoError('Unexpected size of DoTest TRec');
|
||||||
|
Nested(act, expt);
|
||||||
|
if act <> expt then
|
||||||
|
DoError('Unexpected size of Nested TRec');
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
DoTest;
|
||||||
|
end.
|
40
tests/test/tgeneric95.pp
Normal file
40
tests/test/tgeneric95.pp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
program tgeneric95;
|
||||||
|
|
||||||
|
{$mode objfpc}
|
||||||
|
|
||||||
|
type
|
||||||
|
generic TTest<T> = record
|
||||||
|
f: T;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function Test(aArg: Integer): Integer;
|
||||||
|
type
|
||||||
|
TTest_Word = specialize TTest<Word>;
|
||||||
|
var
|
||||||
|
t: TTest_Word;
|
||||||
|
begin
|
||||||
|
Result := SizeOf(t.f);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function Test(aArg: String): Integer;
|
||||||
|
type
|
||||||
|
TTest_String = specialize TTest<String>;
|
||||||
|
var
|
||||||
|
t: TTest_String;
|
||||||
|
begin
|
||||||
|
Result := SizeOf(t.f);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DoError(const aMessage: String);
|
||||||
|
begin
|
||||||
|
Writeln(aMessage);
|
||||||
|
ExitCode := 1;
|
||||||
|
Halt;
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if Test(42) <> SizeOf(Word) then
|
||||||
|
DoError('Unexpected size of field');
|
||||||
|
if Test('Test') <> SizeOf(String) then
|
||||||
|
DoError('Unexpe size of field');
|
||||||
|
end.
|
Loading…
Reference in New Issue
Block a user