Browse Source

* Fix creating thunk class when inherited interfaces are used

Michaël Van Canneyt 1 year ago
parent
commit
312cf246ad
4 changed files with 81 additions and 21 deletions
  1. 8 3
      compiler/pmodules.pas
  2. 1 0
      compiler/symconst.pas
  3. 50 13
      compiler/symcreat.pas
  4. 22 5
      compiler/symdef.pas

+ 8 - 3
compiler/pmodules.pas

@@ -1203,6 +1203,11 @@ type
             exit;
             exit;
           end;
           end;
 
 
+        { we need to be able to reference these in descendants,
+          so they must be generated and included in the interface }
+        if (target_cpu=tsystemcpu.cpu_wasm32) then
+          add_synthetic_interface_classes_for_st(curr.globalsymtable,true,false);
+
         { Our interface is compiled, generate CRC and switch to implementation }
         { Our interface is compiled, generate CRC and switch to implementation }
         if not(cs_compilesystem in current_settings.moduleswitches) and
         if not(cs_compilesystem in current_settings.moduleswitches) and
           (Errorcount=0) then
           (Errorcount=0) then
@@ -1476,8 +1481,8 @@ type
          // This needs to be done before we generate the VMTs
          // This needs to be done before we generate the VMTs
          if (target_cpu=tsystemcpu.cpu_wasm32) then
          if (target_cpu=tsystemcpu.cpu_wasm32) then
            begin
            begin
