Browse Source

* implement necessary conversion functionality for anonymous procdefs to function reference interfaces including capturing of variables

Sven/Sarah Barth 3 years ago
parent
commit
76df7144ba
2 changed files with 83 additions and 9 deletions
  1. 44 5
      compiler/defcmp.pas
  2. 39 4
      compiler/ncnv.pas

+ 44 - 5
compiler/defcmp.pas

@@ -108,7 +108,8 @@ interface
           tc_array_2_dynarray,
           tc_array_2_dynarray,
           tc_elem_2_openarray,
           tc_elem_2_openarray,
           tc_arrayconstructor_2_dynarray,
           tc_arrayconstructor_2_dynarray,
-          tc_arrayconstructor_2_array
+          tc_arrayconstructor_2_array,
+          tc_anonproc_2_funcref
        );
        );
 
 
     function compare_defs_ext(def_from,def_to : tdef;
     function compare_defs_ext(def_from,def_to : tdef;
@@ -203,6 +204,9 @@ implementation
       end;
       end;
 
 
 
 
+    function proc_to_funcref_conv(def1:tabstractprocdef;def2:tobjectdef):tequaltype;forward;
+
+
     function compare_defs_ext(def_from,def_to : tdef;
     function compare_defs_ext(def_from,def_to : tdef;
                               fromtreetype : tnodetype;
                               fromtreetype : tnodetype;
                               var doconv : tconverttype;
                               var doconv : tconverttype;
@@ -1867,6 +1871,20 @@ implementation
                    doconv:=tc_char_2_string;
                    doconv:=tc_char_2_string;
                    eq:=te_convert_l2
                    eq:=te_convert_l2
                  end
                  end
+               else if is_funcref(def_to) and
+                   (def_from.typ=procdef) and
+                   (po_anonymous in tprocdef(def_from).procoptions) then
+                 begin
+                   subeq:=proc_to_funcref_conv(tprocdef(def_from),tobjectdef(def_to));
+                   if subeq>te_incompatible then
+                     begin
+                       doconv:=tc_anonproc_2_funcref;
+                       if subeq>te_convert_l5 then
+                         eq:=pred(subeq)
+                       else
+                         eq:=subeq;
+                     end;
+                 end
                else if is_funcref(def_to) and
                else if is_funcref(def_to) and
                    is_funcref(def_from) and
                    is_funcref(def_from) and
                    not (cdo_equal_check in cdoptions) then
                    not (cdo_equal_check in cdoptions) then
@@ -2507,6 +2525,7 @@ implementation
         po_comp: tprocoptions;
         po_comp: tprocoptions;
         pa_comp: tcompare_paras_options;
         pa_comp: tcompare_paras_options;
         captured : tfplist;
         captured : tfplist;
+        dstisfuncref : boolean;
       begin
       begin
          proc_to_procvar_equal_internal:=te_incompatible;
          proc_to_procvar_equal_internal:=te_incompatible;
          if not(assigned(def1)) or not(assigned(def2)) then
          if not(assigned(def1)) or not(assigned(def2)) then
@@ -2590,19 +2609,27 @@ implementation
                     if def1.typ<>procdef then
                     if def1.typ<>procdef then
                       internalerror(2021052602);
                       internalerror(2021052602);
                     captured:=tprocdef(def1).capturedsyms;
                     captured:=tprocdef(def1).capturedsyms;
+                    { a function reference can capture anything, but they're
+                      rather expensive, so cheaper overloads are preferred }
+                    dstisfuncref:=assigned(def2.owner) and
+                        assigned(def2.owner.defowner) and
+                        is_funcref(tdef(def2.owner.defowner));
                     { if no symbol was captured an anonymous function is
                     { if no symbol was captured an anonymous function is
-                      compatible to all three types of function pointers, but we
+                      compatible to all four types of function pointers, but we
                       might need to generate its code differently (e.g. get rid
                       might need to generate its code differently (e.g. get rid
                       of parentfp parameter for global functions); the order for
                       of parentfp parameter for global functions); the order for
                       this is:
                       this is:
                         - procedure variable
                         - procedure variable
                         - method variable
                         - method variable
+                        - function reference
                         - nested procvar }
                         - nested procvar }
                     if not assigned(captured) or (captured.count=0) then
                     if not assigned(captured) or (captured.count=0) then
                       begin
                       begin
                         if po_methodpointer in def2.procoptions then
                         if po_methodpointer in def2.procoptions then
                           eq:=te_convert_l2
                           eq:=te_convert_l2
                         else if po_delphi_nested_cc in def2.procoptions then
                         else if po_delphi_nested_cc in def2.procoptions then
+                          eq:=te_convert_l4
+                        else if dstisfuncref then
                           eq:=te_convert_l3
                           eq:=te_convert_l3
                         else
                         else
                           eq:=te_convert_l1
                           eq:=te_convert_l1
@@ -2611,21 +2638,27 @@ implementation
                       compatible to normal function pointers; the order for this
                       compatible to normal function pointers; the order for this
                       is:
                       is:
                         - method variable
                         - method variable
+                        - function reference
                         - nested function }
                         - nested function }
                     else if (captured.count=1) and (vo_is_self in tabstractvarsym(pcapturedsyminfo(captured[0])^.sym).varoptions) then
                     else if (captured.count=1) and (vo_is_self in tabstractvarsym(pcapturedsyminfo(captured[0])^.sym).varoptions) then
                       begin
                       begin
                         if po_methodpointer in def2.procoptions then
                         if po_methodpointer in def2.procoptions then
                           eq:=te_convert_l1
                           eq:=te_convert_l1
                         else if po_delphi_nested_cc in def2.procoptions then
                         else if po_delphi_nested_cc in def2.procoptions then
+                          eq:=te_convert_l3
+                        else if dstisfuncref then
                           eq:=te_convert_l2
                           eq:=te_convert_l2
                         else
                         else
                           eq:=te_incompatible;
                           eq:=te_incompatible;
                       end
                       end
-                    { otherwise it's compatible to nested function pointers only }
+                    { otherwise it's compatible to nested function pointers and
+                      function references }
                     else
                     else
                       begin
                       begin
-                        if po_delphi_nested_cc in def2.procoptions then
+                        if dstisfuncref then
                           eq:=te_convert_l1
                           eq:=te_convert_l1
+                        else if po_delphi_nested_cc in def2.procoptions then
+                          eq:=te_convert_l2
                         else
                         else
                           eq:=te_incompatible;
                           eq:=te_incompatible;
                       end;
                       end;
@@ -2642,7 +2675,7 @@ implementation
       end;
       end;
 
 
 
 
-    function proc_to_funcref_equal(def1:tabstractprocdef;def2:tobjectdef):tequaltype;
+    function proc_to_funcref_conv(def1:tabstractprocdef;def2:tobjectdef):tequaltype;
       var
       var
         invoke : tprocdef;
         invoke : tprocdef;
       begin
       begin
@@ -2653,6 +2686,12 @@ implementation
           internalerror(2022011601);
           internalerror(2022011601);
         invoke:=get_invoke_procdef(def2);
         invoke:=get_invoke_procdef(def2);
         result:=proc_to_procvar_equal_internal(def1,invoke,false,true);
         result:=proc_to_procvar_equal_internal(def1,invoke,false,true);
+      end;
+
+
+    function proc_to_funcref_equal(def1:tabstractprocdef;def2:tobjectdef):tequaltype;
+      begin
+        result:=proc_to_funcref_conv(def1,def2);
         { as long as the two methods are considered convertible we consider the
         { as long as the two methods are considered convertible we consider the
           procdef and the function reference as equal }
           procdef and the function reference as equal }
         if result>te_convert_operator then
         if result>te_convert_operator then

+ 39 - 4
compiler/ncnv.pas

@@ -120,6 +120,7 @@ interface
           function typecheck_elem_2_openarray : tnode; virtual;
           function typecheck_elem_2_openarray : tnode; virtual;
           function typecheck_arrayconstructor_to_dynarray : tnode; virtual;
           function typecheck_arrayconstructor_to_dynarray : tnode; virtual;
           function typecheck_arrayconstructor_to_array : tnode; virtual;
           function typecheck_arrayconstructor_to_array : tnode; virtual;
+          function typecheck_anonproc_2_funcref : tnode; virtual;
        private
        private
           function _typecheck_int_to_int : tnode;
           function _typecheck_int_to_int : tnode;
           function _typecheck_cord_to_pointer : tnode;
           function _typecheck_cord_to_pointer : tnode;
@@ -153,6 +154,7 @@ interface
           function _typecheck_elem_2_openarray : tnode;
           function _typecheck_elem_2_openarray : tnode;
           function _typecheck_arrayconstructor_to_dynarray : tnode;
           function _typecheck_arrayconstructor_to_dynarray : tnode;
           function _typecheck_arrayconstructor_to_array : tnode;
           function _typecheck_arrayconstructor_to_array : tnode;
+          function _typecheck_anonproc_to_funcref : tnode;
        protected
        protected
           function first_int_to_int : tnode;virtual;
           function first_int_to_int : tnode;virtual;
           function first_cstring_to_pchar : tnode;virtual;
           function first_cstring_to_pchar : tnode;virtual;
@@ -325,7 +327,7 @@ implementation
       ncon,ncal,nset,nadd,nmem,nmat,nbas,nutils,ninl,nflw,
       ncon,ncal,nset,nadd,nmem,nmat,nbas,nutils,ninl,nflw,
       psub,
       psub,
       cgbase,procinfo,
       cgbase,procinfo,
-      htypechk,blockutl,pparautl,pass_1,cpuinfo;
+      htypechk,blockutl,pparautl,procdefutil,pass_1,cpuinfo;
 
 
 
 
 {*****************************************************************************
 {*****************************************************************************
@@ -2344,6 +2346,12 @@ implementation
       end;
       end;
 
 
 
 
+    function ttypeconvnode._typecheck_anonproc_to_funcref : tnode;
+      begin
+        result:=typecheck_anonproc_2_funcref;
+      end;
+
+
     function ttypeconvnode.target_specific_general_typeconv: boolean;
     function ttypeconvnode.target_specific_general_typeconv: boolean;
       begin
       begin
         result:=false;
         result:=false;
@@ -2639,6 +2647,30 @@ implementation
       end;
       end;
 
 
 
 
+    function ttypeconvnode.typecheck_anonproc_2_funcref : tnode;
+      var
+        capturer : tsym;
+        intfdef : tdef;
+        ldnode : tnode;
+      begin
+        intfdef:=capturer_add_anonymous_proc(current_procinfo,tprocdef(left.resultdef),capturer);
+        if assigned(intfdef) then
+          begin
+            if assigned(capturer) then
+              ldnode:=cloadnode.create(capturer,capturer.owner)
+            else
+              ldnode:=cnilnode.create;
+            result:=ctypeconvnode.create_internal(
+                      ctypeconvnode.create_internal(
+                        ldnode,
+                        intfdef),
+                      totypedef);
+          end
+        else
+          result:=cerrornode.create;
+      end;
+
+
     function ttypeconvnode.typecheck_call_helper(c : tconverttype) : tnode;
     function ttypeconvnode.typecheck_call_helper(c : tconverttype) : tnode;
       const
       const
          resultdefconvert : array[tconverttype] of pointer = (
          resultdefconvert : array[tconverttype] of pointer = (
@@ -2684,7 +2716,8 @@ implementation
           { array_2_dynarray} @ttypeconvnode._typecheck_array_2_dynarray,
           { array_2_dynarray} @ttypeconvnode._typecheck_array_2_dynarray,
           { elem_2_openarray } @ttypeconvnode._typecheck_elem_2_openarray,
           { elem_2_openarray } @ttypeconvnode._typecheck_elem_2_openarray,
           { arrayconstructor_2_dynarray } @ttypeconvnode._typecheck_arrayconstructor_to_dynarray,
           { arrayconstructor_2_dynarray } @ttypeconvnode._typecheck_arrayconstructor_to_dynarray,
-          { arrayconstructor_2_array } @ttypeconvnode._typecheck_arrayconstructor_to_array
+          { arrayconstructor_2_array } @ttypeconvnode._typecheck_arrayconstructor_to_array,
+          { anonproc_2_funcref } @ttypeconvnode._typecheck_anonproc_to_funcref
          );
          );
       type
       type
          tprocedureofobject = function : tnode of object;
          tprocedureofobject = function : tnode of object;
@@ -4392,7 +4425,8 @@ implementation
            nil,
            nil,
            @ttypeconvnode._first_nothing,
            @ttypeconvnode._first_nothing,
            @ttypeconvnode._first_nothing,
            @ttypeconvnode._first_nothing,
-           @ttypeconvnode._first_nothing
+           @ttypeconvnode._first_nothing,
+           nil
          );
          );
       type
       type
          tprocedureofobject = function : tnode of object;
          tprocedureofobject = function : tnode of object;
@@ -4673,7 +4707,8 @@ implementation
            @ttypeconvnode._second_nothing,  { array_2_dynarray }
            @ttypeconvnode._second_nothing,  { array_2_dynarray }
            @ttypeconvnode._second_elem_to_openarray,  { elem_2_openarray }
            @ttypeconvnode._second_elem_to_openarray,  { elem_2_openarray }
            @ttypeconvnode._second_nothing,  { arrayconstructor_2_dynarray }
            @ttypeconvnode._second_nothing,  { arrayconstructor_2_dynarray }
-           @ttypeconvnode._second_nothing   { arrayconstructor_2_array }
+           @ttypeconvnode._second_nothing,  { arrayconstructor_2_array }
+           @ttypeconvnode._second_nothing   { anonproc_2_funcref }
          );
          );
       type
       type
          tprocedureofobject = procedure of object;
          tprocedureofobject = procedure of object;