Browse Source

consume_generic_type_parameter now parses the available parameters first before deciding which generic def is the correct one (this is stored in the "def" variable of the parent frame). The count of the parameters and the order is checked.

parse_proc_head itself uses the correct def (the def found by consume_generic_type_parameter in mode Delphi and the first generic def of the symbol in the other modes) which is available in the "def" variable.

Status of generics:
Non-Delphi generics now work as before and declarations of Delphi generics work as well. Inline specialisations don't work currently.

git-svn-id: branches/svenbarth/generics@17396 -
svenbarth 14 years ago
parent
commit
3ebb2522f1
1 changed files with 112 additions and 60 deletions
  1. 112 60
      compiler/pdecsub.pas

+ 112 - 60
compiler/pdecsub.pas

@@ -812,6 +812,7 @@ implementation
         old_current_genericdef,
         old_current_genericdef,
         old_current_specializedef: tstoreddef;
         old_current_specializedef: tstoreddef;
         lasttoken,lastidtoken: ttoken;
         lasttoken,lastidtoken: ttoken;
+        def : tdef;
 
 
         procedure parse_operator_name;
         procedure parse_operator_name;
          begin
          begin
@@ -910,75 +911,109 @@ implementation
 
 
         function consume_generic_type_parameter:boolean;
         function consume_generic_type_parameter:boolean;
           var
           var
-            i:integer;
-            ok:boolean;
+            i,
+            j,
+            declidx,
+            idx : integer;
+            found : boolean;
             sym:tsym;
             sym:tsym;
+            genparalistdecl : TFPHashList;
           begin
           begin
             result:=not assigned(astruct)and(m_delphi in current_settings.modeswitches);
             result:=not assigned(astruct)and(m_delphi in current_settings.modeswitches);
             if result then
             if result then
               begin
               begin
-                { a generic type parameter? }
+                { is this an overloaded typesym? }
                 srsym:=search_object_name(sp,false);
                 srsym:=search_object_name(sp,false);
                 if (srsym.typ=typesym) and
                 if (srsym.typ=typesym) and
-                   (ttypesym(srsym).typedef.typ in [objectdef,recorddef]) then
-                begin
-                  astruct:=tabstractrecorddef(ttypesym(srsym).typedef);
-                  if (df_generic in astruct.defoptions) and try_to_consume(_LT) then
-                    begin
-                      ok:=true;
-                      i:=0;
-                      repeat
-                        if ok and (token=_ID)  then
-                          begin
-                            ok:=false;
-                            while i<astruct.symtable.SymList.Count-1 do
-                              begin
-                                sym:=tsym(astruct.symtable.SymList[i]);
-                                if sp_generic_para in sym.symoptions then
-                                  begin
-                                    ok:=sym.Name=pattern;
-                                    inc(i);
-                                    break;
-                                  end;
-                                inc(i);
-                              end;
-                            if not ok then
-                              Message1(type_e_generic_declaration_does_not_match,astruct.RttiName);
-                          end;
-                        consume(_ID);
-                      until not try_to_consume(_COMMA);
-                      if ok then
-                        while i<astruct.symtable.SymList.Count-1 do
+                    (ttypesym(srsym).gendeflist.Count>0) then
+                  begin
+                    { parse all parameters first so we can check whether we have
+                      the correct generic def available }
+                    genparalistdecl:=TFPHashList.Create;
+                    if try_to_consume(_LT) then
+                      begin
+                        { start with 1, so Find can return Nil (= 0) }
+                        idx:=1;
+                        repeat
+                          if token=_ID then
+                            begin
+                              genparalistdecl.Add(pattern, Pointer(PtrInt(idx)));
+                              consume(_ID);
+                              inc(idx);
+                            end
+                          else
+                            begin
+                              message2(scan_f_syn_expected,arraytokeninfo[_ID].str,arraytokeninfo[token].str);
+                              if token<>_COMMA then
+                                consume(token);
+                            end;
+                        until not try_to_consume(_COMMA);
+                        if not try_to_consume(_GT) then
+                          consume(_RSHARPBRACKET);
+                      end
+                    else
+                      begin
+                        { no generic }
+                        srsym:=nil;
+                        exit;
+                      end;
+
+                    { now search the matching generic definition }
+                    found:=false;
+                    for i:=0 to ttypesym(srsym).gendeflist.Count-1 do
+                      begin
+                        def:=tdef(ttypesym(srsym).gendeflist[i]);
+                        { for now generic overloads are only allowed for records
+                          and objects; later they'll also be allowed for
+                          procedures and functions }
+                        if not (def.typ in [objectdef,recorddef]) then
+                          continue;
+                        st:=def.getsymtable(gs_record);
+                        if not assigned(st) then
+                          InternalError(2011042901);
+                        idx:=1;
+                        { check whether the generic parameters of the def have the
+                          same count and order as the ones just scanned, if so
+                          "found" is true }
+                        for j:=0 to st.SymList.Count-1 do
                           begin
                           begin
