View Issue Details

IDProjectCategoryView StatusLast Update
0015480FPCCompilerpublic2019-05-02 14:24
ReporterbefelemepesevezeAssigned ToSven Barth 
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionno change required 
Platformx86-64OSUbuntuOS Version9.10
Product Version2.5.1Product Buildr14549 
Target VersionFixed in Version 
Summary0015480: Compiler error when specializing fgl.TFPGList with a record type
Description$ cat project1.pas
program project1;

{$mode objfpc}{$H+}

uses
       fgl;

type
 TPar = record
   I: Integer;
 end;

 TSpec = specialize TFPGList<TPar>;

begin
end.

$
Steps To Reproduce$ fpc project1.pas
Free Pascal Compiler version 2.5.1 [2010/01/05] for x86_64
Copyright (c) 1993-2009 by Florian Klaempfl
Target OS: Linux for x86-64
Compiling project1.pas
Error: Operator is not overloaded
project1.pas(18) Fatal: There were 1 errors compiling module, stopping
Fatal: Compilation aborted
Error: /home/myname/lib/fpc/2.5.1/ppcx64 returned an error exitcode (normal if you did not specify a source file to be compiled)
$
Additional Information- Not tested if reproducible on other platforms/architectures.

- Discussion went here:
http://www.mail-archive.com/fpc-pascal@lists.freepascal.org/msg18933.html

- If possible, it would be nice if the compiler error message could provide a little bit more information (e.g. line number, what operator).

