瀏覽代碼

pastojs: filer: started pending specialize

git-svn-id: trunk@44388 -
Mattias Gaertner 5 年之前
父節點
當前提交
997c8089a6
共有 3 個文件被更改,包括 295 次插入36 次删除
  1. 275 30
      packages/pastojs/src/pas2jsfiler.pp
  2. 19 6
      packages/pastojs/tests/tcfiler.pas
  3. 1 0
      packages/pastojs/tests/testpas2js.lpi

+ 275 - 30
packages/pastojs/src/pas2jsfiler.pp

@@ -774,6 +774,7 @@ type
     procedure WriteScopeReferences(Obj: TJSONObject; References: TPasScopeReferences;
     procedure WriteScopeReferences(Obj: TJSONObject; References: TPasScopeReferences;
       const PropName: string; aContext: TPCUWriterContext); virtual;
       const PropName: string; aContext: TPCUWriterContext); virtual;
     // extern references
     // extern references
+    function IsExternalEl(El: TPasElement): boolean; virtual;
     procedure WriteExtRefSignature(Ref: TPCUFilerElementRef; aContext: TPCUWriterContext); virtual;
     procedure WriteExtRefSignature(Ref: TPCUFilerElementRef; aContext: TPCUWriterContext); virtual;
     function WriteExternalReference(El: TPasElement; aContext: TPCUWriterContext): TPCUFilerElementRef; virtual;
     function WriteExternalReference(El: TPasElement; aContext: TPCUWriterContext): TPCUFilerElementRef; virtual;
     procedure WriteExternalReferences(aContext: TPCUWriterContext); virtual;
     procedure WriteExternalReferences(aContext: TPCUWriterContext); virtual;
@@ -903,6 +904,28 @@ type
     Arr: TJSONArray;
     Arr: TJSONArray;
   end;
   end;
 
 
+  TPCUReaderPendingSpecialized = class;
+
+  { TPCUReaderPendingSpecializedParam }
+
+  TPCUReaderPendingSpecializedParam = class
+  public
+    Spec: TPCUReaderPendingSpecialized;
+    Index: integer; // index in Spec.Params
+    Element: TPasElement;
+  end;
+
+  { TPCUReaderPendingSpecialized }
+
+  TPCUReaderPendingSpecialized = class
+  public
+    Obj: TJSONObject;
+    GenericEl: TPasGenericType;
+    Params: TFPList; // list of PCUReaderPendingSpecializedParams
+    Prev, Next: TPCUReaderPendingSpecialized;
+    destructor Destroy; override;
+  end;
+
   { TPCUReader }
   { TPCUReader }
 
 
   TPCUReader = class(TPCUCustomReader)
   TPCUReader = class(TPCUCustomReader)
@@ -910,6 +933,9 @@ type
     FElementRefsArray: TPCUFilerElementRefArray; // TPCUFilerElementRef by Id
     FElementRefsArray: TPCUFilerElementRefArray; // TPCUFilerElementRef by Id
     FJSON: TJSONObject;
     FJSON: TJSONObject;
     FPendingIdentifierScopes: TObjectList; // list of TPCUReaderPendingIdentifierScope
     FPendingIdentifierScopes: TObjectList; // list of TPCUReaderPendingIdentifierScope
+    FPendingSpecialize: TPCUReaderPendingSpecialized; // chain of TPCUReaderPendingSpecialized
+    function AddPendingSpecialize(GenEl: TPasGenericType; ParamCount: integer): TPCUReaderPendingSpecialized;
+    procedure DeletePendingSpecialize(PendSpec: TPCUReaderPendingSpecialized);
     procedure Set_Variable_VarType(RefEl: TPasElement; Data: TObject);
     procedure Set_Variable_VarType(RefEl: TPasElement; Data: TObject);
     procedure Set_AliasType_DestType(RefEl: TPasElement; Data: TObject);
     procedure Set_AliasType_DestType(RefEl: TPasElement; Data: TObject);
     procedure Set_PointerType_DestType(RefEl: TPasElement; Data: TObject);
     procedure Set_PointerType_DestType(RefEl: TPasElement; Data: TObject);