-                            sym:=tsym(astruct.symtable.SymList[i]);
+                            sym:=tsym(st.SymList[j]);
                             if sp_generic_para in sym.symoptions then
                             if sp_generic_para in sym.symoptions then
                               begin
                               begin
-                                Message1(type_e_generic_declaration_does_not_match,astruct.RttiName);
-                                break;
+                                if not (sym.typ=typesym) then
+                                  internalerror(2011290402);
+                                { too many parameters }
+                                if idx>genparalistdecl.Count then
+                                  break;
+                                declidx:=PtrInt(genparalistdecl.Find(sym.prettyname));
+                                { does the parameters' index match the current
+                                  index value? }
+                                if (declidx=0) or (declidx<>idx) then
+                                  break;
+                                inc(idx);
                               end;
                               end;
-                            inc(i);
+                            if (j=st.SymList.Count-1) and (idx=genparalistdecl.Count+1) then
+                              found:=true;
                           end;
                           end;
-                      consume(_GT);
-                    end
-                  else
-                  if (df_generic in astruct.defoptions) and (token=_POINT) then
-                    begin
-                      Message1(type_e_generic_declaration_does_not_match,astruct.RttiName);
-                    end
-                  else
-                    begin
-                      { not a method. routine name just accidentally match some structure name }
-                      astruct:=nil;
-                      if try_to_consume(_LT) then
-                        begin
-                          Message(type_e_type_parameters_are_not_allowed_here);
-                          repeat
-                            consume(_ID);
-                          until not try_to_consume(_COMMA);
-                          consume(_GT);
-                        end;
-                    end;
-                end;
+
+                        { the first found matching generic def wins }
+                        if found then
+                          break;
+                      end;
+
+                    genparalistdecl.free;
+
+                    if not found then
+                      begin
+                        { TODO : print a nicer typename that contains the parsed
+                                 generic types }
+                        Message1(type_e_generic_declaration_does_not_match,sp);
+                        srsym:=nil;
+                        def:=nil;
+                        exit;
+                      end;
+
+                  end;
               end;
               end;
           end;
           end;
 
 
@@ -1028,15 +1063,32 @@ implementation
            repeat
            repeat
              searchagain:=false;
              searchagain:=false;
              if not assigned(astruct) then
              if not assigned(astruct) then
-               srsym:=search_object_name(sp,true);
+               begin
+                 if not assigned(def) then
+                   begin
+                     srsym:=search_object_name(sp,true);
+                     { in non-Delphi modes we can directly use the generic def if one
+                       exists }
+                     if (srsym.typ=typesym) then
+                       if (ttypesym(srsym).gendeflist.Count>0) and
+                           not (m_delphi in current_settings.modeswitches) then
+                         def:=tdef(ttypesym(srsym).gendeflist[0])
+                       else
+                         def:=ttypesym(srsym).typedef
+                     else
+                       def:=nil;
+                   end;
+               end
+             else
+               def:=astruct;
              { consume proc name }
              { consume proc name }
              procstartfilepos:=current_tokenpos;
              procstartfilepos:=current_tokenpos;
              consume_proc_name;
              consume_proc_name;
              { qualifier is class name ? }
              { qualifier is class name ? }
              if (srsym.typ=typesym) and
              if (srsym.typ=typesym) and
-                (ttypesym(srsym).typedef.typ in [objectdef,recorddef]) then
+                (def.typ in [objectdef,recorddef]) then
               begin
               begin
-                astruct:=tabstractrecorddef(ttypesym(srsym).typedef);
+                astruct:=tabstractrecorddef(def);
                 if (token<>_POINT) then
                 if (token<>_POINT) then
                   if (potype in [potype_class_constructor,potype_class_destructor]) then
                   if (potype in [potype_class_constructor,potype_class_destructor]) then
                     sp:=lower(sp)
                     sp:=lower(sp)