Tagsgenerics, getrlimit
Fixed in Revision
FPCOldBugId
FPCTarget
Attached Files
  • operator_not_overloaded_3_details.patch (696 bytes)
    Index: compiler/htypechk.pas
    ===================================================================
    --- compiler/htypechk.pas	(revision 14684)
    +++ compiler/htypechk.pas	(working copy)
    @@ -661,7 +661,7 @@
             { exit when no overloads are found }
             if cand_cnt=0 then
               begin
    -            CGMessage3(parser_e_operator_not_overloaded_3,ld.gettypename,arraytokeninfo[optoken].str,rd.gettypename);
    +            CGMessage3(parser_e_operator_not_overloaded_3,candidates.FParaNode.resultdef.typename,arraytokeninfo[optoken].str,tcallparanode(candidates.FParaNode).right.resultdef.typename);
                 candidates.free;
                 ppn.free;
                 t:=cnothingnode.create;
    
  • fpc_bug_0015480.patch (619 bytes)
    Index: compiler/htypechk.pas
    ===================================================================
    --- compiler/htypechk.pas	(revision 16197)
    +++ compiler/htypechk.pas	(working copy)
    @@ -666,7 +666,7 @@
             { exit when no overloads are found }
             if cand_cnt=0 then
               begin
    -            CGMessage3(parser_e_operator_not_overloaded_3,ld.gettypename,arraytokeninfo[optoken].str,rd.gettypename);
    +            CGMessage3(parser_e_operator_not_overloaded_3,ld.typename,arraytokeninfo[optoken].str,rd.typename);
                 candidates.free;
                 ppn.free;
                 t:=cnothingnode.create;
    
    fpc_bug_0015480.patch (619 bytes)
  • fpc_bug_0015480_gettypename_to_typename.patch (9,924 bytes)
    Index: compiler/htypechk.pas
    ===================================================================
    --- compiler/htypechk.pas	(revision 16197)
    +++ compiler/htypechk.pas	(working copy)
    @@ -502,7 +502,7 @@
             { stop when there are no operators found }
             if candidates.count=0 then
               begin
    -            CGMessage2(parser_e_operator_not_overloaded_2,ld.gettypename,arraytokeninfo[optoken].str);
    +            CGMessage2(parser_e_operator_not_overloaded_2,ld.typename,arraytokeninfo[optoken].str);
                 candidates.free;
                 ppn.free;
                 t:=cnothingnode.create;
    @@ -520,7 +520,7 @@
             { exit when no overloads are found }
             if cand_cnt=0 then
               begin
    -            CGMessage2(parser_e_operator_not_overloaded_2,ld.gettypename,arraytokeninfo[optoken].str);
    +            CGMessage2(parser_e_operator_not_overloaded_2,ld.typename,arraytokeninfo[optoken].str);
                 candidates.free;
                 ppn.free;
                 t:=cnothingnode.create;
    @@ -666,7 +666,7 @@
             { exit when no overloads are found }
             if cand_cnt=0 then
               begin
    -            CGMessage3(parser_e_operator_not_overloaded_3,ld.gettypename,arraytokeninfo[optoken].str,rd.gettypename);
    +            CGMessage3(parser_e_operator_not_overloaded_3,ld.typename,arraytokeninfo[optoken].str,rd.typename);
                 candidates.free;
                 ppn.free;
                 t:=cnothingnode.create;
    Index: compiler/ncnv.pas
    ===================================================================
    --- compiler/ncnv.pas	(revision 16197)
    +++ compiler/ncnv.pas	(working copy)
    @@ -731,11 +731,11 @@
                 ((Torddef(node.resultdef).low>Torddef(def).low) or (Torddef(node.resultdef).high<Torddef(def).high)) then
                case node.nodetype of
                  addn:
    -               cgmessage1(type_h_convert_add_operands_to_prevent_overflow,def.gettypename);
    +               cgmessage1(type_h_convert_add_operands_to_prevent_overflow,def.typename);
                  subn:
    -               cgmessage1(type_h_convert_sub_operands_to_prevent_overflow,def.gettypename);
    +               cgmessage1(type_h_convert_sub_operands_to_prevent_overflow,def.typename);
                  muln:
    -               cgmessage1(type_h_convert_mul_operands_to_prevent_overflow,def.gettypename);
    +               cgmessage1(type_h_convert_mul_operands_to_prevent_overflow,def.typename);
                end;
           end;
     
    @@ -1308,7 +1308,7 @@
                  result:=cordconstnode.create(fcc,u32inttype,false);
                end
              else
    -           CGMessage2(type_e_illegal_type_conversion,left.resultdef.GetTypeName,resultdef.GetTypeName);
    +           CGMessage2(type_e_illegal_type_conversion,left.resultdef.typename,resultdef.typename);
           end;
     
     
    @@ -1880,7 +1880,7 @@
                              if assigned(hdef) then
                                inserttypeconv_internal(left,hdef)
                              else
    -                           CGMessage2(type_e_illegal_type_conversion,left.resultdef.GetTypeName,resultdef.GetTypeName);
    +                           CGMessage2(type_e_illegal_type_conversion,left.resultdef.typename,resultdef.typename);
                            end;
     
                          { check if the result could be in a register }
    @@ -1976,7 +1976,7 @@
                                      (left.nodetype=derefn)
                                     )
                                    ) then
    -                           CGMessage2(type_e_illegal_type_conversion,left.resultdef.GetTypeName,resultdef.GetTypeName);
    +                           CGMessage2(type_e_illegal_type_conversion,left.resultdef.typename,resultdef.typename);
                            end;
                        end
                       else
    Index: compiler/nflw.pas
    ===================================================================
    --- compiler/nflw.pas	(revision 16197)
    +++ compiler/nflw.pas	(working copy)
    @@ -871,7 +871,7 @@
                             result:=cerrornode.create;
                             hloopvar.free;
                             hloopbody.free;
    -                        MessagePos1(expr.fileinfo,sym_e_no_enumerator_move,pd.returndef.GetTypeName);
    +                        MessagePos1(expr.fileinfo,sym_e_no_enumerator_move,pd.returndef.typename);
                           end
                         else
                           begin
    @@ -881,7 +881,7 @@
                                 result:=cerrornode.create;
                                 hloopvar.free;
                                 hloopbody.free;
    -                            MessagePos1(expr.fileinfo,sym_e_no_enumerator_current,pd.returndef.GetTypeName);
    +                            MessagePos1(expr.fileinfo,sym_e_no_enumerator_current,pd.returndef.typename);
                               end
                             else
                               result:=create_enumerator_for_in_loop(hloopvar, hloopbody, expr, pd, movenext, current);
    @@ -898,7 +898,7 @@
                             result:=cerrornode.create;
                             hloopvar.free;
                             hloopbody.free;
    -                        MessagePos1(expr.fileinfo,sym_e_no_enumerator,expr.resultdef.GetTypeName);
    +                        MessagePos1(expr.fileinfo,sym_e_no_enumerator,expr.resultdef.typename);
                           end;
                         end;
                       end;
    Index: compiler/ninl.pas
    ===================================================================
    --- compiler/ninl.pas	(revision 16197)
    +++ compiler/ninl.pas	(working copy)
    @@ -1958,13 +1958,13 @@
     
                   { source must be a packed array }
                   if not is_packed_array(source.left.resultdef) then
    -                CGMessagePos2(source.left.fileinfo,type_e_got_expected_packed_array,'1',source.left.resultdef.GetTypeName)
    +                CGMessagePos2(source.left.fileinfo,type_e_got_expected_packed_array,'1',source.left.resultdef.typename)
                   else
                     packedarraydef := tarraydef(source.left.resultdef);
                   { target can be any kind of array, as long as it's not packed }
                   if (target.left.resultdef.typ <> arraydef) or
                      is_packed_array(target.left.resultdef) then
    -                CGMessagePos2(target.left.fileinfo,type_e_got_expected_unpacked_array,'2',target.left.resultdef.GetTypeName)
    +                CGMessagePos2(target.left.fileinfo,type_e_got_expected_unpacked_array,'2',target.left.resultdef.typename)
                   else
                     unpackedarraydef := tarraydef(target.left.resultdef);
                 end
    @@ -1976,12 +1976,12 @@
                   { source can be any kind of array, as long as it's not packed }
                   if (source.left.resultdef.typ <> arraydef) or
                      is_packed_array(source.left.resultdef) then
    -                CGMessagePos2(source.left.fileinfo,type_e_got_expected_unpacked_array,'1',source.left.resultdef.GetTypeName)
    +                CGMessagePos2(source.left.fileinfo,type_e_got_expected_unpacked_array,'1',source.left.resultdef.typename)
                   else
                     unpackedarraydef := tarraydef(source.left.resultdef);
                   { target must be a packed array }
                   if not is_packed_array(target.left.resultdef) then
    -                CGMessagePos2(target.left.fileinfo,type_e_got_expected_packed_array,'3',target.left.resultdef.GetTypeName)
    +                CGMessagePos2(target.left.fileinfo,type_e_got_expected_packed_array,'3',target.left.resultdef.typename)
                   else
                     packedarraydef := tarraydef(target.left.resultdef);
                 end;
    Index: compiler/pdecvar.pas
    ===================================================================
    --- compiler/pdecvar.pas	(revision 16197)
    +++ compiler/pdecvar.pas	(working copy)
    @@ -731,7 +731,7 @@
                    begin
                      if compare_defs(def,p.propdef,nothingn)<te_equal then
                        begin
    -                     message2(parser_e_implements_must_have_correct_type,def.GetTypeName,p.propdef.GetTypeName);
    +                     message2(parser_e_implements_must_have_correct_type,def.typename,p.propdef.typename);
                          exit;
                        end;
                    end
    @@ -742,13 +742,13 @@
                        begin
                          if compare_defs(ImplIntf.IntfDef,def,nothingn)<te_equal then
                            begin
    -                         message2(parser_e_implements_must_have_correct_type,ImplIntf.IntfDef.GetTypeName,def.GetTypeName);
    +                         message2(parser_e_implements_must_have_correct_type,ImplIntf.IntfDef.typename,def.typename);
                              exit;
                            end;
                        end
                      else
                        begin
    -                     message2(parser_e_class_doesnt_implement_interface,p.propdef.GetTypeName,def.GetTypeName);
    +                     message2(parser_e_class_doesnt_implement_interface,p.propdef.typename,def.typename);
                          exit;
                        end;
                    end
    @@ -819,7 +819,7 @@
                        end;
                    end
                  else
    -               message1(parser_e_implements_uses_non_implemented_interface,def.GetTypeName);
    +               message1(parser_e_implements_uses_non_implemented_interface,def.typename);
              end;
     
              { remove temporary procvardefs }
    Index: compiler/ptype.pas
    ===================================================================
    --- compiler/ptype.pas	(revision 16197)
    +++ compiler/ptype.pas	(working copy)
    @@ -720,7 +720,7 @@
                            indexdef:=def;
                         end
                       else
    -                    Message1(parser_e_type_cant_be_used_in_array_index,def.GetTypeName);
    +                    Message1(parser_e_type_cant_be_used_in_array_index,def.typename);
                     end;
                   else
                     Message(sym_e_error_in_type_def);
    
  • prgram.tar.gz (653 bytes)

Relationships

has duplicate 0016641 closedJonas Maebe Operator overloading inconsistency (= vs. <>) 

Activities

Florian

2010-01-08 13:25

administrator   ~0033512

The compiler simply has not enough information about the generic because compiling something into a unit throws away a lot of information. We can add the operator not overloaded but that's all, it does not solve the fundamental problem of generics in languages using precompiled entities. But we're not alone, C++ compiler messages when making errors with templates are often also almost non-understandable.

befelemepeseveze

2010-01-08 14:21

reporter   ~0033513

I see. Thanks for the explanation. What I'm still confused about is if it is or if it is not possible to specialize TFPGList with a record type and if so, how to achieve that. I'll try to figure out this on the referenced mail list thread.

Mario Ray Mahardhika

2010-01-15 08:59

reporter   ~0033637

> But we're not alone, C++ compiler messages when making errors with templates
> are often also almost non-understandable.

Is this due to the fact that generics / templates are kept as (something like a) macro (which FPC follows)? I often had this situation when using C macros. If that so, then we need to find an alternative way to store generics (we could be better than C++, I believe).

Florian, in what phase number does the specialization occur? I mean, if I have this code:

type
  TRec = record
    x: Integer;
  end;

operator =(const a,b: TRec) Result: Boolean;
begin
  Result:=a.x=b.x;
end;

type
  TTestGen = specialize TFPGList<TRec>;

which one will the compiler resolve? the operator definition or generics specialization?

Jonas Maebe

2010-01-15 12:30

manager   ~0033641

Generics are implemented in FPC by recording the token stream. This means that everything is resolved during specialisation. It also means that some symbols used in the generic definition may actually resolve into different symbols during the specialisation, because of a different scope.

Florian

2010-01-15 13:49

administrator   ~0033644

No, this is the root of the problem: when specializing, FPC reconstructs the symtable stack as it was when the generic was defined. So when specializing, the compiler cannot see the overloaded operator.

Mario Ray Mahardhika

2010-01-16 11:40

reporter   ~0033673

So, if the operator definition appears before the generic class, the compiler can see it (will try at home)?

Aleksa Todorovic

2010-01-17 22:06

reporter   ~0033715

I've attached patch (operator_not_overloaded_3_details.patch) which, when applied, outputs:

fgl.pp(715,50) Error: Operator is not overloaded: "TPar" = "TPar"
project1.pas(17) Fatal: There were 1 errors compiling module, stopping

Note that I tested patch only on this example.

2010-01-17 22:07

 

operator_not_overloaded_3_details.patch (696 bytes)
Index: compiler/htypechk.pas
===================================================================
--- compiler/htypechk.pas	(revision 14684)
+++ compiler/htypechk.pas	(working copy)
@@ -661,7 +661,7 @@
         { exit when no overloads are found }
         if cand_cnt=0 then
           begin
-            CGMessage3(parser_e_operator_not_overloaded_3,ld.gettypename,arraytokeninfo[optoken].str,rd.gettypename);
+            CGMessage3(parser_e_operator_not_overloaded_3,candidates.FParaNode.resultdef.typename,arraytokeninfo[optoken].str,tcallparanode(candidates.FParaNode).right.resultdef.typename);
             candidates.free;
             ppn.free;
             t:=cnothingnode.create;

Mario Ray Mahardhika

2010-01-20 15:08

reporter   ~0033752

Continuing my note: Yep, it does work. Why the need to reconstruct symtable? Doesn't prepending (or appending) it with the specialized class(es) work?

Florian

2010-01-23 12:53

administrator   ~0033812

If the user code redefines a type used by the generic, this will break havok: so we've to reconstruct the symtable state.

It looks like we've to bite the bullet and support methods and operators inside records :/

About the patch: I'am not sure if this really works under all circumstances and all operator types.

Aleksa Todorovic

2010-01-24 19:38

reporter   ~0033863

I believe it does, because:

1) case on line 572 ensures only binary operators will pass on
2) candidates.FParaNode is equal to the second parameter passed to tcallcandidates.create_operator (see implementation of create_operator)
3) both calls to tcallcandidates.create_operator (lines 621 and 640) use same ppn
4) ppn is by declaration tcallparanode