@@ -943,6 +969,7 @@ type
     procedure Set_ResolvedReference_Declaration(RefEl: TPasElement; Data: TObject);
     procedure Set_ResolvedReference_Declaration(RefEl: TPasElement; Data: TObject);
     procedure Set_ResolvedReference_CtxConstructor(RefEl: TPasElement; Data: TObject);
     procedure Set_ResolvedReference_CtxConstructor(RefEl: TPasElement; Data: TObject);
     procedure Set_ResolvedReference_CtxAttrProc(RefEl: TPasElement; Data: TObject);
     procedure Set_ResolvedReference_CtxAttrProc(RefEl: TPasElement; Data: TObject);
+    procedure Set_SpecializeParam(RefEl: TPasElement; Data: TObject);
   protected
   protected
     // json
     // json
     procedure RaiseMsg(Id: int64; const Msg: string = ''); overload; override;
     procedure RaiseMsg(Id: int64; const Msg: string = ''); overload; override;
@@ -988,6 +1015,7 @@ type
     procedure ReadPasElement(Obj: TJSONObject; El: TPasElement; aContext: TPCUReaderContext); virtual;
     procedure ReadPasElement(Obj: TJSONObject; El: TPasElement; aContext: TPCUReaderContext); virtual;
     procedure ReadExternalMembers(El: TPasElement; Arr: TJSONArray; Members: TFPList); virtual;
     procedure ReadExternalMembers(El: TPasElement; Arr: TJSONArray; Members: TFPList); virtual;
     procedure ReadExternalReferences(Obj: TJSONObject; El: TPasElement); virtual;
     procedure ReadExternalReferences(Obj: TJSONObject; El: TPasElement); virtual;
+    procedure ReadExternalSpecialized(Obj: TJSONObject; GenEl: TPasGenericType; ParamIDs: TJSONArray); virtual;
     procedure ReadUsedUnitsInit(Obj: TJSONObject; Section: TPasSection; aContext: TPCUReaderContext); virtual;
     procedure ReadUsedUnitsInit(Obj: TJSONObject; Section: TPasSection; aContext: TPCUReaderContext); virtual;
     procedure ReadUsedUnitsFinish(Obj: TJSONObject; Section: TPasSection; aContext: TPCUReaderContext); virtual;
     procedure ReadUsedUnitsFinish(Obj: TJSONObject; Section: TPasSection; aContext: TPCUReaderContext); virtual;
     procedure ReadSectionScope(Obj: TJSONObject; Scope: TPas2JSSectionScope; aContext: TPCUReaderContext); virtual;
     procedure ReadSectionScope(Obj: TJSONObject; Scope: TPas2JSSectionScope; aContext: TPCUReaderContext); virtual;
@@ -1734,6 +1762,23 @@ begin
     AddLine(Line);
     AddLine(Line);
 end;
 end;
 
 
+{ TPCUReaderPendingSpecialized }
+
+destructor TPCUReaderPendingSpecialized.Destroy;
+var
+  i: Integer;
+begin
+  Obj:=nil;
+  GenericEl:=nil;
+  if Params<>nil then
+    begin
+    for i:=0 to Params.Count-1 do
+      TObject(Params[i]).Free;
+    FreeAndNil(Params);
+    end;
+  inherited Destroy;
+end;
+
 { TPCUCustomReader }
 { TPCUCustomReader }
 
 
 function TPCUCustomReader.ReadCanContinue: boolean;
 function TPCUCustomReader.ReadCanContinue: boolean;
@@ -2192,7 +2237,7 @@ end;
 function TPCUWriter.CreateElementRef(El: TPasElement): TPCUFilerElementRef;
 function TPCUWriter.CreateElementRef(El: TPasElement): TPCUFilerElementRef;
 begin
 begin
   Result:=inherited CreateElementRef(El);
   Result:=inherited CreateElementRef(El);
-  if El.GetModule<>Resolver.RootElement then
+  if IsExternalEl(El) then
     begin
     begin
     if FFirstNewExt=nil then
     if FFirstNewExt=nil then
       FFirstNewExt:=Result
       FFirstNewExt:=Result
