mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-11 01:38:07 +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/tgeneric92.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/theap.pp svneol=native#text/plain
|
||||
tests/test/theapthread.pp svneol=native#text/plain
|
||||
|
@ -278,7 +278,7 @@ uses
|
||||
if assigned(parsedtype) then
|
||||
begin
|
||||
genericdeflist.Add(parsedtype);
|
||||
specializename:='$'+parsedtype.typename;
|
||||
specializename:='$'+parsedtype.fulltypename;
|
||||
prettyname:=parsedtype.typesym.prettyname;
|
||||
if assigned(poslist) then
|
||||
begin
|
||||
@ -315,11 +315,11 @@ uses
|
||||
message(type_e_generics_cannot_reference_itself)
|
||||
else
|
||||
begin
|
||||
specializename:=specializename+'$'+typeparam.resultdef.typename;
|
||||
if first then
|
||||
prettyname:=prettyname+typeparam.resultdef.typesym.prettyname
|
||||
else
|
||||
prettyname:=prettyname+','+typeparam.resultdef.typesym.prettyname;
|
||||
{ we use the full name of the type to uniquely identify it }
|
||||
specializename:=specializename+'$'+typeparam.resultdef.fulltypename;
|
||||
if not first then
|
||||
prettyname:=prettyname+',';
|
||||
prettyname:=prettyname+typeparam.resultdef.fullownerhierarchyname+typeparam.resultdef.typesym.prettyname;
|
||||
end;
|
||||
end
|
||||
else
|
||||
|
@ -66,6 +66,8 @@ interface
|
||||
{ tstoreddef }
|
||||
|
||||
tstoreddef = class(tdef)
|
||||
private
|
||||
_fullownerhierarchyname : pshortstring;
|
||||
protected
|
||||
typesymderef : tderef;
|
||||
procedure fillgenericparas(symtable:tsymtable);
|
||||
@ -100,6 +102,7 @@ interface
|
||||
function needs_inittable : boolean;override;
|
||||
function rtti_mangledname(rt:trttitype):string;override;
|
||||
function OwnerHierarchyName: string; override;
|
||||
function fullownerhierarchyname:string;override;
|
||||
function needs_separate_initrtti:boolean;override;
|
||||
function in_currentunit: boolean;
|
||||
{ regvars }
|
||||
@ -1532,6 +1535,7 @@ implementation
|
||||
end;
|
||||
genericparas.free;
|
||||
genconstraintdata.free;
|
||||
stringdispose(_fullownerhierarchyname);
|
||||
inherited destroy;
|
||||
end;
|
||||
|
||||
@ -1621,6 +1625,36 @@ implementation
|
||||
until tmp=nil;
|
||||
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;
|
||||
var
|
||||
|
@ -68,12 +68,14 @@ interface
|
||||
procedure deref;virtual;abstract;
|
||||
procedure derefimpl;virtual;abstract;
|
||||
function typename:string;
|
||||
function fulltypename:string;
|
||||
function GetTypeName:string;virtual;
|
||||
function typesymbolprettyname:string;virtual;
|
||||
function mangledparaname:string;
|
||||
function getmangledparaname:TSymStr;virtual;
|
||||
function rtti_mangledname(rt:trttitype):string;virtual;abstract;
|
||||
function OwnerHierarchyName: string; virtual; abstract;
|
||||
function fullownerhierarchyname:string;virtual;abstract;
|
||||
function size:asizeint;virtual;abstract;
|
||||
function packedbitsize:asizeint;virtual;
|
||||
function alignment:shortint;virtual;abstract;
|
||||
@ -274,11 +276,21 @@ implementation
|
||||
result:=result+GetTypeName;
|
||||
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;
|
||||
begin
|
||||
GetTypeName:='<unknown type>'
|
||||
end;
|
||||
GetTypeName:='<unknown type>' end;
|
||||
|
||||
|
||||
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