2010-10-22 15:26

 

fpc_bug_0015480.patch (619 bytes)
Index: compiler/htypechk.pas
===================================================================
--- compiler/htypechk.pas	(revision 16197)
+++ compiler/htypechk.pas	(working copy)
@@ -666,7 +666,7 @@
         { exit when no overloads are found }
         if cand_cnt=0 then
           begin
-            CGMessage3(parser_e_operator_not_overloaded_3,ld.gettypename,arraytokeninfo[optoken].str,rd.gettypename);
+            CGMessage3(parser_e_operator_not_overloaded_3,ld.typename,arraytokeninfo[optoken].str,rd.typename);
             candidates.free;
             ppn.free;
             t:=cnothingnode.create;
fpc_bug_0015480.patch (619 bytes)

2010-10-22 15:44

 

fpc_bug_0015480_gettypename_to_typename.patch (9,924 bytes)
Index: compiler/htypechk.pas
===================================================================
--- compiler/htypechk.pas	(revision 16197)
+++ compiler/htypechk.pas	(working copy)
@@ -502,7 +502,7 @@
         { stop when there are no operators found }
         if candidates.count=0 then
           begin
-            CGMessage2(parser_e_operator_not_overloaded_2,ld.gettypename,arraytokeninfo[optoken].str);
+            CGMessage2(parser_e_operator_not_overloaded_2,ld.typename,arraytokeninfo[optoken].str);
             candidates.free;
             ppn.free;
             t:=cnothingnode.create;