@@ -3119,22 +3164,81 @@ begin
   if aContext=nil then ;
   if aContext=nil then ;
 end;
 end;
 
 
+function TPCUWriter.IsExternalEl(El: TPasElement): boolean;
+var
+  C: TClass;
+begin
+  while El<>nil do
+    begin
+    C:=El.ClassType;
+    if C.InheritsFrom(TPasModule) then
+      exit(El<>Resolver.RootElement)
+    else if C.InheritsFrom(TPasGenericType) then
+      begin
+      if Resolver.IsSpecialized(TPasGenericType(El)) then
+        exit(true);
+      end;
+    El:=El.Parent;
+    end;
+end;
+
 procedure TPCUWriter.WriteExtRefSignature(Ref: TPCUFilerElementRef;
 procedure TPCUWriter.WriteExtRefSignature(Ref: TPCUFilerElementRef;
   aContext: TPCUWriterContext);
   aContext: TPCUWriterContext);
 
 
   procedure WriteMemberIndex(Members: TFPList; Member: TPasElement; Obj: TJSONObject);
   procedure WriteMemberIndex(Members: TFPList; Member: TPasElement; Obj: TJSONObject);
   var
   var
-    i, Index: Integer;
+    i, Index, j: Integer;
+    CurEl: TPasElement;
+    SpecItem: TPRSpecializedItem;
+    Arr: TJSONArray;
+    Param: TPasType;
   begin
   begin
+    j:=0;
+    Index:=-1;
+    SpecItem:=nil;
+
+    if (Member.CustomData is TPasGenericScope) then
+      begin
+      SpecItem:=TPasGenericScope(Member.CustomData).SpecializedFromItem;
+      if SpecItem<>nil then
+        begin
+        // member is specialized -> write generic index
+        Member:=SpecItem.GenericEl;
+        end;
+      end;
+
     for i:=0 to Members.Count-1 do
     for i:=0 to Members.Count-1 do
-      if TPasElement(Members[i])=Member then
+      begin
+      CurEl:=TPasElement(Members[i]);
+      if CurEl=Member then
         begin
         begin
-        Index:=i;
+        Index:=j;
         break;
         break;
-        end;
+        end
+      else if (CurEl is TPasGenericType)
+          and Resolver.IsSpecialized(TPasGenericType(CurEl)) then
+        // skip specialized type
+      else
+        inc(j);
+      end;
     if Index<0 then
     if Index<0 then
       RaiseMsg(20180309184111,Member);
       RaiseMsg(20180309184111,Member);
     Obj.Add('MId',Index);
     Obj.Add('MId',Index);
+
+    if SpecItem<>nil then
+      begin
+      // write specialize params
+      Obj.Add('SpecName',SpecItem.SpecializedEl.Name);
+      Arr:=TJSONArray.Create;
+      Obj.Add('Spec',Arr);
+      for i:=0 to length(SpecItem.Params)-1 do
+        begin
+        Param:=SpecItem.Params[i];
+        if Param=nil then
+          RaiseMsg(20200222110205,Member);
+        AddReferenceToArray(Arr,Param);
+        end;
+      end;
   end;
   end;
 
 
 var
 var
@@ -3169,24 +3273,44 @@ function TPCUWriter.WriteExternalReference(El: TPasElement;
   aContext: TPCUWriterContext): TPCUFilerElementRef;
   aContext: TPCUWriterContext): TPCUFilerElementRef;
 var
 var
   ParentRef, Ref: TPCUFilerElementRef;
   ParentRef, Ref: TPCUFilerElementRef;
-  Parent: TPasElement;
+  Parent, NameEl: TPasElement;
   Name: String;
   Name: String;
+  SpecItem: TPRSpecializedItem;
 begin
 begin
   Result:=nil;
   Result:=nil;
   if El=nil then exit;
   if El=nil then exit;
   // check if already written
   // check if already written
   Ref:=GetElementReference(El);
   Ref:=GetElementReference(El);
   if Ref.Obj<>nil then
   if Ref.Obj<>nil then
