Browse Source

* ptype.pas:
"generate_specialization" now parses the generic parameters without verifying them. The verification is done after their count is known and thus the correct generic def can be determined.

Note: It does currently only work with the first found symbol, the extended lookup needs to be implemented yet (including the unit name works though)

* pexpr.pas:
In "factor_read_id" an "identifer not found" error is generated if the undefined non-generic def is used (e.g. as a type for a variable)

Note: This check needs to be adjusted for the case "typeonly=false".

Status of generics:
Specializations can now be parsed, but declarations containing methods are still broken, because the correct def is not yet resolved (not even talking about inline specializations yet ;) )

git-svn-id: branches/svenbarth/generics@17394 -

svenbarth 14 years ago
parent
commit
b18772916b
2 changed files with 129 additions and 55 deletions
  1. 10 1
      compiler/pexpr.pas
  2. 119 54
      compiler/ptype.pas

+ 10 - 1
compiler/pexpr.pas

@@ -1381,7 +1381,16 @@ implementation
                     exit;
                   end;
                { if nothing found give error and return errorsym }
-               if assigned(srsym) then
+               if assigned(srsym) and
+                   not (
+                     { in case of an overloaded generic symbol we need to
+                       generate an error if the non-generic symbol is still
+                       undefined and we're not doing a specialization }
+                     typeonly and (srsym.typ=typesym) and
+                     (ttypesym(srsym).typedef.typ=undefineddef) and
+                     (ttypesym(srsym).gendeflist.Count>0) and
+                     not (token in [_LT, _LSHARPBRACKET])
+                   ) then
                  check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg)
                else
                  begin

+ 119 - 54
compiler/ptype.pas

@@ -148,12 +148,17 @@ implementation
         st  : TSymtable;
         srsym : tsym;
         pt2 : tnode;
+        found,
         first,
         err : boolean;
-        i   : longint;
+        i,
+        j,
+        gencount : longint;
         sym : tsym;
         genericdef : tstoreddef;
+        genericsym,
         generictype : ttypesym;
+        genericdeflist : TFPObjectList;
         generictypelist : TFPObjectList;
         oldsymtablestack   : tsymtablestack;
         oldextendeddefs    : TFPHashObjectList;
@@ -165,14 +170,21 @@ implementation
         onlyparsepara : boolean;
         specializest : tsymtable;
         item: psymtablestackitem;
+        def : tdef;
       begin
         { retrieve generic def that we are going to replace }
         genericdef:=tstoreddef(tt);
         tt:=nil;
         onlyparsepara:=false;
 
-        if not(df_generic in genericdef.defoptions) then
+        if not assigned(genericdef.typesym) or
+            (genericdef.typesym.typ<>typesym) then
+           internalerror(2011042701);
+
+        genericsym:=ttypesym(genericdef.typesym);
+        if genericsym.gendeflist.Count=0 then
           begin
+            { TODO : search for other generics with the same name }
             Message(parser_e_special_onlygenerics);
             tt:=generrordef;
             onlyparsepara:=true;
@@ -205,62 +217,109 @@ implementation
 
         if not try_to_consume(_LT) then
           consume(_LSHARPBRACKET);
-        { Parse generic parameters, for each undefineddef in the symtable of
-          the genericdef we need to have a new def }
-        err:=false;
-        first:=true;
+
         generictypelist:=TFPObjectList.create(false);
-        case genericdef.typ of
-          procdef:
-            st:=genericdef.GetSymtable(gs_para);
-          objectdef,
-          recorddef:
-            st:=genericdef.GetSymtable(gs_record);
-          arraydef:
-            st:=tarraydef(genericdef).symtable;
-          procvardef:
-            st:=genericdef.GetSymtable(gs_para);
-          else
-            internalerror(200511182);
-        end;
+        genericdeflist:=TFPObjectList.Create(false);
 
         { Parse type parameters }
         if not assigned(genericdef.typesym) then
           internalerror(200710173);
-        specializename:=genericdef.typesym.realname;
-        for i:=0 to st.SymList.Count-1 do
+        err:=false;
+        first:=true;
+        specializename:='';
+        while not (token in [_GT,_RSHARPBRACKET]) do
           begin
-            sym:=tsym(st.SymList[i]);
-            if (sp_generic_para in sym.symoptions) then
+            if not first then
+              consume(_COMMA)
+            else
+              first:=false;
+            pt2:=factor(false,true);
+            if pt2.nodetype=typen then
               begin
-                if not first then
-                  consume(_COMMA)
-                else
-                  first:=false;
-                pt2:=factor(false,true);
-                if pt2.nodetype=typen then
-                  begin
-                    if df_generic in pt2.resultdef.defoptions then
-                      Message(parser_e_no_generics_as_params);
-                    generictype:=ttypesym.create(sym.realname,pt2.resultdef);
-                    generictypelist.add(generictype);
-                    if not assigned(pt2.resultdef.typesym) then
-                      message(type_e_generics_cannot_reference_itself)
-                    else
-                      specializename:=specializename+'$'+pt2.resultdef.typesym.realname;
-                  end
+                if df_generic in pt2.resultdef.defoptions then
+                  Message(parser_e_no_generics_as_params);
+                genericdeflist.Add(pt2.resultdef);
+                if not assigned(pt2.resultdef.typesym) then
+                  message(type_e_generics_cannot_reference_itself)
                 else