@@ -520,7 +520,7 @@
         { exit when no overloads are found }
         if cand_cnt=0 then
           begin
-            CGMessage2(parser_e_operator_not_overloaded_2,ld.gettypename,arraytokeninfo[optoken].str);
+            CGMessage2(parser_e_operator_not_overloaded_2,ld.typename,arraytokeninfo[optoken].str);
             candidates.free;
             ppn.free;
             t:=cnothingnode.create;
@@ -666,7 +666,7 @@
         { exit when no overloads are found }
         if cand_cnt=0 then
           begin
-            CGMessage3(parser_e_operator_not_overloaded_3,ld.gettypename,arraytokeninfo[optoken].str,rd.gettypename);
+            CGMessage3(parser_e_operator_not_overloaded_3,ld.typename,arraytokeninfo[optoken].str,rd.typename);
             candidates.free;
             ppn.free;
             t:=cnothingnode.create;
Index: compiler/ncnv.pas
===================================================================
--- compiler/ncnv.pas	(revision 16197)
+++ compiler/ncnv.pas	(working copy)
@@ -731,11 +731,11 @@
             ((Torddef(node.resultdef).low>Torddef(def).low) or (Torddef(node.resultdef).high<Torddef(def).high)) then
            case node.nodetype of
              addn:
-               cgmessage1(type_h_convert_add_operands_to_prevent_overflow,def.gettypename);
+               cgmessage1(type_h_convert_add_operands_to_prevent_overflow,def.typename);
              subn:
