Browse Source

pastojs: delay RTTI init of dynamic and static array specializations

git-svn-id: trunk@46749 -
Mattias Gaertner 5 years ago
parent
commit
05edd719d5

+ 2 - 18
packages/fcl-passrc/src/pparser.pp

@@ -14,26 +14,10 @@
 
 
  **********************************************************************}
  **********************************************************************}
 
 
-{$mode objfpc}
-{$h+}
-
-{$ifdef fpc}
-  {$define UsePChar}
-  {$define UseAnsiStrings}
-  {$define HasStreams}
-  {$IF FPC_FULLVERSION<30101}
-    {$define EmulateArrayInsert}
-  {$endif}
-  {$define HasFS}
-{$endif}
-
-{$IFDEF NODEJS}
-  {$define HasFS}
-{$ENDIF}
-
-
 unit PParser;
 unit PParser;
 
 
+{$i fcl-passrc.inc}
+
 interface
 interface
 
 
 uses
 uses

+ 58 - 18
packages/pastojs/src/fppas2js.pp

@@ -15531,6 +15531,9 @@ var
   end;
   end;
 
 
 var
 var
+  aResolver: TPas2JSResolver;
+  Scope: TPasArrayScope;
+  SpecializeNeedsDelay: Boolean;
   AssignSt: TJSSimpleAssignStatement;
   AssignSt: TJSSimpleAssignStatement;
   CallName, ArrName: String;
   CallName, ArrName: String;
   Obj: TJSObjectLiteral;
   Obj: TJSObjectLiteral;
@@ -15538,7 +15541,7 @@ var
   ArrLit: TJSArrayLiteral;
   ArrLit: TJSArrayLiteral;
   Arr: TPasArrayType;
   Arr: TPasArrayType;
   Index: Integer;
   Index: Integer;
-  ElType: TPasType;
+  ElTypeHi, ElTypeLo: TPasType;
   RangeEl: TPasExpr;
   RangeEl: TPasExpr;
   Call: TJSCallExpression;
   Call: TJSCallExpression;
   RgLen, RangeEnd: TMaxPrecInt;
   RgLen, RangeEnd: TMaxPrecInt;
@@ -15552,7 +15555,6 @@ var
   BracketEx: TJSBracketMemberExpression;
   BracketEx: TJSBracketMemberExpression;
   ArraySt, CloneEl: TJSElement;
   ArraySt, CloneEl: TJSElement;
   ReturnSt: TJSReturnStatement;
   ReturnSt: TJSReturnStatement;
-  aResolver: TPas2JSResolver;
 begin
 begin
   Result:=nil;
   Result:=nil;
   aResolver:=AContext.Resolver;
   aResolver:=AContext.Resolver;
@@ -15564,6 +15566,10 @@ begin
   writeln('TPasToJSConverter.ConvertArrayType ',GetObjName(El));
   writeln('TPasToJSConverter.ConvertArrayType ',GetObjName(El));
   {$ENDIF}
   {$ENDIF}
 
 
+  Scope:=El.CustomData as TPasArrayScope;
+  SpecializeNeedsDelay:=(Scope<>nil)
+           and (aResolver.SpecializeNeedsDelay(Scope.SpecializedFromItem)<>nil);
+
   ProcScope:=nil;
   ProcScope:=nil;
   Src:=nil;
   Src:=nil;
   if AContext.JSElement is TJSSourceElements then
   if AContext.JSElement is TJSSourceElements then
@@ -15615,20 +15621,20 @@ begin
       BracketEx.MExpr:=CreatePrimitiveDotExpr(CloneArrName,El);
       BracketEx.MExpr:=CreatePrimitiveDotExpr(CloneArrName,El);
       BracketEx.Name:=CreatePrimitiveDotExpr(CloneRunName,El);
       BracketEx.Name:=CreatePrimitiveDotExpr(CloneRunName,El);
       // clone a[i]
       // clone a[i]
-      ElType:=aResolver.ResolveAliasType(El.ElType);
+      ElTypeLo:=aResolver.ResolveAliasType(El.ElType);
       CloneEl:=nil;
       CloneEl:=nil;
-      if ElType is TPasArrayType then
+      if ElTypeLo is TPasArrayType then
         begin
         begin
-        if length(TPasArrayType(ElType).Ranges)=0 then
-          RaiseNotSupported(El,AContext,20180218223414,GetObjName(ElType));
-        CloneEl:=CreateCloneStaticArray(El,TPasArrayType(ElType),BracketEx,AContext);
+        if length(TPasArrayType(ElTypeLo).Ranges)=0 then
+          RaiseNotSupported(El,AContext,20180218223414,GetObjName(ElTypeLo));
+        CloneEl:=CreateCloneStaticArray(El,TPasArrayType(ElTypeLo),BracketEx,AContext);
         end
         end
