Browse Source

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 -
svenbarth 14 years ago
parent
commit
de1e6b1c3d
5 changed files with 127 additions and 36 deletions
  1. 31 11
      compiler/pdecl.pas
  2. 9 0
      compiler/pdecobj.pas
  3. 22 0
      compiler/pexpr.pas
  4. 35 24
      compiler/psub.pas
  5. 30 1
      compiler/ptype.pas

+ 31 - 11
compiler/pdecl.pas

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

+ 9 - 0
compiler/pdecobj.pas

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

+ 22 - 0
compiler/pexpr.pas

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

+ 35 - 24
compiler/psub.pas

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

+ 30 - 1
compiler/ptype.pas

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