-    exit(Ref);
+    exit(Ref);// already written
+  if not IsExternalEl(El) then
+    RaiseMsg(20200323121033,El,GetObjName(El));
+
   //writeln('TPCUWriter.WriteExternalReference ',GetObjName(El));
   //writeln('TPCUWriter.WriteExternalReference ',GetObjName(El));
-  // check that is written
+  // write Parent first
   Parent:=El.Parent;
   Parent:=El.Parent;
-  ParentRef:=WriteExternalReference(Parent,aContext);
-  if ParentRef=nil then
-    if not (El is TPasModule) then
-      RaiseMsg(20180308174440,El,GetObjName(El));
+  if IsExternalEl(Parent) then
+    begin
+    ParentRef:=WriteExternalReference(Parent,aContext);
+    if ParentRef=nil then
+      if not (El is TPasModule) then
+        RaiseMsg(20180308174440,El,GetObjName(El));
+    end
+  else
+    begin
+    // El is external, Parent is not -> e.g. El is a specialization
+    RaiseMsg(20200328173009,El,GetObjName(El)); // ToDo
+    end;
+
   // check name
   // check name
-  Name:=Resolver.GetOverloadName(El);
+  NameEl:=El;
+  if (El.CustomData is TPasGenericScope) then
+    begin
+    SpecItem:=TPasGenericScope(El.CustomData).SpecializedFromItem;
+    if SpecItem<>nil then
+      NameEl:=SpecItem.GenericEl; // specialized -> use generic name
+    end;
+  Name:=Resolver.GetOverloadName(NameEl);
   if Name='' then
   if Name='' then
     begin
     begin
     Name:=GetDefaultRefName(El);
     Name:=GetDefaultRefName(El);
@@ -3243,7 +3367,7 @@ begin
       FLastNewExt:=nil;
       FLastNewExt:=nil;
     if Ref.Pending=nil then
     if Ref.Pending=nil then
       continue; // not used, e.g. when a child is written, its parents are
       continue; // not used, e.g. when a child is written, its parents are
-                // written too, which might still be in the queue
+                // written too, who might still be in the queue
     El:=Ref.Element;
     El:=Ref.Element;
     //writeln('TPCUWriter.WriteExternalReferences ',GetObjName(El),' ',GetElementFullPath(El));
     //writeln('TPCUWriter.WriteExternalReferences ',GetObjName(El),' ',GetElementFullPath(El));
     {$IF defined(VerbosePJUFiler) or defined(VerbosePCUFiler) or defined(VerboseUnitQueue)}
     {$IF defined(VerbosePJUFiler) or defined(VerbosePCUFiler) or defined(VerboseUnitQueue)}
@@ -3265,13 +3389,6 @@ end;
 
 
 procedure TPCUWriter.WriteElement(Obj: TJSONObject;
 procedure TPCUWriter.WriteElement(Obj: TJSONObject;
   El: TPasElement; aContext: TPCUWriterContext);
   El: TPasElement; aContext: TPCUWriterContext);
-
-  function IsSpecialized(GenEl: TPasGenericType): boolean;
-  begin
-    Result:=(GenEl.CustomData is TPasGenericScope)
-        and (TPasGenericScope(GenEl.CustomData).SpecializedFromItem<>nil);
-  end;
-
 var
 var
   C: TClass;
   C: TClass;
   Kind: TPasExprKind;
   Kind: TPasExprKind;
@@ -3391,7 +3508,7 @@ begin
     end
     end
   else if C=TPasArrayType then
   else if C=TPasArrayType then
     begin
     begin
-    if IsSpecialized(TPasGenericType(El)) then exit;
+    if Resolver.IsSpecialized(TPasGenericType(El)) then exit;
     Obj.Add('Type','ArrType');
     Obj.Add('Type','ArrType');
     WriteArrayType(Obj,TPasArrayType(El),aContext);
     WriteArrayType(Obj,TPasArrayType(El),aContext);
     end
     end
