Browse Source

* give an error when trying to call an object instance method via a type node
(mantis #34821)

git-svn-id: trunk@40785 -

Jonas Maebe 6 years ago
parent
commit
b2b34338e5
6 changed files with 469 additions and 380 deletions
  1. 1 0
      .gitattributes
  2. 12 0
      compiler/msg/errore.msg
  3. 3 2
      compiler/msgidx.inc
  4. 382 372
      compiler/msgtxt.inc
  5. 42 6
      compiler/pexpr.pas
  6. 29 0
      tests/webtbf/tw34821.pp

+ 1 - 0
.gitattributes

@@ -14760,6 +14760,7 @@ tests/webtbf/tw34691.pp svneol=native#text/pascal
 tests/webtbf/tw3473.pp svneol=native#text/plain
 tests/webtbf/tw3473.pp svneol=native#text/plain
 tests/webtbf/tw3480.pp svneol=native#text/plain
 tests/webtbf/tw3480.pp svneol=native#text/plain
 tests/webtbf/tw3480a.pp svneol=native#text/plain
 tests/webtbf/tw3480a.pp svneol=native#text/plain
+tests/webtbf/tw34821.pp svneol=native#text/plain
 tests/webtbf/tw3488.pp svneol=native#text/plain
 tests/webtbf/tw3488.pp svneol=native#text/plain
 tests/webtbf/tw3495.pp svneol=native#text/plain
 tests/webtbf/tw3495.pp svneol=native#text/plain
 tests/webtbf/tw3502.pp svneol=native#text/plain
 tests/webtbf/tw3502.pp svneol=native#text/plain

+ 12 - 0
compiler/msg/errore.msg

@@ -1582,6 +1582,18 @@ parser_w_operator_overloaded_hidden_3=03347_W_Operator overload hidden by intern
 % (in case of dynamic arrays that is the modeswitch \var{ArrayOperators}).
 % (in case of dynamic arrays that is the modeswitch \var{ArrayOperators}).
 parser_e_threadvar_must_be_class=03348_E_Thread variables inside classes or records must be class variables
 parser_e_threadvar_must_be_class=03348_E_Thread variables inside classes or records must be class variables
 % A \var{threadvar} section inside a class or record was started without it being prefixed by \var{class}.
 % A \var{threadvar} section inside a class or record was started without it being prefixed by \var{class}.
+parser_e_only_static_members_via_object_type=03349_E_Only static methods and static variables can be referenced through an object type
+% This error occurs in a situation like the following:
+% \begin{verbatim}
+% Type
+%    TObj = object
+%      procedure test;
+%    end;
+%
+% begin
+%   TObj.test;
+% \end{verbatim}
+% \var{test} is not a static method and hence cannot be called through a type, but only using an instance.
 %
 %
 %
 %
 % \end{description}
 % \end{description}

+ 3 - 2
compiler/msgidx.inc

@@ -459,6 +459,7 @@ const
   parser_e_invalid_internal_function_index=03346;
   parser_e_invalid_internal_function_index=03346;
   parser_w_operator_overloaded_hidden_3=03347;
   parser_w_operator_overloaded_hidden_3=03347;
   parser_e_threadvar_must_be_class=03348;
   parser_e_threadvar_must_be_class=03348;
+  parser_e_only_static_members_via_object_type=03349;
   type_e_mismatch=04000;
   type_e_mismatch=04000;
   type_e_incompatible_types=04001;
   type_e_incompatible_types=04001;
   type_e_not_equal_types=04002;
   type_e_not_equal_types=04002;
@@ -1106,9 +1107,9 @@ const
   option_info=11024;
   option_info=11024;
   option_help_pages=11025;
   option_help_pages=11025;
 
 
-  MsgTxtSize = 82706;
+  MsgTxtSize = 82796;
 
 
   MsgIdxMax : array[1..20] of longint=(
   MsgIdxMax : array[1..20] of longint=(
-    28,106,349,126,99,59,142,34,221,67,
+    28,106,350,126,99,59,142,34,221,67,
     62,20,30,1,1,1,1,1,1,1
     62,20,30,1,1,1,1,1,1,1
   );
   );

File diff suppressed because it is too large
+ 382 - 372
compiler/msgtxt.inc


+ 42 - 6
compiler/pexpr.pas

@@ -1281,6 +1281,7 @@ implementation
       var
       var
         isclassref:boolean;
         isclassref:boolean;
         isrecordtype:boolean;
         isrecordtype:boolean;
+        isobjecttype:boolean;
       begin
       begin
          if sym=nil then
          if sym=nil then
            begin
            begin
@@ -1301,11 +1302,13 @@ implementation
                    do_typecheckpass(p1);
                    do_typecheckpass(p1);
                  isclassref:=(p1.resultdef.typ=classrefdef);
                  isclassref:=(p1.resultdef.typ=classrefdef);
                  isrecordtype:=(p1.nodetype=typen) and (p1.resultdef.typ=recorddef);
                  isrecordtype:=(p1.nodetype=typen) and (p1.resultdef.typ=recorddef);
+                 isobjecttype:=(p1.nodetype=typen) and is_object(p1.resultdef);
                end
                end
               else
               else
                 begin
                 begin
                   isclassref:=false;
                   isclassref:=false;
                   isrecordtype:=false;
                   isrecordtype:=false;
+                  isobjecttype:=false;
                 end;
                 end;
 
 
               if assigned(spezcontext) and not (sym.typ=procsym) then
               if assigned(spezcontext) and not (sym.typ=procsym) then
@@ -1325,16 +1328,47 @@ implementation
                       if (
                       if (
                             isclassref or
                             isclassref or
                             (
                             (
-                              isrecordtype and
+                              (isobjecttype or
+                               isrecordtype) and
                               not (cnf_inherited in callflags)
                               not (cnf_inherited in callflags)
                             )
                             )
                           ) and
                           ) and
                          (p1.nodetype=calln) and
                          (p1.nodetype=calln) and
                          assigned(tcallnode(p1).procdefinition) then
                          assigned(tcallnode(p1).procdefinition) then
                         begin
                         begin
-                          if not(po_classmethod in tcallnode(p1).procdefinition.procoptions) and
-                             not(tcallnode(p1).procdefinition.proctypeoption=potype_constructor) then
-                            Message(parser_e_only_class_members_via_class_ref);
+                          if not isobjecttype then
+                            begin
+                              if not(po_classmethod in tcallnode(p1).procdefinition.procoptions) and
+                                 not(tcallnode(p1).procdefinition.proctypeoption=potype_constructor) then
+                                Message(parser_e_only_class_members_via_class_ref);
+                            end
+                          else
+                            begin
+                              { with objects, you can also do this:
+                                  type
+                                    tparent = object
+                                      procedure test;
+                                    end;
+
+                                    tchild = object(tchild)
+                                      procedure test;
+                                    end;
+
+                                    procedure tparent.test;
+                                      begin
+                                      end;
+
+                                    procedure tchild.test;
+                                      begin
+                                        tparent.test;
+                                      end;
+                              }
+                              if (tcallnode(p1).procdefinition.proctypeoption<>potype_constructor) and
+                                 not(po_staticmethod in tcallnode(p1).procdefinition.procoptions) and
+                                 (not assigned(current_structdef) or
+                                  not def_is_related(current_structdef,structh)) then
+                                Message(parser_e_only_static_members_via_object_type);
+                            end;
                           { in Java, constructors are not automatically inherited
                           { in Java, constructors are not automatically inherited
                             -> calling a constructor from a parent type will create
                             -> calling a constructor from a parent type will create
                                an instance of that parent type! }
                                an instance of that parent type! }
@@ -1352,7 +1386,7 @@ implementation
                               assigned(tcallnode(p1).methodpointer) and
                               assigned(tcallnode(p1).methodpointer) and
                               (tcallnode(p1).methodpointer.nodetype=loadvmtaddrn) then
                               (tcallnode(p1).methodpointer.nodetype=loadvmtaddrn) then
                             Message1(type_w_instance_abstract_class,structh.RttiName);
                             Message1(type_w_instance_abstract_class,structh.RttiName);
-                        end;
+                        end
                    end;
                    end;
                  fieldvarsym:
                  fieldvarsym:
                    begin
                    begin
@@ -1366,7 +1400,9 @@ implementation
                                 (current_procinfo.procdef.struct=structh))) then
                                 (current_procinfo.procdef.struct=structh))) then
                               Message(parser_e_only_class_members)
                               Message(parser_e_only_class_members)
                             else
                             else
-                              Message(parser_e_only_class_members_via_class_ref);
+                              Message(parser_e_only_class_members_via_class_ref)
+                          else if isobjecttype then
+                            Message(parser_e_only_static_members_via_object_type);
                           p1:=csubscriptnode.create(sym,p1);
                           p1:=csubscriptnode.create(sym,p1);
                         end;
                         end;
                    end;
                    end;

+ 29 - 0
tests/webtbf/tw34821.pp

@@ -0,0 +1,29 @@
+{ %fail }
+
+ unit tw34821;
+
+{$mode objfpc}{$H+}
+
+interface
+
+type TStrBuilder = class
+  procedure append(); inline;
+end;
+
+type TTest = object
+  procedure xyz;
+end;
+
+implementation
+
+procedure TStrBuilder.append();
+begin
+  TTest.xyz;
+end;
+
+procedure TTest.xyz;
+begin
+end;
+
+end.
+

Some files were not shown because too many files changed in this diff