mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-11-10 11:09:35 +01:00
Implement support for nested non-generic types inside generic types. This is mostly for records, classes and objects ("structures") as those didn't work at all, but the others (arrays, procvars) weren't done cleanly either.
pobjdec.pas (object_dec) / ptype.pas (record_dec, array_dec, procvar_dec): - enable "parse_generic" if a nested type is parsed and we're already inside a generic (this prevents code to be generated for the nested type's methods) - set the "df_specialization" flag so that the code for generating the methods (and thus resolving the forwards declarations) is called for this symbol pexpr.pas: add "post_comp_expr_gendef" which basically calls "handle_factor_typenode" and "postfixoperators" as those aren't exported from the unit themselves ptype.pas, read_named_type.expr_type: - use "post_comp_expr_gendef" to parse the use of nested types (e.g. "var t: TTest<T>.TTestSub") psub.pas, specialize_objectdefs: implement the generation of the method bodies for nested structures (resolves the forward declarations) pdecl.pas, types_dec: when we encounter a nested structure inside a specialization of a structure, we need to find the corresponding generic definition so that the generic can be correctly parsed later on. git-svn-id: branches/svenbarth/generics@18002 -
This commit is contained in:
parent
bb61abe546
commit
de1e6b1c3d
@ -360,8 +360,8 @@ implementation
|
|||||||
generictypelist : TFPObjectList;
|
generictypelist : TFPObjectList;
|
||||||
generictokenbuf : tdynamicarray;
|
generictokenbuf : tdynamicarray;
|
||||||
vmtbuilder : TVMTBuilder;
|
vmtbuilder : TVMTBuilder;
|
||||||
i : integer;
|
|
||||||
s : shortstring;
|
s : shortstring;
|
||||||
|
gendef : tstoreddef;
|
||||||
begin
|
begin
|
||||||
old_block_type:=block_type;
|
old_block_type:=block_type;
|
||||||
{ save unit container of forward declarations -
|
{ save unit container of forward declarations -
|
||||||
@ -486,6 +486,7 @@ implementation
|
|||||||
referencing the type before it's really set it
|
referencing the type before it's really set it
|
||||||
will give an error (PFV) }
|
will give an error (PFV) }
|
||||||
hdef:=generrordef;
|
hdef:=generrordef;
|
||||||
|
gendef:=nil;
|
||||||
storetokenpos:=current_tokenpos;
|
storetokenpos:=current_tokenpos;
|
||||||
if isgeneric then
|
if isgeneric then
|
||||||
begin
|
begin
|
||||||
@ -508,6 +509,7 @@ implementation
|
|||||||
Message1(sym_e_duplicate_id,genorgtypename);
|
Message1(sym_e_duplicate_id,genorgtypename);
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
begin
|
||||||
if assigned(sym) and (sym.typ=typesym) and
|
if assigned(sym) and (sym.typ=typesym) and
|
||||||
(ttypesym(sym).typedef.typ=undefineddef) and
|
(ttypesym(sym).typedef.typ=undefineddef) and
|
||||||
not (sp_generic_para in sym.symoptions) then
|
not (sp_generic_para in sym.symoptions) then
|
||||||
@ -516,6 +518,24 @@ implementation
|
|||||||
declaration, reuse it }
|
declaration, reuse it }
|
||||||
newtype:=ttypesym(sym);
|
newtype:=ttypesym(sym);
|
||||||
newtype.typedef:=hdef;
|
newtype.typedef:=hdef;
|
||||||
|
sym:=nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ check whether this is a declaration of a type inside a
|
||||||
|
specialization }
|
||||||
|
if assigned(current_structdef) and
|
||||||
|
(df_specialization in current_structdef.defoptions) then
|
||||||
|
begin
|
||||||
|
if not assigned(current_structdef.genericdef) or
|
||||||
|
not (current_structdef.genericdef.typ in [recorddef,objectdef]) then
|
||||||
|
internalerror(2011052301);
|
||||||
|
sym:=tsym(tabstractrecorddef(current_structdef.genericdef).symtable.Find(gentypename));
|
||||||
|
if not assigned(sym) or not (sym.typ=typesym) then
|
||||||
|
internalerror(2011052302);
|
||||||
|
{ use the corresponding type in the generic's symtable as
|
||||||
|
genericdef for the specialized type }
|
||||||
|
gendef:=tstoreddef(ttypesym(sym).typedef);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
{ insert a newtype if we don't reuse an existing symbol }
|
{ insert a newtype if we don't reuse an existing symbol }
|
||||||
if not assigned(newtype) then
|
if not assigned(newtype) then
|
||||||
@ -527,7 +547,7 @@ implementation
|
|||||||
current_tokenpos:=defpos;
|
current_tokenpos:=defpos;
|
||||||
current_tokenpos:=storetokenpos;
|
current_tokenpos:=storetokenpos;
|
||||||
{ read the type definition }
|
{ read the type definition }
|
||||||
read_named_type(hdef,genorgtypename,nil,generictypelist,false);
|
read_named_type(hdef,genorgtypename,gendef,generictypelist,false);
|
||||||
{ update the definition of the type }
|
{ update the definition of the type }
|
||||||
if assigned(hdef) then
|
if assigned(hdef) then
|
||||||
begin
|
begin
|
||||||
|
|||||||
@ -1143,6 +1143,11 @@ implementation
|
|||||||
else if assigned(genericlist) then
|
else if assigned(genericlist) then
|
||||||
current_genericdef:=current_structdef;
|
current_genericdef:=current_structdef;
|
||||||
|
|
||||||
|
{ nested types of specializations are specializations as well }
|
||||||
|
if assigned(old_current_structdef) and
|
||||||
|
(df_specialization in old_current_structdef.defoptions) then
|
||||||
|
include(current_structdef.defoptions,df_specialization);
|
||||||
|
|
||||||
{ set published flag in $M+ mode, it can also be inherited and will
|
{ set published flag in $M+ mode, it can also be inherited and will
|
||||||
be added when the parent class set with tobjectdef.set_parent (PFV) }
|
be added when the parent class set with tobjectdef.set_parent (PFV) }
|
||||||
if (cs_generate_rtti in current_settings.localswitches) and
|
if (cs_generate_rtti in current_settings.localswitches) and
|
||||||
@ -1183,6 +1188,10 @@ implementation
|
|||||||
|
|
||||||
symtablestack.push(current_structdef.symtable);
|
symtablestack.push(current_structdef.symtable);
|
||||||
insert_generic_parameter_types(current_structdef,genericdef,genericlist);
|
insert_generic_parameter_types(current_structdef,genericdef,genericlist);
|
||||||
|
{ when we are parsing a generic already then this is a generic as
|
||||||
|
well }
|
||||||
|
if old_parse_generic then
|
||||||
|
include(current_structdef.defoptions, df_generic);
|
||||||
parse_generic:=(df_generic in current_structdef.defoptions);
|
parse_generic:=(df_generic in current_structdef.defoptions);
|
||||||
|
|
||||||
{ parse list of parent classes }
|
{ parse list of parent classes }
|
||||||
|
|||||||
@ -49,6 +49,10 @@ interface
|
|||||||
function get_intconst:TConstExprInt;
|
function get_intconst:TConstExprInt;
|
||||||
function get_stringconst:string;
|
function get_stringconst:string;
|
||||||
|
|
||||||
|
{ Does some postprocessing for a generic type (especially when nested types
|
||||||
|
of the specialization are used) }
|
||||||
|
procedure post_comp_expr_gendef(var def: tdef);
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
@ -2826,6 +2830,24 @@ implementation
|
|||||||
end;
|
end;
|
||||||
{$maxfpuregisters default}
|
{$maxfpuregisters default}
|
||||||
|
|
||||||
|
procedure post_comp_expr_gendef(var def: tdef);
|
||||||
|
var
|
||||||
|
p1 : tnode;
|
||||||
|
again : boolean;
|
||||||
|
begin
|
||||||
|
if not assigned(def) then
|
||||||
|
internalerror(2011053001);
|
||||||
|
again:=false;
|
||||||
|
{ handle potential typecasts, etc }
|
||||||
|
p1:=handle_factor_typenode(def,false,again);
|
||||||
|
{ parse postfix operators }
|
||||||
|
if postfixoperators(p1,again,false) then
|
||||||
|
if assigned(p1) and (p1.nodetype=typen) then
|
||||||
|
def:=ttypenode(p1).typedef
|
||||||
|
else
|
||||||
|
def:=generrordef;
|
||||||
|
end;
|
||||||
|
|
||||||
{****************************************************************************
|
{****************************************************************************
|
||||||
Sub_Expr
|
Sub_Expr
|
||||||
****************************************************************************}
|
****************************************************************************}
|
||||||
|
|||||||
@ -1968,14 +1968,46 @@ implementation
|
|||||||
|
|
||||||
procedure specialize_objectdefs(p:TObject;arg:pointer);
|
procedure specialize_objectdefs(p:TObject;arg:pointer);
|
||||||
var
|
var
|
||||||
i : longint;
|
|
||||||
hp : tdef;
|
|
||||||
oldcurrent_filepos : tfileposinfo;
|
oldcurrent_filepos : tfileposinfo;
|
||||||
oldsymtablestack : tsymtablestack;
|
oldsymtablestack : tsymtablestack;
|
||||||
oldextendeddefs : TFPHashObjectList;
|
oldextendeddefs : TFPHashObjectList;
|
||||||
pu : tused_unit;
|
pu : tused_unit;
|
||||||
hmodule : tmodule;
|
hmodule : tmodule;
|
||||||
specobj : tabstractrecorddef;
|
specobj : tabstractrecorddef;
|
||||||
|
|
||||||
|
procedure process_abstractrecorddef(def:tabstractrecorddef);
|
||||||
|
var
|
||||||
|
i : longint;
|
||||||
|
hp : tdef;
|
||||||
|
begin
|
||||||
|
for i:=0 to def.symtable.DefList.Count-1 do
|
||||||
|
begin
|
||||||
|
hp:=tdef(def.symtable.DefList[i]);
|
||||||
|
if hp.typ=procdef then
|
||||||
|
begin
|
||||||
|
if assigned(tprocdef(hp).genericdef) and
|
||||||
|
(tprocdef(hp).genericdef.typ=procdef) and
|
||||||
|
assigned(tprocdef(tprocdef(hp).genericdef).generictokenbuf) then
|
||||||
|
begin
|
||||||
|
oldcurrent_filepos:=current_filepos;
|
||||||
|
current_filepos:=tprocdef(tprocdef(hp).genericdef).fileinfo;
|
||||||
|
{ use the index the module got from the current compilation process }
|
||||||
|
current_filepos.moduleindex:=hmodule.unit_index;
|
||||||
|
current_tokenpos:=current_filepos;
|
||||||
|
current_scanner.startreplaytokens(tprocdef(tprocdef(hp).genericdef).generictokenbuf);
|
||||||
|
read_proc_body(nil,tprocdef(hp));
|
||||||
|
current_filepos:=oldcurrent_filepos;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
MessagePos1(tprocdef(hp).fileinfo,sym_e_forward_not_resolved,tprocdef(hp).fullprocname(false));
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if hp.typ in [objectdef,recorddef] then
|
||||||
|
{ generate code for subtypes as well }
|
||||||
|
process_abstractrecorddef(tabstractrecorddef(hp));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
if not((tsym(p).typ=typesym) and
|
if not((tsym(p).typ=typesym) and
|
||||||
(ttypesym(p).typedef.typesym=tsym(p)) and
|
(ttypesym(p).typedef.typesym=tsym(p)) and
|
||||||
@ -2013,28 +2045,7 @@ implementation
|
|||||||
symtablestack.push(hmodule.localsymtable);
|
symtablestack.push(hmodule.localsymtable);
|
||||||
|
|
||||||
{ procedure definitions for classes or objects }
|
{ procedure definitions for classes or objects }
|
||||||
for i:=0 to specobj.symtable.DefList.Count-1 do
|
process_abstractrecorddef(specobj);
|
||||||
begin
|
|
||||||
hp:=tdef(specobj.symtable.DefList[i]);
|
|
||||||
if hp.typ=procdef then
|
|
||||||
begin
|
|
||||||
if assigned(tprocdef(hp).genericdef) and
|
|
||||||
(tprocdef(hp).genericdef.typ=procdef) and
|
|
||||||
assigned(tprocdef(tprocdef(hp).genericdef).generictokenbuf) then
|
|
||||||
begin
|
|
||||||
oldcurrent_filepos:=current_filepos;
|
|
||||||
current_filepos:=tprocdef(tprocdef(hp).genericdef).fileinfo;
|
|
||||||
{ use the index the module got from the current compilation process }
|
|
||||||
current_filepos.moduleindex:=hmodule.unit_index;
|
|
||||||
current_tokenpos:=current_filepos;
|
|
||||||
current_scanner.startreplaytokens(tprocdef(tprocdef(hp).genericdef).generictokenbuf);
|
|
||||||
read_proc_body(nil,tprocdef(hp));
|
|
||||||
current_filepos:=oldcurrent_filepos;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
MessagePos1(tprocdef(hp).fileinfo,sym_e_forward_not_resolved,tprocdef(hp).fullprocname(false));
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ Restore symtablestack }
|
{ Restore symtablestack }
|
||||||
current_module.extendeddefs.free;
|
current_module.extendeddefs.free;
|
||||||
|
|||||||
@ -720,7 +720,16 @@ implementation
|
|||||||
else if assigned(genericlist) then
|
else if assigned(genericlist) then
|
||||||
current_genericdef:=current_structdef;
|
current_genericdef:=current_structdef;
|
||||||
|
|
||||||
|
{ nested types of specializations are specializations as well }
|
||||||
|
if assigned(old_current_structdef) and
|
||||||
|
(df_specialization in old_current_structdef.defoptions) then
|
||||||
|
include(current_structdef.defoptions,df_specialization);
|
||||||
|
|
||||||
insert_generic_parameter_types(current_structdef,genericdef,genericlist);
|
insert_generic_parameter_types(current_structdef,genericdef,genericlist);
|
||||||
|
{ when we are parsing a generic already then this is a generic as
|
||||||
|
well }
|
||||||
|
if old_parse_generic then
|
||||||
|
include(current_structdef.defoptions, df_generic);
|
||||||
parse_generic:=(df_generic in current_structdef.defoptions);
|
parse_generic:=(df_generic in current_structdef.defoptions);
|
||||||
if m_advanced_records in current_settings.modeswitches then
|
if m_advanced_records in current_settings.modeswitches then
|
||||||
parse_record_members
|
parse_record_members
|
||||||
@ -829,7 +838,11 @@ implementation
|
|||||||
if (m_delphi in current_settings.modeswitches) then
|
if (m_delphi in current_settings.modeswitches) then
|
||||||
dospecialize:=token=_LSHARPBRACKET;
|
dospecialize:=token=_LSHARPBRACKET;
|
||||||
if dospecialize then
|
if dospecialize then
|
||||||
generate_specialization(def,false,nil)
|
begin
|
||||||
|
generate_specialization(def,false,nil);
|
||||||
|
{ handle nested types }
|
||||||
|
post_comp_expr_gendef(def);
|
||||||
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
if assigned(current_specializedef) and (def=current_specializedef.genericdef) then
|
if assigned(current_specializedef) and (def=current_specializedef.genericdef) then
|
||||||
@ -1055,8 +1068,16 @@ implementation
|
|||||||
{ reject declaration of generic class inside generic class }
|
{ reject declaration of generic class inside generic class }
|
||||||
else if assigned(genericlist) then
|
else if assigned(genericlist) then
|
||||||
current_genericdef:=arrdef;
|
current_genericdef:=arrdef;
|
||||||
|
{ nested types of specializations are specializations as well }
|
||||||
|
if assigned(current_structdef) and
|
||||||
|
(df_specialization in current_structdef.defoptions) then
|
||||||
|
include(arrdef.defoptions,df_specialization);
|
||||||
symtablestack.push(arrdef.symtable);
|
symtablestack.push(arrdef.symtable);
|
||||||
insert_generic_parameter_types(arrdef,genericdef,genericlist);
|
insert_generic_parameter_types(arrdef,genericdef,genericlist);
|
||||||
|
{ when we are parsing a generic already then this is a generic as
|
||||||
|
well }
|
||||||
|
if old_parse_generic then
|
||||||
|
include(arrdef.defoptions, df_generic);
|
||||||
parse_generic:=(df_generic in arrdef.defoptions);
|
parse_generic:=(df_generic in arrdef.defoptions);
|
||||||
end;
|
end;
|
||||||
consume(_OF);
|
consume(_OF);
|
||||||
@ -1102,8 +1123,16 @@ implementation
|
|||||||
{ reject declaration of generic class inside generic class }
|
{ reject declaration of generic class inside generic class }
|
||||||
else if assigned(genericlist) then
|
else if assigned(genericlist) then
|
||||||
current_genericdef:=pd;
|
current_genericdef:=pd;
|
||||||
|
{ nested types of specializations are specializations as well }
|
||||||
|
if assigned(current_structdef) and
|
||||||
|
(df_specialization in current_structdef.defoptions) then
|
||||||
|
include(pd.defoptions,df_specialization);
|
||||||
symtablestack.push(pd.parast);
|
symtablestack.push(pd.parast);
|
||||||
insert_generic_parameter_types(pd,genericdef,genericlist);
|
insert_generic_parameter_types(pd,genericdef,genericlist);
|
||||||
|
{ when we are parsing a generic already then this is a generic as
|
||||||
|
well }
|
||||||
|
if old_parse_generic then
|
||||||
|
include(pd.defoptions, df_generic);
|
||||||
parse_generic:=(df_generic in pd.defoptions);
|
parse_generic:=(df_generic in pd.defoptions);
|
||||||
{ don't allow to add defs to the symtable - use it for type param search only }
|
{ don't allow to add defs to the symtable - use it for type param search only }
|
||||||
tparasymtable(pd.parast).readonly:=true;
|
tparasymtable(pd.parast).readonly:=true;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user