@@ -3422,13 +3539,14 @@ begin
     end
     end
   else if C=TPasRecordType then
   else if C=TPasRecordType then
     begin
     begin
-    if IsSpecialized(TPasGenericType(El)) then exit;
+    if Resolver.IsSpecialized(TPasGenericType(El)) then exit;
     Obj.Add('Type','Record');
     Obj.Add('Type','Record');
     WriteRecordType(Obj,TPasRecordType(El),aContext);
     WriteRecordType(Obj,TPasRecordType(El),aContext);
     end
     end
   else if C=TPasClassType then
   else if C=TPasClassType then
     begin
     begin
-    if IsSpecialized(TPasGenericType(El)) then exit;
+    if Resolver.IsSpecialized(TPasGenericType(El)) then
+      exit; // Note: only referenced specializations are stored
     Obj.Add('Type',PCUObjKindNames[TPasClassType(El).ObjKind]);
     Obj.Add('Type',PCUObjKindNames[TPasClassType(El).ObjKind]);
     WriteClassType(Obj,TPasClassType(El),aContext);
     WriteClassType(Obj,TPasClassType(El),aContext);
     end
     end
@@ -3439,7 +3557,7 @@ begin
     end
     end
   else if C=TPasProcedureType then
   else if C=TPasProcedureType then
     begin
     begin
-    if IsSpecialized(TPasGenericType(El)) then exit;
+    if Resolver.IsSpecialized(TPasGenericType(El)) then exit;
     Obj.Add('Type','ProcType');
     Obj.Add('Type','ProcType');
     WriteProcedureType(Obj,TPasProcedureType(El),aContext);
     WriteProcedureType(Obj,TPasProcedureType(El),aContext);
     end
     end
@@ -4763,6 +4881,43 @@ end;
 
 
 { TPCUReader }
 { TPCUReader }
 
 
+function TPCUReader.AddPendingSpecialize(GenEl: TPasGenericType;
+  ParamCount: integer): TPCUReaderPendingSpecialized;
+var
+  Param: TPCUReaderPendingSpecializedParam;
+  i: Integer;
+begin
+  Result:=TPCUReaderPendingSpecialized.Create;
+  Result.GenericEl:=GenEl;
+  if FPendingSpecialize<>nil then
+    begin
+    Result.Next:=FPendingSpecialize;
+    FPendingSpecialize.Prev:=Result;
+    end;
+  FPendingSpecialize:=Result;
+
+  Result.Params:=TFPList.Create;
+  for i:=0 to ParamCount-1 do
+    begin
+    Param:=TPCUReaderPendingSpecializedParam.Create;
+    Result.Params.Add(Param);
+    Param.Spec:=Result;
+    Param.Index:=i;
+    end;
+end;
+
+procedure TPCUReader.DeletePendingSpecialize(
+  PendSpec: TPCUReaderPendingSpecialized);
+begin
+  if FPendingSpecialize=PendSpec then
+    FPendingSpecialize:=PendSpec.Next;
+  if PendSpec.Prev<>nil then PendSpec.Prev.Next:=PendSpec.Next;
+  if PendSpec.Next<>nil then PendSpec.Next.Prev:=PendSpec.Prev;
+  PendSpec.Prev:=nil;
+  PendSpec.Next:=nil;
+  PendSpec.Free;
+end;
+
 procedure TPCUReader.Set_Variable_VarType(RefEl: TPasElement; Data: TObject);
 procedure TPCUReader.Set_Variable_VarType(RefEl: TPasElement; Data: TObject);
 var
 var
   El: TPasVariable absolute Data;
   El: TPasVariable absolute Data;
@@ -5166,7 +5321,7 @@ begin
   if RefEl is TPasType then
   if RefEl is TPasType then
     TResolvedRefCtxConstructor(Ref.Context).Typ:=TPasType(RefEl) // no AddRef
     TResolvedRefCtxConstructor(Ref.Context).Typ:=TPasType(RefEl) // no AddRef
   else
   else