-               cgmessage1(type_h_convert_sub_operands_to_prevent_overflow,def.gettypename);
+               cgmessage1(type_h_convert_sub_operands_to_prevent_overflow,def.typename);
              muln:
-               cgmessage1(type_h_convert_mul_operands_to_prevent_overflow,def.gettypename);
+               cgmessage1(type_h_convert_mul_operands_to_prevent_overflow,def.typename);
            end;
       end;
 
@@ -1308,7 +1308,7 @@
              result:=cordconstnode.create(fcc,u32inttype,false);
            end
          else
-           CGMessage2(type_e_illegal_type_conversion,left.resultdef.GetTypeName,resultdef.GetTypeName);
+           CGMessage2(type_e_illegal_type_conversion,left.resultdef.typename,resultdef.typename);
       end;
 
 
@@ -1880,7 +1880,7 @@
                          if assigned(hdef) then
                            inserttypeconv_internal(left,hdef)
                          else
-                           CGMessage2(type_e_illegal_type_conversion,left.resultdef.GetTypeName,resultdef.GetTypeName);
+                           CGMessage2(type_e_illegal_type_conversion,left.resultdef.typename,resultdef.typename);
                        end;
 
                      { check if the result could be in a register }
@@ -1976,7 +1976,7 @@
                                  (left.nodetype=derefn)
                                 )
                                ) then