-                  begin
-                    Message(type_e_type_id_expected);
-                    err:=true;
-                  end;
-                pt2.free;
+                  specializename:=specializename+'$'+pt2.resultdef.typesym.realname;
+              end
+            else
+              begin
+                Message(type_e_type_id_expected);
+                err:=true;
               end;
+            pt2.free;
+          end;
+
+        if err then
+          begin
+            try_to_consume(_RSHARPBRACKET);
+            exit;
           end;
+
+        { check whether we have a generic with the correct amount of params }
+        found:=false;
+        for i:=0 to genericsym.gendeflist.Count-1 do begin
+          def:=tdef(genericsym.gendeflist[i]);
+          { select the symtable containing the params }
+          case def.typ of
+            procdef:
+              st:=def.GetSymtable(gs_para);
+            objectdef,
+            recorddef:
+              st:=def.GetSymtable(gs_record);
+            arraydef:
+              st:=tarraydef(def).symtable;
+            procvardef:
+              st:=def.GetSymtable(gs_para);
+            else
+              internalerror(200511182);
+          end;
+
+          gencount:=0;
+          for j:=0 to st.SymList.Count-1 do
+            begin
+              if sp_generic_para in tsym(st.SymList[j]).symoptions then
+                inc(gencount);
+            end;
+
+          if gencount=genericdeflist.count then
+            begin
+              found:=true;
+              break;
+            end;
+        end;
+
+        if not found then
+          begin
+            identifier_not_found(genericdef.typename);
+            tt:=generrordef;
+            exit;
+          end;
+
+        { we've found the correct def, so use it }
+        genericdef:=tstoreddef(def);
+
+        { build the new type's name }
+        specializename:=genericdef.typesym.realname+specializename;
         uspecializename:=upper(specializename);
-        { force correct error location if too much type parameters are passed }
-        if not (token in [_RSHARPBRACKET,_GT]) then
-          consume(_RSHARPBRACKET);
+
+        { build the list containing the types for the generic params }
+        gencount:=0;
+        for i:=0 to st.SymList.Count-1 do
+          begin
+            sym:=tsym(st.SymList[i]);
+            if sp_generic_para in sym.symoptions then
+              begin
+                if gencount=genericdeflist.Count then
+                  internalerror(2011042702);
+                generictype:=ttypesym.create(sym.realname,tdef(genericdeflist[gencount]));
+                generictypelist.add(generictype);
+                inc(gencount);
+              end;
+          end;
+
 
         { Special case if we are referencing the current defined object }
         if assigned(current_structdef) and
@@ -385,13 +444,14 @@ implementation
             tundefineddef.create;
           end;
 
+        genericdeflist.free;
         generictypelist.free;
         if not try_to_consume(_GT) then
           consume(_RSHARPBRACKET);
       end;
 
 
-    procedure id_type(var def : tdef;isforwarddef,checkcurrentrecdef:boolean); forward;
+    procedure id_type(var def : tdef;isforwarddef,checkcurrentrecdef,allowgenericsyms:boolean); forward;
 
     { def is the outermost type in which other types have to be searched
 
@@ -435,7 +495,7 @@ implementation
                      structstackindex:=-1;
                      symtablestack.push(tabstractrecorddef(def).symtable);
                      t2:=generrordef;
-                     id_type(t2,isforwarddef,false);
+                     id_type(t2,isforwarddef,false,false);
                      symtablestack.pop(tabstractrecorddef(def).symtable);
                      def:=t2;
                    end;
@@ -480,7 +540,7 @@ implementation
          result:=false;
       end;
 
-    procedure id_type(var def : tdef;isforwarddef,checkcurrentrecdef:boolean);
+    procedure id_type(var def : tdef;isforwarddef,checkcurrentrecdef,allowgenericsyms:boolean);
     { reads a type definition }
     { to a appropriating tdef, s gets the name of   }
     { the type to allow name mangling          }
@@ -511,7 +571,9 @@ implementation
            table as forwarddef are not resolved directly }
          if assigned(srsym) and
             (srsym.typ=typesym) and
-            (ttypesym(srsym).typedef.typ=errordef) then
+            (ttypesym(srsym).typedef.typ=errordef) and
+            (not allowgenericsyms or
+            (ttypesym(srsym).gendeflist.Count=0)) then
           begin
             Message1(type_e_type_is_not_completly_defined,ttypesym(srsym).realname);
             def:=generrordef;
@@ -538,8 +600,11 @@ implementation
             def:=generrordef;
             exit;
           end;
-         { Give an error when referring to an errordef }
-         if (ttypesym(srsym).typedef.typ=errordef) then
+         { Give an error when referring to an errordef that does not have
+           generic overloads }
+         if (ttypesym(srsym).typedef.typ=errordef) and
+            (not allowgenericsyms or
+            (ttypesym(srsym).gendeflist.Count=0)) then
           begin
             Message(sym_e_error_in_type_def);
             def:=generrordef;
@@ -600,7 +665,7 @@ implementation
                      end
                    else
                      begin
-                       id_type(def,stoIsForwardDef in options,true);
+                       id_type(def,stoIsForwardDef in options,true,true);
                        parse_nested_types(def,stoIsForwardDef in options,nil);
                      end;
                  end;