-    RaiseMsg(20190222010314,Ref.Element,GetObjName(RefEl));
+    RaiseMsg(20190222010314,Ref.Element,GetObjPath(RefEl));
 end;
 end;
 
 
 procedure TPCUReader.Set_ResolvedReference_CtxAttrProc(RefEl: TPasElement;
 procedure TPCUReader.Set_ResolvedReference_CtxAttrProc(RefEl: TPasElement;
@@ -5177,7 +5332,37 @@ begin
   if RefEl is TPasConstructor then
   if RefEl is TPasConstructor then
     TResolvedRefCtxAttrProc(Ref.Context).Proc:=TPasConstructor(RefEl) // no AddRef
     TResolvedRefCtxAttrProc(Ref.Context).Proc:=TPasConstructor(RefEl) // no AddRef
   else
   else
-    RaiseMsg(20190222010821,Ref.Element,GetObjName(RefEl));
+    RaiseMsg(20190222010821,Ref.Element,GetObjPath(RefEl));
+end;
+
+procedure TPCUReader.Set_SpecializeParam(RefEl: TPasElement; Data: TObject);
+var
+  Param: TPCUReaderPendingSpecializedParam absolute Data;
+  PendSpec: TPCUReaderPendingSpecialized;
+  i: Integer;
+  RefParams, ElParams: TFPList;
+  SpecEl: TPasElement;
+begin
+  PendSpec:=Param.Spec;
+  if not (RefEl is TPasType) then
+    RaiseMsg(20200222195932,PendSpec.GenericEl,GetObjPath(RefEl));
+  Param.Element:=RefEl;
+  RefParams:=PendSpec.Params;
+  i:=RefParams.Count-1;
+  while (i>=0) and (TPCUReaderPendingSpecializedParam(RefParams[i]).Element<>nil) do
+    dec(i);
+  if i>=0 then exit;
+  // all RefParams resolved -> specialize
+  ElParams:=TFPList.Create;
+  try
+    for i:=0 to RefParams.Count-1 do
+      ElParams.Add(TPCUReaderPendingSpecializedParam(RefParams[i]).Element);
+    SpecEl:=Resolver.GetSpecializedEl(Resolver.RootElement,PendSpec.GenericEl,ElParams);
+  finally
+    ElParams.Free;
+  end;
+  // read child declarations
+  ReadExternalReferences(PendSpec.Obj,SpecEl);
 end;
 end;
 
 
 procedure TPCUReader.RaiseMsg(Id: int64; const Msg: string);
 procedure TPCUReader.RaiseMsg(Id: int64; const Msg: string);
@@ -6056,11 +6241,12 @@ end;
 procedure TPCUReader.ReadExternalMembers(El: TPasElement; Arr: TJSONArray;
 procedure TPCUReader.ReadExternalMembers(El: TPasElement; Arr: TJSONArray;
   Members: TFPList);
   Members: TFPList);
 var
 var
-  i, Index: Integer;
+  i, Index, j, k: Integer;
   Data: TJSONData;
   Data: TJSONData;
   SubObj: TJSONObject;
   SubObj: TJSONObject;
   Name: string;
   Name: string;
   ChildEl: TPasElement;
   ChildEl: TPasElement;
+  SpecArr: TJSONArray;
 begin
 begin
   for i:=0 to Arr.Count-1 do
   for i:=0 to Arr.Count-1 do
     begin
     begin
@@ -6076,12 +6262,33 @@ begin
       RaiseMsg(20180309184629,El,IntToStr(i));
       RaiseMsg(20180309184629,El,IntToStr(i));
     if (Index<0) or (Index>=Members.Count) then
     if (Index<0) or (Index>=Members.Count) then
       RaiseMsg(20180309184718,El,IntToStr(Index)+' out of bounds 0-'+IntToStr(Members.Count));
       RaiseMsg(20180309184718,El,IntToStr(Index)+' out of bounds 0-'+IntToStr(Members.Count));
-    ChildEl:=TPasElement(Members[Index]);
+    ChildEl:=nil;
+    j:=0;
+    for k:=0 to Members.Count-1 do
+      begin
+      ChildEl:=TPasElement(Members[k]);
+      if (ChildEl is TPasGenericType)
+          and Resolver.IsSpecialized(TPasGenericType(ChildEl)) then
+        // skip specialized type
+      else if Index=j then
+        break
+      else
+        inc(j);
+      end;
+    if Index>j then
+      RaiseMsg(20200222102600,El,IntToStr(Index)+' out of bounds');
     if Resolver.GetOverloadName(ChildEl)<>Name then
     if Resolver.GetOverloadName(ChildEl)<>Name then
       RaiseMsg(20180309200800,El,'Expected="'+Name+'", but found "'+Resolver.GetOverloadName(ChildEl)+'" ('+ChildEl.Name+')');
       RaiseMsg(20180309200800,El,'Expected="'+Name+'", but found "'+Resolver.GetOverloadName(ChildEl)+'" ('+ChildEl.Name+')');
 
 
     // read child declarations
     // read child declarations
-    ReadExternalReferences(SubObj,ChildEl);
+    if ReadArray(SubObj,'Spec',SpecArr,ChildEl) then
+      begin
+      if not (ChildEl is TPasGenericType) then
+        RaiseMsg(20200222163616,El,GetObjPath(ChildEl));
+      ReadExternalSpecialized(SubObj,TPasGenericType(ChildEl),SpecArr);
+      end
+    else
+      ReadExternalReferences(SubObj,ChildEl);
     end;
     end;
 end;
 end;
 
 
@@ -6134,6 +6341,31 @@ begin
     end;
     end;
 end;
 end;
 
 
+procedure TPCUReader.ReadExternalSpecialized(Obj: TJSONObject;
+  GenEl: TPasGenericType; ParamIDs: TJSONArray);
+var
+  i, Id: Integer;
+  ErrorEl: TPasElement;
+  PendSpec: TPCUReaderPendingSpecialized;
+  PendParam: TPCUReaderPendingSpecializedParam;
+begin
+  ErrorEl:=GenEl;
+  if ParamIDs.Count=0 then
+    RaiseMsg(20200222190934,ErrorEl);
+  PendSpec:=AddPendingSpecialize(GenEl,ParamIDs.Count);
+  PendSpec.Obj:=Obj;
+  for i:=0 to ParamIDs.Count-1 do
+    begin
+    if ParamIDs.Types[i]<>jtNumber then
+      RaiseMsg(20200222164327,GenEl,'i='+IntToStr(i)+' '+IntToStr(ord(ParamIDs.Types[i])));
+    Id:=ParamIDs[i].AsInteger;
+    if Id<=0 then
+      RaiseMsg(20200222191724,ErrorEl,IntToStr(i));
+    PendParam:=TPCUReaderPendingSpecializedParam(PendSpec.Params[i]);
+    PromiseSetElReference(Id,@Set_SpecializeParam,PendParam,ErrorEl);
+    end;
+end;
+
 procedure TPCUReader.ReadUsedUnitsInit(Obj: TJSONObject; Section: TPasSection;
 procedure TPCUReader.ReadUsedUnitsInit(Obj: TJSONObject; Section: TPasSection;
   aContext: TPCUReaderContext);
   aContext: TPCUReaderContext);
 // Note: can be called twice for each section if there are pending used interfaces
 // Note: can be called twice for each section if there are pending used interfaces
@@ -8082,6 +8314,9 @@ begin
   El.PackMode:=ReadPackedMode(Obj,'Packed',El);
   El.PackMode:=ReadPackedMode(Obj,'Packed',El);
   // ObjKind is the 'Type'
   // ObjKind is the 'Type'
 
 
+  if El.IsForward then
+    exit;
+
   El.InterfaceType:=ReadClassInterfaceType(Obj,'IntfType',El,citCom);
   El.InterfaceType:=ReadClassInterfaceType(Obj,'IntfType',El,citCom);
 
 
   ReadElType(Obj,'Ancestor',El,@Set_ClassType_AncestorType,aContext);
   ReadElType(Obj,'Ancestor',El,@Set_ClassType_AncestorType,aContext);
@@ -8140,6 +8375,13 @@ begin
     Resolver.FinishSpecializedClassOrRecIntf(Scope);
     Resolver.FinishSpecializedClassOrRecIntf(Scope);
     Resolver.FinishSpecializations(Scope);
     Resolver.FinishSpecializations(Scope);
     end;
     end;
+
+  if (El.GenericTemplateTypes<>nil) and (El.GenericTemplateTypes.Count>0)
+      and ReadArray(Obj,'El',Arr,El) then
+    begin
+    // has specializations used by the module itself
+    ReadExternalMembers(El,Arr,El.Members);
+    end;
 end;
 end;
 
 
 procedure TPCUReader.ReadArgument(Obj: TJSONObject; El: TPasArgument;
 procedure TPCUReader.ReadArgument(Obj: TJSONObject; El: TPasArgument;
@@ -9008,6 +9250,9 @@ begin
       FElementRefsArray[i].Free;
       FElementRefsArray[i].Free;
   FElementRefsArray:=nil;
   FElementRefsArray:=nil;
   FPendingIdentifierScopes.Clear;
   FPendingIdentifierScopes.Clear;
+  while FPendingSpecialize<>nil do
+    DeletePendingSpecialize(FPendingSpecialize);
+
   inherited Clear;
   inherited Clear;
   FInitialFlags.Clear;
   FInitialFlags.Clear;
 end;
 end;

+ 19 - 6
packages/pastojs/tests/tcfiler.pas

@@ -16,7 +16,7 @@
  Examples:
  Examples:
    ./testpas2js --suite=TTestPrecompile.TestPC_EmptyUnit
    ./testpas2js --suite=TTestPrecompile.TestPC_EmptyUnit
 }
 }
-unit tcfiler;
+unit TCFiler;
 
 
 {$mode objfpc}{$H+}
 {$mode objfpc}{$H+}
 
 
@@ -212,11 +212,24 @@ type
     procedure TestPC_GenericClass;
     procedure TestPC_GenericClass;
     procedure TestPC_GenericMethod;
     procedure TestPC_GenericMethod;
     procedure TestPC_SpecializeClassSameUnit; // ToDo
     procedure TestPC_SpecializeClassSameUnit; // ToDo
-    // ToDo: specialize
-    // ToDo: inline specialize in unit interface
-    // ToDo: inline specialize in unit implementation
-    // ToDo: inline specialize in proc decl
-    // ToDo: inline specialize in proc body
+    // ToDo: specialize local generic type in unit interface
+    // ToDo: specialize local generic type in unit implementation
+    // ToDo: specialize local generic type in proc decl
+    // ToDo: specialize local generic type in proc body
+    // ToDo: inline specialize local generic type in unit interface
+    // ToDo: inline specialize local generic type in unit implementation
+    // ToDo: inline specialize local generic type in proc decl
+    // ToDo: inline specialize local generic type in proc body
+    // ToDo: specialize extern generic type in unit interface
+    // ToDo: specialize extern generic type in unit implementation
+    // ToDo: specialize extern generic type in proc decl
+    // ToDo: specialize extern generic type in proc body
+    // ToDo: inline specialize extern generic type in unit interface
+    // ToDo: inline specialize extern generic type in unit implementation
+    // ToDo: inline specialize extern generic type in proc decl
+    // ToDo: inline specialize extern generic type in proc body
+    // ToDo: half specialize TBird<T> = class a: TAnt<word,T>; end;
+    // ToDo: no specialize: TBird<T> = class a: TBird<T>; end;
     // ToDo: constraints
     // ToDo: constraints
 
 
     procedure TestPC_UseUnit;
     procedure TestPC_UseUnit;

+ 1 - 0
packages/pastojs/tests/testpas2js.lpi

@@ -72,6 +72,7 @@
       <Unit7>
       <Unit7>
         <Filename Value="tcfiler.pas"/>
         <Filename Value="tcfiler.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
+        <UnitName Value="TCFiler"/>
       </Unit7>
       </Unit7>
       <Unit8>
       <Unit8>
         <Filename Value="../src/pas2jsfiler.pp"/>
         <Filename Value="../src/pas2jsfiler.pp"/>