-      else if ElType is TPasRecordType then
-        CloneEl:=CreateRecordCallClone(El,TPasRecordType(ElType),BracketEx,AContext)
-      else if ElType is TPasSetType then
+      else if ElTypeLo is TPasRecordType then
+        CloneEl:=CreateRecordCallClone(El,TPasRecordType(ElTypeLo),BracketEx,AContext)
+      else if ElTypeLo is TPasSetType then
         CloneEl:=CreateReferencedSet(El,BracketEx)
         CloneEl:=CreateReferencedSet(El,BracketEx)
       else
       else
-        RaiseNotSupported(El,AContext,20180218223618,GetObjName(ElType));
+        RaiseNotSupported(El,AContext,20180218223618,GetObjName(ElTypeLo));
       Call.AddArg(CloneEl);
       Call.AddArg(CloneEl);
       BracketEx:=nil;
       BracketEx:=nil;
       // return r;
       // return r;
@@ -15679,7 +15685,8 @@ begin
       CallName:=GetBIName(pbifnRTTINewDynArray);
       CallName:=GetBIName(pbifnRTTINewDynArray);
     Call:=CreateRTTINewType(El,CallName,false,AContext,Obj);
     Call:=CreateRTTINewType(El,CallName,false,AContext,Obj);
     try
     try
-      ElType:=aResolver.ResolveAliasType(El.ElType);
+      ElTypeHi:=aResolver.ResolveAliasType(El.ElType,false);
+      ElTypeLo:=aResolver.ResolveAliasType(ElTypeHi);
       if length(El.Ranges)>0 then
       if length(El.Ranges)>0 then
         begin
         begin
         // static array
         // static array
@@ -15697,20 +15704,24 @@ begin
           inc(Index);
           inc(Index);
           if Index=length(Arr.Ranges) then
           if Index=length(Arr.Ranges) then
             begin
             begin
-            if ElType.ClassType<>TPasArrayType then
+            if ElTypeLo.ClassType<>TPasArrayType then
               break;
               break;
-            Arr:=TPasArrayType(ElType);
+            Arr:=TPasArrayType(ElTypeLo);
             if length(Arr.Ranges)=0 then
             if length(Arr.Ranges)=0 then
               RaiseNotSupported(Arr,AContext,20170411222315,'static array of anonymous array');
               RaiseNotSupported(Arr,AContext,20170411222315,'static array of anonymous array');
-            ElType:=aResolver.ResolveAliasType(Arr.ElType);
+            ElTypeHi:=aResolver.ResolveAliasType(Arr.ElType,false);
+            ElTypeLo:=aResolver.ResolveAliasType(ElTypeHi);
             Index:=0;
             Index:=0;
             end;
             end;
         until false;
         until false;
         end;
         end;
       // eltype: ref
       // eltype: ref
-      Prop:=Obj.Elements.AddElement;
-      Prop.Name:=TJSString(GetBIName(pbivnRTTIArray_ElType));
-      Prop.Expr:=CreateTypeInfoRef(ElType,AContext,El);
+      if not SpecializeNeedsDelay then
+        begin
+        Prop:=Obj.Elements.AddElement;
+        Prop.Name:=TJSString(GetBIName(pbivnRTTIArray_ElType));
+        Prop.Expr:=CreateTypeInfoRef(ElTypeHi,AContext,El);
+        end;
 
 
       if Src<>nil then
       if Src<>nil then
         begin
         begin
@@ -16729,6 +16740,10 @@ var
   Path: String;
   Path: String;
   Call: TJSCallExpression;
   Call: TJSCallExpression;
   DotExpr: TJSDotMemberExpression;
   DotExpr: TJSDotMemberExpression;
+  AssignSt: TJSSimpleAssignStatement;
+  Arr: TPasArrayType;
+  ElTypeHi, ElTypeLo: TPasType;
+  aResolver: TPas2JSResolver;
 begin
 begin
   if not IsElementUsed(El) then exit;
   if not IsElementUsed(El) then exit;
   C:=El.ClassType;
   C:=El.ClassType;
@@ -16753,6 +16768,31 @@ begin
     Call.Expr:=DotExpr;
     Call.Expr:=DotExpr;
     AddToSourceElements(Src,Call);
     AddToSourceElements(Src,Call);
     end
     end
