mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-23 22:52:13 +02:00
+ support for generics on the JVM target:
o don't try to create .class files for generic types o still generate all JVM-specific wrappers for generic types even though they won't be written out, because when specializing all the defid's have to match exactly o add synthetic routine implementations after generating the specializations, so that the synthetic routines for those specializations are also generated (we don't specialize generic versions of the synthetic generic routines because it's not easy or even always possible to create valid generic versions of synthetic routines) o Note: these are Pascal-style generics, not Java-style generics. The generic types nor their specializations are usable from Java code (specializations may become usable in the future) git-svn-id: branches/jvmbackend@19047 -
This commit is contained in:
parent
fdab7122dd
commit
125c0cf225
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -9821,6 +9821,7 @@ tests/test/jvm/tval5.pp svneol=native#text/plain
|
|||||||
tests/test/jvm/tvalc.pp svneol=native#text/plain
|
tests/test/jvm/tvalc.pp svneol=native#text/plain
|
||||||
tests/test/jvm/tvarpara.pp svneol=native#text/plain
|
tests/test/jvm/tvarpara.pp svneol=native#text/plain
|
||||||
tests/test/jvm/tvirtclmeth.pp svneol=native#text/plain
|
tests/test/jvm/tvirtclmeth.pp svneol=native#text/plain
|
||||||
|
tests/test/jvm/tw20212.pp svneol=native#text/plain
|
||||||
tests/test/jvm/twith.pp svneol=native#text/plain
|
tests/test/jvm/twith.pp svneol=native#text/plain
|
||||||
tests/test/jvm/uenum.pp svneol=native#text/plain
|
tests/test/jvm/uenum.pp svneol=native#text/plain
|
||||||
tests/test/jvm/unsupported.pp svneol=native#text/plain
|
tests/test/jvm/unsupported.pp svneol=native#text/plain
|
||||||
|
@ -624,10 +624,11 @@ implementation
|
|||||||
{ in case of nested class: relation to parent class }
|
{ in case of nested class: relation to parent class }
|
||||||
if obj.owner.symtabletype in [objectsymtable,recordsymtable] then
|
if obj.owner.symtabletype in [objectsymtable,recordsymtable] then
|
||||||
AsmWriteln(InnerStructDef(obj));
|
AsmWriteln(InnerStructDef(obj));
|
||||||
{ all all nested classes }
|
{ add all nested classes }
|
||||||
for i:=0 to obj.symtable.deflist.count-1 do
|
for i:=0 to obj.symtable.deflist.count-1 do
|
||||||
if is_java_class_or_interface(tdef(obj.symtable.deflist[i])) or
|
if (is_java_class_or_interface(tdef(obj.symtable.deflist[i])) or
|
||||||
(tdef(obj.symtable.deflist[i]).typ=recorddef) then
|
(tdef(obj.symtable.deflist[i]).typ=recorddef)) and
|
||||||
|
not(df_generic in tdef(obj.symtable.deflist[i]).defoptions) then
|
||||||
AsmWriteln(InnerStructDef(tabstractrecorddef(obj.symtable.deflist[i])));
|
AsmWriteln(InnerStructDef(tabstractrecorddef(obj.symtable.deflist[i])));
|
||||||
end;
|
end;
|
||||||
AsmLn;
|
AsmLn;
|
||||||
@ -966,6 +967,7 @@ implementation
|
|||||||
procsym:
|
procsym:
|
||||||
begin
|
begin
|
||||||
for j:=0 to tprocsym(sym).procdeflist.count-1 do
|
for j:=0 to tprocsym(sym).procdeflist.count-1 do
|
||||||
|
if not(df_generic in tprocdef(tprocsym(sym).procdeflist[j]).defoptions) then
|
||||||
WriteSymtableVarSyms(tprocdef(tprocsym(sym).procdeflist[j]).localst);
|
WriteSymtableVarSyms(tprocdef(tprocsym(sym).procdeflist[j]).localst);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -989,8 +991,9 @@ implementation
|
|||||||
{ methods are also in the static/globalsymtable of the unit
|
{ methods are also in the static/globalsymtable of the unit
|
||||||
-> make sure they are only written for the objectdefs that
|
-> make sure they are only written for the objectdefs that
|
||||||
own them }
|
own them }
|
||||||
if not(st.symtabletype in [staticsymtable,globalsymtable]) or
|
if (not(st.symtabletype in [staticsymtable,globalsymtable]) or
|
||||||
(def.owner=st) then
|
(def.owner=st)) and
|
||||||
|
not(df_generic in def.defoptions) then
|
||||||
begin
|
begin
|
||||||
WriteProcDef(tprocdef(def));
|
WriteProcDef(tprocdef(def));
|
||||||
if assigned(tprocdef(def).localst) then
|
if assigned(tprocdef(def).localst) then
|
||||||
@ -1014,6 +1017,8 @@ implementation
|
|||||||
for i:=0 to st.DefList.Count-1 do
|
for i:=0 to st.DefList.Count-1 do
|
||||||
begin
|
begin
|
||||||
def:=tdef(st.DefList[i]);
|
def:=tdef(st.DefList[i]);
|
||||||
|
if df_generic in def.defoptions then
|
||||||
|
continue;
|
||||||
case def.typ of
|
case def.typ of
|
||||||
objectdef:
|
objectdef:
|
||||||
if not(oo_is_external in tobjectdef(def).objectoptions) then
|
if not(oo_is_external in tobjectdef(def).objectoptions) then
|
||||||
|
@ -139,6 +139,8 @@ implementation
|
|||||||
topowner:=topowner.owner.defowner;
|
topowner:=topowner.owner.defowner;
|
||||||
{ create procdef }
|
{ create procdef }
|
||||||
pd:=tprocdef.create(topowner.owner.symtablelevel+1);
|
pd:=tprocdef.create(topowner.owner.symtablelevel+1);
|
||||||
|
if df_generic in obj.defoptions then
|
||||||
|
include(pd.defoptions,df_generic);
|
||||||
{ method of this objectdef }
|
{ method of this objectdef }
|
||||||
pd.struct:=obj;
|
pd.struct:=obj;
|
||||||
{ associated procsym }
|
{ associated procsym }
|
||||||
@ -474,6 +476,8 @@ implementation
|
|||||||
pvclass:=tobjectdef.create(odt_javaclass,'$'+current_module.realmodulename^+'$'+name+'$InternProcvar$'+tostr(def.defid),java_procvarbase);
|
pvclass:=tobjectdef.create(odt_javaclass,'$'+current_module.realmodulename^+'$'+name+'$InternProcvar$'+tostr(def.defid),java_procvarbase);
|
||||||
tprocvardef(def).classdef:=pvclass;
|
tprocvardef(def).classdef:=pvclass;
|
||||||
include(pvclass.objectoptions,oo_is_sealed);
|
include(pvclass.objectoptions,oo_is_sealed);
|
||||||
|
if df_generic in def.defoptions then
|
||||||
|
include(pvclass.defoptions,df_generic);
|
||||||
{ associate typesym }
|
{ associate typesym }
|
||||||
pvclass.symtable.insert(ttypesym.create('__FPC_TProcVarClassAlias',pvclass));
|
pvclass.symtable.insert(ttypesym.create('__FPC_TProcVarClassAlias',pvclass));
|
||||||
{ set external name to match procvar type name }
|
{ set external name to match procvar type name }
|
||||||
@ -825,6 +829,8 @@ implementation
|
|||||||
|
|
||||||
{ create procdef }
|
{ create procdef }
|
||||||
pd:=tprocdef.create(normal_function_level);
|
pd:=tprocdef.create(normal_function_level);
|
||||||
|
if df_generic in obj.defoptions then
|
||||||
|
include(pd.defoptions,df_generic);
|
||||||
|
|
||||||
{ construct procsym name (unique for this access; reusing the same
|
{ construct procsym name (unique for this access; reusing the same
|
||||||
helper for multiple accesses to the same field is hard because the
|
helper for multiple accesses to the same field is hard because the
|
||||||
|
@ -936,15 +936,16 @@ implementation
|
|||||||
init_procinfo.parse_body;
|
init_procinfo.parse_body;
|
||||||
{ save file pos for debuginfo }
|
{ save file pos for debuginfo }
|
||||||
current_module.mainfilepos:=init_procinfo.entrypos;
|
current_module.mainfilepos:=init_procinfo.entrypos;
|
||||||
{ add implementations for synthetic method declarations added by
|
|
||||||
the compiler }
|
|
||||||
add_synthetic_method_implementations(current_module.globalsymtable);
|
|
||||||
add_synthetic_method_implementations(current_module.localsymtable);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ Generate specializations of objectdefs methods }
|
{ Generate specializations of objectdefs methods }
|
||||||
generate_specialization_procs;
|
generate_specialization_procs;
|
||||||
|
|
||||||
|
{ add implementations for synthetic method declarations added by
|
||||||
|
the compiler }
|
||||||
|
add_synthetic_method_implementations(current_module.globalsymtable);
|
||||||
|
add_synthetic_method_implementations(current_module.localsymtable);
|
||||||
|
|
||||||
{ if the unit contains ansi/widestrings, initialization and
|
{ if the unit contains ansi/widestrings, initialization and
|
||||||
finalization code must be forced }
|
finalization code must be forced }
|
||||||
force_init_final:=tglobalsymtable(current_module.globalsymtable).needs_init_final or
|
force_init_final:=tglobalsymtable(current_module.globalsymtable).needs_init_final or
|
||||||
@ -1874,11 +1875,13 @@ implementation
|
|||||||
{ save file pos for debuginfo }
|
{ save file pos for debuginfo }
|
||||||
current_module.mainfilepos:=main_procinfo.entrypos;
|
current_module.mainfilepos:=main_procinfo.entrypos;
|
||||||
|
|
||||||
add_synthetic_method_implementations(current_module.localsymtable);
|
|
||||||
|
|
||||||
{ Generate specializations of objectdefs methods }
|
{ Generate specializations of objectdefs methods }
|
||||||
generate_specialization_procs;
|
generate_specialization_procs;
|
||||||
|
|
||||||
|
{ add implementations for synthetic method declarations added by
|
||||||
|
the compiler }
|
||||||
|
add_synthetic_method_implementations(current_module.localsymtable);
|
||||||
|
|
||||||
{ should we force unit initialization? }
|
{ should we force unit initialization? }
|
||||||
force_init_final:=tstaticsymtable(current_module.localsymtable).needs_init_final;
|
force_init_final:=tstaticsymtable(current_module.localsymtable).needs_init_final;
|
||||||
if force_init_final or cnodeutils.force_init then
|
if force_init_final or cnodeutils.force_init then
|
||||||
|
@ -2066,7 +2066,7 @@ implementation
|
|||||||
{ Setup symtablestack a definition time }
|
{ Setup symtablestack a definition time }
|
||||||
specobj:=tabstractrecorddef(ttypesym(p).typedef);
|
specobj:=tabstractrecorddef(ttypesym(p).typedef);
|
||||||
|
|
||||||
if not (is_class_or_object(specobj) or is_record(specobj)) then
|
if not (is_class_or_object(specobj) or is_record(specobj) or is_javaclass(specobj)) then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
oldsymtablestack:=symtablestack;
|
oldsymtablestack:=symtablestack;
|
||||||
@ -2110,7 +2110,8 @@ implementation
|
|||||||
read_proc_body(nil,tprocdef(hp));
|
read_proc_body(nil,tprocdef(hp));
|
||||||
current_filepos:=oldcurrent_filepos;
|
current_filepos:=oldcurrent_filepos;
|
||||||
end
|
end
|
||||||
else
|
{ synthetic routines will be implemented afterwards }
|
||||||
|
else if tprocdef(hp).synthetickind=tsk_none then
|
||||||
MessagePos1(tprocdef(hp).fileinfo,sym_e_forward_not_resolved,tprocdef(hp).fullprocname(false));
|
MessagePos1(tprocdef(hp).fileinfo,sym_e_forward_not_resolved,tprocdef(hp).fullprocname(false));
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
@ -699,8 +699,10 @@ implementation
|
|||||||
if jvmimplicitpointertype(procvar.returndef) then
|
if jvmimplicitpointertype(procvar.returndef) then
|
||||||
str:=str+'type __FPC_returnptrtype = ^'+procvar.returndef.typename+';';
|
str:=str+'type __FPC_returnptrtype = ^'+procvar.returndef.typename+';';
|
||||||
str:=str+'begin ';
|
str:=str+'begin ';
|
||||||
{ result handling }
|
{ result handling (skip for generic definitions, we'll generate a new
|
||||||
if not is_void(procvar.returndef) then
|
version for the specialized definition) ) }
|
||||||
|
if not is_void(procvar.returndef) and
|
||||||
|
(procvar.returndef.typ<>undefineddef) then
|
||||||
begin
|
begin
|
||||||
str:=str+'invoke:=';
|
str:=str+'invoke:=';
|
||||||
if procvar.returndef.typ in [orddef,floatdef] then
|
if procvar.returndef.typ in [orddef,floatdef] then
|
||||||
@ -915,6 +917,9 @@ implementation
|
|||||||
stname: string;
|
stname: string;
|
||||||
i: longint;
|
i: longint;
|
||||||
begin
|
begin
|
||||||
|
{ add generic flag if required }
|
||||||
|
if df_generic in newstruct.defoptions then
|
||||||
|
include(pd.defoptions,df_generic);
|
||||||
{ associate the procdef with a procsym in the owner }
|
{ associate the procdef with a procsym in the owner }
|
||||||
if not(pd.proctypeoption in [potype_class_constructor,potype_class_destructor]) then
|
if not(pd.proctypeoption in [potype_class_constructor,potype_class_destructor]) then
|
||||||
stname:=upper(realname)
|
stname:=upper(realname)
|
||||||
|
@ -3211,6 +3211,11 @@ implementation
|
|||||||
else
|
else
|
||||||
internalerror(2011032601);
|
internalerror(2011032601);
|
||||||
|
|
||||||
|
{ in case of specializations, add some extras to prevent name conflicts
|
||||||
|
with nested classes }
|
||||||
|
if df_specialization in defoptions then
|
||||||
|
result:='$'+result+'$specialization$';
|
||||||
|
|
||||||
st:=owner;
|
st:=owner;
|
||||||
while assigned(st) and
|
while assigned(st) and
|
||||||
(st.symtabletype in [objectsymtable,recordsymtable,localsymtable]) do
|
(st.symtabletype in [objectsymtable,recordsymtable,localsymtable]) do
|
||||||
@ -3758,6 +3763,10 @@ implementation
|
|||||||
begin
|
begin
|
||||||
// ignore, reuse original constym. Should also be duplicated
|
// ignore, reuse original constym. Should also be duplicated
|
||||||
// be safe though
|
// be safe though
|
||||||
|
end;
|
||||||
|
symconst.typesym:
|
||||||
|
begin
|
||||||
|
// reuse original, part of generic declaration
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
internalerror(201160604);
|
internalerror(201160604);
|
||||||
|
@ -208,4 +208,12 @@ ppcjvm -O2 -g -B tstring9
|
|||||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||||
java -Dfile.encoding=UTF-8 -cp ..\..\..\rtl\units\jvm-java;. tstring9
|
java -Dfile.encoding=UTF-8 -cp ..\..\..\rtl\units\jvm-java;. tstring9
|
||||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||||
|
ppcjvm -O2 -g -B tstr
|
||||||
|
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||||
|
java -Dfile.encoding=UTF-8 -cp ..\..\..\rtl\units\jvm-java;. tstr
|
||||||
|
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||||
|
ppcjvm -O2 -g -B tw20212
|
||||||
|
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||||
|
java -Dfile.encoding=UTF-8 -cp ..\..\..\rtl\units\jvm-java;. tw20212
|
||||||
|
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||||
|
|
||||||
|
@ -116,3 +116,5 @@ $PPC -O2 -g -B tstring9
|
|||||||
java -Dfile.encoding=UTF-8 -cp ../../../rtl/units/jvm-java:. tstring9
|
java -Dfile.encoding=UTF-8 -cp ../../../rtl/units/jvm-java:. tstring9
|
||||||
$PPC -O2 -g -B tstr
|
$PPC -O2 -g -B tstr
|
||||||
java -Dfile.encoding=UTF-8 -cp ../../../rtl/units/jvm-java:. tstr
|
java -Dfile.encoding=UTF-8 -cp ../../../rtl/units/jvm-java:. tstr
|
||||||
|
$PPC -O2 -g -B tw20212
|
||||||
|
java -Dfile.encoding=UTF-8 -cp ../../../rtl/units/jvm-java:. tw20212
|
||||||
|
64
tests/test/jvm/tw20212.pp
Normal file
64
tests/test/jvm/tw20212.pp
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
program tw20212;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
{$ifdef cpujvm}
|
||||||
|
uses
|
||||||
|
jdk15;
|
||||||
|
|
||||||
|
{$macro on}
|
||||||
|
{$define writeln:=JLSystem.fout.println}
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
|
||||||
|
type
|
||||||
|
generic TLinkedList<T> = class
|
||||||
|
private
|
||||||
|
FData: T;
|
||||||
|
FNext: TLinkedList;
|
||||||
|
public
|
||||||
|
property Data: T read FData write FData;
|
||||||
|
property Next: TLinkedList read FNext write FNext;
|
||||||
|
constructor Create(const AData: T);
|
||||||
|
procedure Append(const AData: T);
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TLinkedList.Create(const AData: T);
|
||||||
|
begin
|
||||||
|
FData := AData;
|
||||||
|
FNext := nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TLinkedList.Append(const AData: T);
|
||||||
|
var
|
||||||
|
tmp: TLinkedList;
|
||||||
|
begin
|
||||||
|
tmp:=FNext;
|
||||||
|
while Assigned(tmp) and Assigned(tmp.Next) do
|
||||||
|
tmp := tmp.Next;
|
||||||
|
if Assigned(tmp) then
|
||||||
|
tmp.Next := TLinkedList.Create(AData)
|
||||||
|
else
|
||||||
|
FNext := TLinkedList.Create(AData);
|
||||||
|
end;
|
||||||
|
|
||||||
|
type
|
||||||
|
TIntegerLinkedList = specialize TLinkedList<Integer>;
|
||||||
|
var
|
||||||
|
L, it: TIntegerLinkedList;
|
||||||
|
begin
|
||||||
|
L := TIntegerLinkedList.Create(1);
|
||||||
|
L.Append(1);
|
||||||
|
L.Append(2);
|
||||||
|
L.Append(3);
|
||||||
|
L.Append(5);
|
||||||
|
L.Append(8);
|
||||||
|
L.Append(11);
|
||||||
|
it:=l;
|
||||||
|
while assigned(it) do
|
||||||
|
begin
|
||||||
|
writeln(it.data);
|
||||||
|
it:=it.next;
|
||||||
|
end;
|
||||||
|
end.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user