-           add_synthetic_interface_classes_for_st(module.globalsymtable);
-           add_synthetic_interface_classes_for_st(module.localsymtable);
+           add_synthetic_interface_classes_for_st(module.globalsymtable,false,true);
+           add_synthetic_interface_classes_for_st(module.localsymtable,true,true);
            end;
            end;
 
 
          { generate construction functions for all attributes in the unit:
          { generate construction functions for all attributes in the unit:
@@ -2542,7 +2547,7 @@ type
 
 
         { This needs to be done before we generate the VMTs }
         { This needs to be done before we generate the VMTs }
         if (target_cpu=tsystemcpu.cpu_wasm32) then
         if (target_cpu=tsystemcpu.cpu_wasm32) then
-          add_synthetic_interface_classes_for_st(curr.localsymtable);
+          add_synthetic_interface_classes_for_st(curr.localsymtable,true,true);
 
 
         { Generate VMTs }
         { Generate VMTs }
         if Errorcount=0 then
         if Errorcount=0 then

+ 1 - 0
compiler/symconst.pas

@@ -1004,6 +1004,7 @@ inherited_objectoptions : tobjectoptions = [oo_has_virtual,oo_has_private,oo_has
 {$endif not jvm}
 {$endif not jvm}
 
 
      objecttypes_with_helpers=[odt_class,odt_interfacecom,odt_interfacecorba,odt_dispinterface];
      objecttypes_with_helpers=[odt_class,odt_interfacecom,odt_interfacecorba,odt_dispinterface];
+     objecttypes_with_thunk=[odt_interfacecorba,odt_interfacecom];
 
 
 { !! Be sure to keep these in sync with ones in rtl/inc/varianth.inc }
 { !! Be sure to keep these in sync with ones in rtl/inc/varianth.inc }
       varempty = 0;
       varempty = 0;

+ 50 - 13
compiler/symcreat.pas

@@ -130,7 +130,7 @@ interface
   { Generate the hidden thunk class for interfaces,
   { Generate the hidden thunk class for interfaces,
     so we can use them in TVirtualInterface on platforms that do not allow
     so we can use them in TVirtualInterface on platforms that do not allow
     generating executable code in memory at runtime.}
     generating executable code in memory at runtime.}
-  procedure add_synthetic_interface_classes_for_st(st : tsymtable);
+  procedure add_synthetic_interface_classes_for_st(st : tsymtable; gen_intf, gen_impl : boolean);
 
 
 
 
 implementation
 implementation
@@ -318,8 +318,10 @@ implementation
     function str_parse_objecttypedef(typename : shortstring;str: ansistring): tobjectdef;
     function str_parse_objecttypedef(typename : shortstring;str: ansistring): tobjectdef;
      var
      var
        b,oldparse_only: boolean;
        b,oldparse_only: boolean;
+       i : integer;
        tmpstr: ansistring;
        tmpstr: ansistring;
        flags : tread_proc_flags;
        flags : tread_proc_flags;
+       o : TObject;
 
 
      begin
      begin
       result:=nil;
       result:=nil;
@@ -333,9 +335,18 @@ implementation
       current_scanner.substitutemacro('hidden_interface_class_macro',@str[1],length(str),current_scanner.line_no,current_scanner.inputfile.ref_index,true);
       current_scanner.substitutemacro('hidden_interface_class_macro',@str[1],length(str),current_scanner.line_no,current_scanner.inputfile.ref_index,true);
       current_scanner.readtoken(false);
       current_scanner.readtoken(false);
       type_dec(b);
       type_dec(b);
-      if (current_module.DefList.Last is tobjectdef) and
-         (tobjectdef(current_module.DefList.Last).GetTypeName=typename) then
-           result:=tobjectdef(current_module.DefList.Last);
+      // In the interface part, the object def is not necessarily the last one, the methods also generate defs.
+      i:=current_module.DefList.count-1;
+      While (result=nil) and (i>=0) do
+        begin
+        O:=current_module.DefList[i];
+        if (o is tobjectdef) then
+           if (tobjectdef(o).GetTypeName=typename) then
+             result:=tobjectdef(o);
+        dec(i);
+        end;
+      if result=nil then
+        internalerror(2024050401);
       parse_only:=oldparse_only;
       parse_only:=oldparse_only;
       { remove the temporary macro input file again }
       { remove the temporary macro input file again }
       current_scanner.closeinputfile;
       current_scanner.closeinputfile;
@@ -1537,19 +1548,40 @@ implementation
       result:=offs;
       result:=offs;
     end;
     end;
 
 
+
+  // return parent Interface def, but skip iunknown.
+
+  function getparent_interface_def(odef : tobjectdef) : tobjectdef;
+
+  begin
+    if (odef.getparentdef is tobjectdef) then
+      begin
+      result:=odef.getparentdef as tobjectdef;
+      if result=interface_iunknown then
+        result:=Nil;
+      end
+    else
+      result:=nil;
+  end;
+
   procedure implement_interface_thunkclass_decl(cn : shortstring; objdef : tobjectdef);
   procedure implement_interface_thunkclass_decl(cn : shortstring; objdef : tobjectdef);
 
 
   var
   var
-    str : ansistring;
+    parentname,str : ansistring;
     sym : tsym;
     sym : tsym;
     proc : tprocsym absolute sym;
     proc : tprocsym absolute sym;
     pd : tprocdef;
     pd : tprocdef;
-    def : tobjectdef;
+    odef,def : tobjectdef;
     offs,argcount,i,j : integer;
     offs,argcount,i,j : integer;
 
 
   begin
   begin
     str:='type '#10;
     str:='type '#10;
-    str:=str+cn+' = class(TInterfaceThunk,'+objdef.GetTypeName+')'#10;
+    odef:=getparent_interface_def(objdef);
+    if (oDef=Nil) or (oDef.hiddenclassdef=Nil) then
+      parentname:='TInterfaceThunk'
+    else
+      parentname:=odef.hiddenclassdef.GetTypeName;
+    str:=str+cn+' = class('+parentname+','+objdef.GetTypeName+')'#10;
     str:=str+' protected '#10;
     str:=str+' protected '#10;
     for I:=0 to objdef.symtable.symList.Count-1 do
     for I:=0 to objdef.symtable.symList.Count-1 do
       begin
       begin
@@ -1583,6 +1615,9 @@ implementation
     if assigned(def) then
     if assigned(def) then
       begin
       begin
       def.created_in_current_module:=true;
       def.created_in_current_module:=true;
+      if not def.typesym.is_registered then
+        def.typesym.register_sym;
+      def.buildderef;
       include(def.objectoptions,oo_can_have_published);
       include(def.objectoptions,oo_can_have_published);
       end;
       end;
     objdef.hiddenclassdef:=def;
     objdef.hiddenclassdef:=def;
@@ -1738,7 +1773,7 @@ implementation
       end;
       end;
   end;
   end;
 
 
-  procedure add_synthetic_interface_classes_for_st(st : tsymtable);
+  procedure add_synthetic_interface_classes_for_st(st : tsymtable; gen_intf, gen_impl : boolean);
 
 
   var
   var
     i   : longint;
     i   : longint;
@@ -1759,14 +1794,16 @@ implementation
       def:=tdef(st.deflist[i]);
       def:=tdef(st.deflist[i]);
       if (def.typ<>objectdef) then
       if (def.typ<>objectdef) then
         continue;
         continue;
-      if not (objdef.objecttype in [odt_interfacecorba,odt_interfacecom]) then
+      if not (objdef.objecttype in objecttypes_with_thunk) then
         continue;
         continue;
       if not (oo_can_have_published in objdef.objectoptions) then
       if not (oo_can_have_published in objdef.objectoptions) then
         continue;
         continue;
       // need to add here extended rtti check when it is available
       // need to add here extended rtti check when it is available
       cn:=generate_thunkclass_name(i,objdef);
       cn:=generate_thunkclass_name(i,objdef);
-      implement_interface_thunkclass_decl(cn,objdef);
-      implement_interface_thunkclass_impl(cn,objdef);
+      if gen_intf then
+        implement_interface_thunkclass_decl(cn,objdef);
+      if gen_impl then
+        implement_interface_thunkclass_impl(cn,objdef);
       end;
       end;
     restore_scanner(sstate);
     restore_scanner(sstate);
     // Recurse for interfaces defined in a type section of a class/record.
     // Recurse for interfaces defined in a type section of a class/record.
@@ -1774,9 +1811,9 @@ implementation
       begin
       begin
       def:=tdef(st.deflist[i]);
       def:=tdef(st.deflist[i]);
       if (def.typ=objectdef) and (objdef.objecttype=odt_class) then
       if (def.typ=objectdef) and (objdef.objecttype=odt_class) then
-        add_synthetic_interface_classes_for_st(objdef.symtable)
+        add_synthetic_interface_classes_for_st(objdef.symtable,gen_intf,gen_impl)
       else if (def.typ=recorddef) and (m_advanced_records in current_settings.modeswitches) then
       else if (def.typ=recorddef) and (m_advanced_records in current_settings.modeswitches) then
-        add_synthetic_interface_classes_for_st(recdef.symtable);
+        add_synthetic_interface_classes_for_st(recdef.symtable,gen_intf,gen_impl);
       end;
       end;
   end;
   end;
 
 

+ 22 - 5
compiler/symdef.pas

@@ -516,10 +516,12 @@ interface
           objecttype     : tobjecttyp;
           objecttype     : tobjecttyp;
           { for interfaces that can be invoked using Invoke(),
           { for interfaces that can be invoked using Invoke(),
             this is the definition of the hidden class that is generated by the compiler.
             this is the definition of the hidden class that is generated by the compiler.
-            we need this definition to reference it in the RTTI, only during compilation of unit. 
-            so no need to write it to the .ppu file.
+            we need this definition to reference it in the RTTI.
+            Since interfaces can inherit, so can these hidden classes,
+            so we need to write this to the ppu to be able to reference the parents.
           }
           }
           hiddenclassdef : tobjectdef;
           hiddenclassdef : tobjectdef;
+          hiddenclassdefref : tderef;
           constructor create(ot:tobjecttyp;const n:string;c:tobjectdef;doregister:boolean);virtual;
           constructor create(ot:tobjecttyp;const n:string;c:tobjectdef;doregister:boolean);virtual;
           constructor ppuload(ppufile:tcompilerppufile);
           constructor ppuload(ppufile:tcompilerppufile);
           destructor  destroy;override;
           destructor  destroy;override;
@@ -1645,7 +1647,7 @@ implementation
 
 
     function make_mangledname(const typeprefix:TSymStr;st:TSymtable;const suffix:TSymStr):TSymStr;
     function make_mangledname(const typeprefix:TSymStr;st:TSymtable;const suffix:TSymStr):TSymStr;
       var
       var
-        s,
+        s,t,
         prefix : TSymStr;
         prefix : TSymStr;
         hash : qword;
         hash : qword;
       begin
       begin
@@ -1691,8 +1693,11 @@ implementation
              prefix:=tabstractrecorddef(st.defowner).objname^+'_$_'+prefix;
              prefix:=tabstractrecorddef(st.defowner).objname^+'_$_'+prefix;
              st:=st.defowner.owner;
              st:=st.defowner.owner;
            end;
            end;
-          { local classes & interfaces are possible (because of closures) }
-          if st.symtabletype<>localsymtable then
+          { local classes & interfaces are possible (because of closures)
+            or parasymtable for this case:
+             class function Trace<TResult>(const Func: TFunc<TLogToken, TResult>): TResult;
+          }
+          if not (st.symtabletype in [localsymtable,parasymtable]) then
             break;
             break;
           prefix:='$'+prefix;
           prefix:='$'+prefix;
         until false;
         until false;
@@ -7858,6 +7863,8 @@ implementation
         childof:=nil;
         childof:=nil;
         childofderef.reset;
         childofderef.reset;
         vmt_fieldderef.reset;
         vmt_fieldderef.reset;
+        hiddenclassdefref.reset;
+
         extendeddefderef.reset;
         extendeddefderef.reset;
         cloneddefderef.reset;
         cloneddefderef.reset;
         if objecttype=odt_helper then
         if objecttype=odt_helper then
@@ -7945,6 +7952,8 @@ implementation
          else
          else
            ImplementedInterfaces:=nil;
            ImplementedInterfaces:=nil;
 
 
+         if (target_cpu=tsystemcpu.cpu_wasm32) and (objecttype in objecttypes_with_thunk) then
+           ppufile.getderef(hiddenclassdefref);
          if df_copied_def in defoptions then
          if df_copied_def in defoptions then
            begin
            begin
              ppufile.getderef(cloneddefderef);
              ppufile.getderef(cloneddefderef);
@@ -8143,6 +8152,9 @@ implementation
                end;
                end;
            end;
            end;
 
 
+         if (target_cpu=tsystemcpu.cpu_wasm32) and (objecttype in objecttypes_with_thunk) then
+           ppufile.putderef(hiddenclassdefref);
+
          if df_copied_def in defoptions then
          if df_copied_def in defoptions then
            ppufile.putderef(cloneddefderef);
            ppufile.putderef(cloneddefderef);
 
 
@@ -8176,6 +8188,9 @@ implementation
          inherited buildderef;
          inherited buildderef;
          vmt_fieldderef.build(vmt_field);
          vmt_fieldderef.build(vmt_field);
          childofderef.build(childof);
          childofderef.build(childof);
+
+        if (target_cpu=tsystemcpu.cpu_wasm32) and (objecttype in objecttypes_with_thunk) then
+           hiddenclassdefref.build(hiddenclassdef);
          if df_copied_def in defoptions then
          if df_copied_def in defoptions then
            cloneddefderef.build(symtable.defowner)
            cloneddefderef.build(symtable.defowner)
          else
          else
@@ -8206,6 +8221,8 @@ implementation
          inherited deref;
          inherited deref;
          vmt_field:=tsym(vmt_fieldderef.resolve);
          vmt_field:=tsym(vmt_fieldderef.resolve);
          childof:=tobjectdef(childofderef.resolve);
          childof:=tobjectdef(childofderef.resolve);
+         if (target_cpu=tsystemcpu.cpu_wasm32) and (objecttype in objecttypes_with_thunk) then
+           hiddenclassdef:=tobjectdef(hiddenclassdefref.resolve);
          if df_copied_def in defoptions then
          if df_copied_def in defoptions then
            begin
            begin
              cloneddef:=tobjectdef(cloneddefderef.resolve);
              cloneddef:=tobjectdef(cloneddefderef.resolve);