-                           CGMessage2(type_e_illegal_type_conversion,left.resultdef.GetTypeName,resultdef.GetTypeName);
+                           CGMessage2(type_e_illegal_type_conversion,left.resultdef.typename,resultdef.typename);
                        end;
                    end
                   else
Index: compiler/nflw.pas
===================================================================
--- compiler/nflw.pas	(revision 16197)
+++ compiler/nflw.pas	(working copy)
@@ -871,7 +871,7 @@
                         result:=cerrornode.create;
                         hloopvar.free;
                         hloopbody.free;
-                        MessagePos1(expr.fileinfo,sym_e_no_enumerator_move,pd.returndef.GetTypeName);
+                        MessagePos1(expr.fileinfo,sym_e_no_enumerator_move,pd.returndef.typename);
                       end
                     else
                       begin
@@ -881,7 +881,7 @@
                             result:=cerrornode.create;
                             hloopvar.free;
                             hloopbody.free;
-                            MessagePos1(expr.fileinfo,sym_e_no_enumerator_current,pd.returndef.GetTypeName);
+                            MessagePos1(expr.fileinfo,sym_e_no_enumerator_current,pd.returndef.typename);
                           end
                         else
                           result:=create_enumerator_for_in_loop(hloopvar, hloopbody, expr, pd, movenext, current);
@@ -898,7 +898,7 @@
                         result:=cerrornode.create;
                         hloopvar.free;
                         hloopbody.free;
-                        MessagePos1(expr.fileinfo,sym_e_no_enumerator,expr.resultdef.GetTypeName);
+                        MessagePos1(expr.fileinfo,sym_e_no_enumerator,expr.resultdef.typename);
                       end;
                     end;
                   end;
Index: compiler/ninl.pas
===================================================================
--- compiler/ninl.pas	(revision 16197)
+++ compiler/ninl.pas	(working copy)
@@ -1958,13 +1958,13 @@
 
               { source must be a packed array }
               if not is_packed_array(source.left.resultdef) then
