mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-06 02:10:28 +02: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;
|
||||
generictokenbuf : tdynamicarray;
|
||||
vmtbuilder : TVMTBuilder;
|
||||
i : integer;
|
||||
s : shortstring;
|
||||
gendef : tstoreddef;
|
||||
begin
|
||||
old_block_type:=block_type;
|
||||
{ save unit container of forward declarations -
|
||||
@ -486,6 +486,7 @@ implementation
|
||||
referencing the type before it's really set it
|
||||
will give an error (PFV) }
|
||||
hdef:=generrordef;
|
||||
gendef:=nil;
|
||||
storetokenpos:=current_tokenpos;
|
||||
if isgeneric then
|
||||
begin
|
||||
@ -508,15 +509,34 @@ implementation
|
||||
Message1(sym_e_duplicate_id,genorgtypename);
|
||||
end
|
||||
else
|
||||
if assigned(sym) and (sym.typ=typesym) and
|
||||
(ttypesym(sym).typedef.typ=undefineddef) and
|
||||
not (sp_generic_para in sym.symoptions) then
|
||||
begin
|
||||
{ this is a symbol that was added by an earlier generic
|
||||
declaration, reuse it }
|
||||
newtype:=ttypesym(sym);
|
||||
newtype.typedef:=hdef;
|
||||
end;
|
||||
begin
|
||||
if assigned(sym) and (sym.typ=typesym) and
|
||||
(ttypesym(sym).typedef.typ=undefineddef) and
|
||||
not (sp_generic_para in sym.symoptions) then
|
||||
begin
|
||||
{ this is a symbol that was added by an earlier generic
|
||||
declaration, reuse it }
|
||||
newtype:=ttypesym(sym);
|
||||
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;
|
||||
{ insert a newtype if we don't reuse an existing symbol }
|
||||
if not assigned(newtype) then
|
||||
begin
|
||||
@ -527,7 +547,7 @@ implementation
|
||||
current_tokenpos:=defpos;
|
||||
current_tokenpos:=storetokenpos;
|
||||
{ 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 }
|
||||
if assigned(hdef) then
|
||||
begin
|
||||
|
@ -1143,6 +1143,11 @@ implementation
|
||||
else if assigned(genericlist) then
|
||||
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
|
||||
be added when the parent class set with tobjectdef.set_parent (PFV) }
|
||||
if (cs_generate_rtti in current_settings.localswitches) and
|
||||
@ -1183,6 +1188,10 @@ implementation
|
||||
|
||||
symtablestack.push(current_structdef.symtable);
|
||||
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 list of parent classes }
|
||||
|
@ -49,6 +49,10 @@ interface
|
||||
function get_intconst:TConstExprInt;
|
||||
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
|
||||
|
||||
uses
|
||||
@ -2826,6 +2830,24 @@ implementation
|
||||
end;
|
||||
{$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
|
||||
****************************************************************************}
|
||||
|
@ -1968,14 +1968,46 @@ implementation
|
||||
|
||||
procedure specialize_objectdefs(p:TObject;arg:pointer);
|
||||
var
|
||||
i : longint;
|
||||
hp : tdef;
|
||||
oldcurrent_filepos : tfileposinfo;
|
||||
oldsymtablestack : tsymtablestack;
|
||||
oldextendeddefs : TFPHashObjectList;
|
||||
pu : tused_unit;
|
||||
hmodule : tmodule;
|
||||
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
|
||||
if not((tsym(p).typ=typesym) and
|
||||
(ttypesym(p).typedef.typesym=tsym(p)) and
|
||||
@ -2013,28 +2045,7 @@ implementation
|
||||
symtablestack.push(hmodule.localsymtable);
|
||||
|
||||
{ procedure definitions for classes or objects }
|
||||
for i:=0 to specobj.symtable.DefList.Count-1 do
|
||||
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;
|
||||
process_abstractrecorddef(specobj);
|
||||
|
||||
{ Restore symtablestack }
|
||||
current_module.extendeddefs.free;
|
||||
|
@ -720,7 +720,16 @@ implementation
|
||||
else if assigned(genericlist) then
|
||||
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);
|
||||
{ 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);
|
||||
if m_advanced_records in current_settings.modeswitches then
|
||||
parse_record_members
|
||||
@ -829,7 +838,11 @@ implementation
|
||||
if (m_delphi in current_settings.modeswitches) then
|
||||
dospecialize:=token=_LSHARPBRACKET;
|
||||
if dospecialize then
|
||||
generate_specialization(def,false,nil)
|
||||
begin
|
||||
generate_specialization(def,false,nil);
|
||||
{ handle nested types }
|
||||
post_comp_expr_gendef(def);
|
||||
end
|
||||
else
|
||||
begin
|
||||
if assigned(current_specializedef) and (def=current_specializedef.genericdef) then
|
||||
@ -1055,8 +1068,16 @@ implementation
|
||||
{ reject declaration of generic class inside generic class }
|
||||
else if assigned(genericlist) then
|
||||
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);
|
||||
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);
|
||||
end;
|
||||
consume(_OF);
|
||||
@ -1102,8 +1123,16 @@ implementation
|
||||
{ reject declaration of generic class inside generic class }
|
||||
else if assigned(genericlist) then
|
||||
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);
|
||||
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);
|
||||
{ don't allow to add defs to the symtable - use it for type param search only }
|
||||
tparasymtable(pd.parast).readonly:=true;
|
||||
|
Loading…
Reference in New Issue
Block a user