+  else if (C=TPasArrayType) then
+    begin
+    // pas.unitname.$rtti.TArr.eltype=$mod.$rtti.TBird;
+    aResolver:=AContext.Resolver;
+    Arr:=TPasArrayType(El);
+    ElTypeHi:=aResolver.ResolveAliasType(Arr.ElType,false);
+    ElTypeLo:=aResolver.ResolveAliasType(ElTypeHi);
+    if length(Arr.Ranges)>0 then
+      begin
+      // static array
+      while ElTypeLo.ClassType=TPasArrayType do
+        begin
+        Arr:=TPasArrayType(ElTypeLo);
+        if length(Arr.Ranges)=0 then
+          RaiseNotSupported(Arr,AContext,20200902155418,'static array of anonymous array');
+        ElTypeHi:=aResolver.ResolveAliasType(Arr.ElType,false);
+        ElTypeLo:=aResolver.ResolveAliasType(ElTypeHi);
+        end;
+      end;
+    AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
+    AssignSt.LHS:=CreateDotNameExpr(El,CreateTypeInfoRef(El,AContext,El),
+                                   TJSString(GetBIName(pbivnRTTIArray_ElType)));
+    AssignSt.Expr:=CreateTypeInfoRef(ElTypeHi,AContext,El);
+    AddToSourceElements(Src,AssignSt);
+    end
   else
   else
     RaiseNotSupported(El,AContext,20200831115251);
     RaiseNotSupported(El,AContext,20200831115251);
 end;
 end;

+ 71 - 1
packages/pastojs/tests/tcgenerics.pas

@@ -76,7 +76,7 @@ type
     procedure TestGenMethod_ObjFPC;
     procedure TestGenMethod_ObjFPC;
 
 
     // generic array
     // generic array
-    // procedure TestGen_ArrayOfUnitImplRec;  ToDo dynamic + static + RTTI
+    procedure TestGen_ArrayOfUnitImplRec;
 
 
     // generic procedure type
     // generic procedure type
     procedure TestGen_ProcType_ParamUnitImpl;
     procedure TestGen_ProcType_ParamUnitImpl;
@@ -1974,6 +1974,76 @@ begin
     '']));
     '']));
 end;
 end;
 
 
+procedure TTestGenerics.TestGen_ArrayOfUnitImplRec;
+begin
+  WithTypeInfo:=true;
+  StartProgram(true,[supTObject]);
+  AddModuleWithIntfImplSrc('UnitA.pas',
+  LinesToStr([
+  'type',
+  '  generic TDyn<T> = array of T;',
+  '  generic TStatic<T> = array[1..2] of T;',
+  '']),
+  LinesToStr([
+  'type',
+  '  TBird = record',
+  '    b: word;',
+  '  end;',
+  'var',
+  '  d: specialize TDyn<TBird>;',
+  '  s: specialize TStatic<TBird>;',
+  'begin',
+  '  d[0].b:=s[1].b;',
+  '']));
+  Add([
+  'uses UnitA;',
+  'begin',
+  'end.']);
+  ConvertProgram;
+  CheckUnit('UnitA.pas',
+    LinesToStr([ // statements
+    'rtl.module("UnitA", ["system"], function () {',
+    '  var $mod = this;',
+    '  var $impl = $mod.$impl;',
+    '  $mod.$rtti.$DynArray("TDyn$G1", {});',
+    '  this.TStatic$G1$clone = function (a) {',
+    '    var r = [];',
+    '    for (var i = 0; i < 2; i++) r.push($impl.TBird.$clone(a[i]));',
+    '    return r;',
+    '  };',
+    '  $mod.$rtti.$StaticArray("TStatic$G1", {',
+    '    dims: [2]',
+    '  });',
+    '  $mod.$init = function () {',
+    '    $impl.d[0].b = $impl.s[0].b;',
+    '  };',
+    '}, null, function () {',
+    '  var $mod = this;',
+    '  var $impl = $mod.$impl;',
+    '  rtl.recNewT($impl, "TBird", function () {',
+    '    this.b = 0;',
+    '    this.$eq = function (b) {',
+    '      return this.b === b.b;',
+    '    };',
+    '    this.$assign = function (s) {',
+    '      this.b = s.b;',
+    '      return this;',
+    '    };',
+    '    var $r = $mod.$rtti.$Record("TBird", {});',
+    '    $r.addField("b", rtl.word);',
+    '  });',
+    '  $impl.d = [];',
+    '  $impl.s = rtl.arraySetLength(null, $impl.TBird, 2);',
+    '});']));
+  CheckSource('TestGen_Class_ClassVarRecord_UnitImpl',
+    LinesToStr([ // statements
+    'pas.UnitA.$rtti["TDyn$G1"].eltype = pas.UnitA.$rtti["TBird"];',
+    'pas.UnitA.$rtti["TStatic$G1"].eltype = pas.UnitA.$rtti["TBird"];',
+    '']),
+    LinesToStr([ // $mod.$main
+    '']));
+end;
+
 procedure TTestGenerics.TestGen_ProcType_ParamUnitImpl;
 procedure TTestGenerics.TestGen_ProcType_ParamUnitImpl;
 begin
 begin
   WithTypeInfo:=true;
   WithTypeInfo:=true;