-                CGMessagePos2(source.left.fileinfo,type_e_got_expected_packed_array,'1',source.left.resultdef.GetTypeName)
+                CGMessagePos2(source.left.fileinfo,type_e_got_expected_packed_array,'1',source.left.resultdef.typename)
               else
                 packedarraydef := tarraydef(source.left.resultdef);
               { target can be any kind of array, as long as it's not packed }
               if (target.left.resultdef.typ <> arraydef) or
                  is_packed_array(target.left.resultdef) then
-                CGMessagePos2(target.left.fileinfo,type_e_got_expected_unpacked_array,'2',target.left.resultdef.GetTypeName)
+                CGMessagePos2(target.left.fileinfo,type_e_got_expected_unpacked_array,'2',target.left.resultdef.typename)
               else
                 unpackedarraydef := tarraydef(target.left.resultdef);
             end
@@ -1976,12 +1976,12 @@
               { source can be any kind of array, as long as it's not packed }
               if (source.left.resultdef.typ <> arraydef) or
                  is_packed_array(source.left.resultdef) then
-                CGMessagePos2(source.left.fileinfo,type_e_got_expected_unpacked_array,'1',source.left.resultdef.GetTypeName)
+                CGMessagePos2(source.left.fileinfo,type_e_got_expected_unpacked_array,'1',source.left.resultdef.typename)
               else
                 unpackedarraydef := tarraydef(source.left.resultdef);
               { target must be a packed array }
               if not is_packed_array(target.left.resultdef) then
-                CGMessagePos2(target.left.fileinfo,type_e_got_expected_packed_array,'3',target.left.resultdef.GetTypeName)
+                CGMessagePos2(target.left.fileinfo,type_e_got_expected_packed_array,'3',target.left.resultdef.typename)
               else
                 packedarraydef := tarraydef(target.left.resultdef);
             end;
Index: compiler/pdecvar.pas
===================================================================
--- compiler/pdecvar.pas	(revision 16197)
+++ compiler/pdecvar.pas	(working copy)
@@ -731,7 +731,7 @@
                begin
                  if compare_defs(def,p.propdef,nothingn)<te_equal then
                    begin
-                     message2(parser_e_implements_must_have_correct_type,def.GetTypeName,p.propdef.GetTypeName);
+                     message2(parser_e_implements_must_have_correct_type,def.typename,p.propdef.typename);
                      exit;
                    end;
                end
@@ -742,13 +742,13 @@
                    begin
                      if compare_defs(ImplIntf.IntfDef,def,nothingn)<te_equal then
                        begin
-                         message2(parser_e_implements_must_have_correct_type,ImplIntf.IntfDef.GetTypeName,def.GetTypeName);
+                         message2(parser_e_implements_must_have_correct_type,ImplIntf.IntfDef.typename,def.typename);
                          exit;
                        end;
                    end
                  else
                    begin
-                     message2(parser_e_class_doesnt_implement_interface,p.propdef.GetTypeName,def.GetTypeName);
+                     message2(parser_e_class_doesnt_implement_interface,p.propdef.typename,def.typename);
                      exit;
                    end;
                end
@@ -819,7 +819,7 @@
                    end;
                end
              else
-               message1(parser_e_implements_uses_non_implemented_interface,def.GetTypeName);
+               message1(parser_e_implements_uses_non_implemented_interface,def.typename);
          end;
 
          { remove temporary procvardefs }
Index: compiler/ptype.pas
===================================================================
--- compiler/ptype.pas	(revision 16197)
+++ compiler/ptype.pas	(working copy)
@@ -720,7 +720,7 @@
                        indexdef:=def;
                     end
                   else
-                    Message1(parser_e_type_cant_be_used_in_array_index,def.GetTypeName);
+                    Message1(parser_e_type_cant_be_used_in_array_index,def.typename);
                 end;
               else
                 Message(sym_e_error_in_type_def);

Aleksa Todorovic

2010-10-22 15:44

reporter   ~0041999

Attached fpc_bug_0015480.patch correctly reports type names, because it calls tdef.typename instead of tdef.gettypename to report that compiler cannot find appropriate operator overload.

Second attached patch (fpc_bug_0015480_gettypename_to_typename.patch) replaces all calls in messages reporting from tdef.gettypename to tdef.typename, because typename fallbacks to gettypename if tdef.typesym is not assigned (see tdef.typename).

2010-10-29 15:58

 

prgram.tar.gz (653 bytes)

Николай Лубягов

2010-10-29 16:22

reporter   ~0042348

Hello all!
I don't understand it patches, solve uses Record in TFPGList list or not?
How i understand, in fgl.pp not visible my overloaded operator '='?
I write simple example for test prgram.tar.gz, if i union unit1 and unit2 in one unit, it will be compile. If operator overloaded in other unit i got (not where used it):

nick@Nick-ASUS:~/fpprojects/tcolects/prgram/ErrProgram$ fpc ./program1.pas
Free Pascal Compiler version 2.5.1 [2010/10/27] for i386
Copyright (c) 1993-2010 by Florian Klaempfl
Target OS: Linux for i386
Compiling ./program1.pas
Compiling Unit2.pas
Compiling Unit1.pas
Unit1.pas(19,12) Error: Operator is not overloaded: "TTreeNodeData" = "TTreeNodeData"
Unit2.pas(24) Fatal: There were 1 errors compiling module, stopping
Fatal: Compilation aborted
Error: /usr/bin/ppc386 returned an error exitcode (normal if you did not specify a source file to be compiled)

how i must correct overload operator '='?

Florian

2010-11-01 21:24

administrator   ~0042561

Thanks for the patches, I committed them in r16287

Aleksa Todorovic

2010-11-02 22:00

reporter   ~0042670

Nikolai, attached patches do not fix this issue, they just improve error reporting.

Fixing this issue requires one of these (heavy) modifications:
1. support for methods and operators inside records
2. redesign of specialization so that it takes into account appropriate symbol tables of both unit where generic is declared and unit where it is specialized, but this raises two important issues (and probably some more):

- How should compiler handle situation where symbol is defined in both specializing unit and generic-declaration unit (Florian mentioned this in comment 33812 above)?

- During compilation of specializing unit, local symbol table of generic-declaration unit is not available, so compiler can't find locally-defined symbols (see 0015591). Another issue static and global symbol tables cannot be used in generics (units used in implementation go into static symbol table, as far as I understand).

Marco van de Voort

2011-08-02 16:28

manager   ~0050380

(Delphi qualifies all typenames in mangled names with unitname)

Michalis Kamburelis

2011-08-07 17:45

reporter   ~0050594

Last edited: 2012-04-03 07:20

It may be worth noting here that the only thing causing trouble is the TFPGList.IndexOf implementation, that uses <> for comparison. You can implement your own generic class that doesn't use <> operator, that will work with every type, including records. It can even still descend from FGL.TFPSList.

I'm using such thing in my engine now:

http://svn.code.sf.net/p/castle-engine/code/trunk/castle_game_engine/src/base/genericstructlist.pas

Feel free to use this unit in your projects, it doesn't depend on my engine units.

My TGenericStructList descends from FGL.TFPSList, that uses CompareByte, and so already works for records and other compound types. It also correctly works for a list of method callbacks ("procedure/function ... of object"), where the standard comparison operator doesn't do a sensible comparison (see http://bugs.freepascal.org/view.php?id=11868 , http://bugs.freepascal.org/view.php?id=9228 ).

I use it successfully in my engine now, that is converted from our home-made templates into FPC generics now. 71 descendants of FGL.TFPGObjectList, 9 descendants of TFPGList, 56 descendants of TGenericStructList, and everything works :) So a solution, that works in both FPC SVN and 2.4.4, and still allows you to use generics, is available.

Sven Barth

2012-06-07 10:58

manager   ~0060332

As Free Pascal now supports methods and operators in records a suitable "=" or "<>" operator for a record type can be defined in that record type and the specialization will then use that.

Using global operators (and helpers) together with generics will not be possible (as technical and semantical issues are too complicated).

Regards,
Sven

Issue History

Date Modified Username Field Change
2010-01-08 13:12 befelemepeseveze New Issue
2010-01-08 13:25 Florian Note Added: 0033512
2010-01-08 14:21 befelemepeseveze Note Added: 0033513
2010-01-15 08:59 Mario Ray Mahardhika Note Added: 0033637
2010-01-15 12:30 Jonas Maebe Note Added: 0033641
2010-01-15 13:49 Florian Note Added: 0033644
2010-01-16 11:40 Mario Ray Mahardhika Note Added: 0033673
2010-01-17 22:06 Aleksa Todorovic Note Added: 0033715
2010-01-17 22:07 Aleksa Todorovic File Added: operator_not_overloaded_3_details.patch
2010-01-20 15:08 Mario Ray Mahardhika Note Added: 0033752
2010-01-23 12:07 Jonas Maebe Tag Attached: generics
2010-01-23 12:53 Florian Note Added: 0033812
2010-01-24 19:38 Aleksa Todorovic Note Added: 0033863
2010-06-05 18:27 Jonas Maebe Relationship added has duplicate 0016641
2010-08-15 23:45 Ian Hickson Tag Attached: getrlimit
2010-10-22 15:26 Aleksa Todorovic File Added: fpc_bug_0015480.patch
2010-10-22 15:44 Aleksa Todorovic File Added: fpc_bug_0015480_gettypename_to_typename.patch
2010-10-22 15:44 Aleksa Todorovic Note Added: 0041999
2010-10-29 15:58 Николай Лубягов File Added: prgram.tar.gz
2010-10-29 16:22 Николай Лубягов Note Added: 0042348
2010-11-01 21:24 Florian Note Added: 0042561
2010-11-02 22:00 Aleksa Todorovic Note Added: 0042670
2011-08-02 16:28 Marco van de Voort Note Added: 0050380
2011-08-07 17:45 Michalis Kamburelis Note Added: 0050594
2012-04-03 07:20 Michalis Kamburelis Note Edited: 0050594
2012-06-07 10:58 Sven Barth Status new => resolved
2012-06-07 10:58 Sven Barth Resolution open => no change required
2012-06-07 10:58 Sven Barth Assigned To => Sven Barth
2012-06-07 10:58 Sven Barth Note Added: 0060332