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:
svenbarth 2011-07-16 14:12:25 +00:00
parent bb61abe546
commit de1e6b1c3d
5 changed files with 127 additions and 36 deletions

View File

@ -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

View File

@ -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 }

View File

@ -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
****************************************************************************}

View File

@ -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;

View File

@ -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;