Bladeren bron

fcl-passrc: resolver: specialize proc implementation

git-svn-id: trunk@42578 -
Mattias Gaertner 6 jaren geleden
bovenliggende
commit
16752a8fba

+ 579 - 184
packages/fcl-passrc/src/pasresolver.pp

@@ -687,6 +687,7 @@ type
     Step: TPSSpecializeStep;
     FirstSpecialize: TPasElement;
     Params: TPasTypeArray;
+    ImplProcs: TFPList;
     destructor Destroy; override;
     property SpecializedType: TPasGenericType read FSpecializedType write SetSpecializedType;
   end;
@@ -1019,7 +1020,8 @@ type
   end;
 
   TPasProcedureScopeFlag = (
-    ppsfIsGroupOverload // mode objfpc: one overload is enough for all procs in same scope
+    ppsfIsGroupOverload, // mode objfpc: one overload is enough for all procs in same scope
+    ppsfIsSpecialized
     );
   TPasProcedureScopeFlags = set of TPasProcedureScopeFlag;
 
@@ -1712,12 +1714,20 @@ type
     function CreateSpecializedType(El: TPasSpecializeType;
       const ParamsResolved: TPasTypeArray): TPSSpecializedItem; virtual;
     function InitSpecializeScopes(El: TPasElement): integer; virtual;
-    procedure SpecializeInterface(GenericType: TPasGenericType; SpecializedItem: TPSSpecializedItem); virtual;
+    procedure SpecializeGenTypeIntf(GenericType: TPasGenericType; SpecializedItem: TPSSpecializedItem); virtual;
+    procedure SpecializeGenTypeImpl(GenericType: TPasGenericType; SpecializedItem: TPSSpecializedItem); virtual;
     procedure SpecializeMembers(GenMembersType, SpecMembersType: TPasMembersType); virtual;
     procedure SpecializeElement(GenEl, SpecEl: TPasElement);
     procedure SpecializePasElementProperties(GenEl, SpecEl: TPasElement);
     procedure SpecializeVariable(GenEl, SpecEl: TPasVariable);
     procedure SpecializeElType(GenEl, SpecEl: TPasElement; GenElType: TPasType; var SpecElType: TPasType);
+    procedure SpecializeElExpr(GenEl, SpecEl: TPasElement; GenElExpr: TPasExpr; var SpecElExpr: TPasExpr);
+    procedure SpecializeProcedure(GenEl, SpecEl: TPasProcedure);
+    procedure SpecializeProcedureType(GenEl, SpecEl: TPasProcedureType);
+    procedure SpecializeProcedureBody(GenEl, SpecEl: TProcedureBody);
+    procedure SpecializeDeclarations(GenEl, SpecEl: TPasDeclarations);
+    procedure SpecializeArgument(GenEl, SpecEl: TPasArgument);
+    procedure SpecializeImplBlock(GenEl, SpecEl: TPasImplBlock);
   protected
     // custom types (added by descendant resolvers)
     function CheckAssignCompatibilityCustom(
@@ -2898,7 +2908,16 @@ begin
 end;
 
 destructor TPSSpecializedItem.Destroy;
+var
+  i: Integer;
 begin
+  if ImplProcs<>nil then
+    begin
+    for i:=0 to ImplProcs.Count-1 do
+      TPasElement(ImplProcs[i]).Release{$IFDEF CheckPasTreeRefCount}('CreateElement'){$ENDIF};
+    ImplProcs.Free;
+    ImplProcs:=nil;
+    end;
   SpecializedType:=nil;
   inherited Destroy;
 end;
@@ -5451,7 +5470,8 @@ begin
   C:=El.ClassType;
   if C=TPasClassType then
     begin
-    if TPasClassType(El).IsForward and (TPasClassType(El).CustomData=nil) then
+    if TPasClassType(El).IsForward
+        and not (TPasClassType(El).CustomData is TResolvedReference) then
       RaiseMsg(20170216151534,nForwardTypeNotResolved,sForwardTypeNotResolved,[El.Name],El);
     end
   else if (C=TPasClassOfType) then
@@ -5895,7 +5915,7 @@ begin
         for j:=0 to FScopeCount-1 do
           writeln('  ',i,'/',FScopeCount,' ',GetObjName(FScopes[i]));
         {$ENDIF}
-        SpecializeInterface(El,SpecializedItem);
+        SpecializeGenTypeIntf(El,SpecializedItem);
 
         {$IFDEF VerbosePasResolver}
         writeln('TPasResolver.FinishClassType Finished specialize interface: ',GetObjName(SpecializedItem.SpecializedType),' ',ScopeCount,' FStashScopeCount=',FStashScopeCount);
@@ -6296,12 +6316,12 @@ begin
   if (Proc<>nil) and (Proc.ProcType=El) then
     begin
     // finished header of a procedure declaration
-    // -> search the best fitting proc
     CheckTopScope(FScopeClass_Proc);
     {$IFDEF VerbosePasResolver}
     writeln('TPasResolver.FinishProcedureHeader El=',GetTreeDbg(El),' ',GetElementSourcePosStr(El),' IsForward=',Proc.IsForward,' Parent=',GetObjName(El.Parent));
     {$ENDIF}
     ProcName:=Proc.Name;
+    ProcScope:=Proc.CustomData as TPasProcedureScope;
 
     if El is TPasFunctionType then
       CheckUseAsType(TPasFunctionType(El).ResultEl.ResultType,20190123095743,TPasFunctionType(El).ResultEl);
@@ -6484,7 +6504,7 @@ begin
         and not IsValidIdent(ProcName) then
       RaiseNotYetImplemented(20160922163407,El);
 
-    if El is TPasFunctionType then
+    if (El is TPasFunctionType) and not (ppsfIsSpecialized in ProcScope.Flags) then
       EmitTypeHints(TPasFunctionType(El).ResultEl,TPasFunctionType(El).ResultEl.ResultType);
 
     if Proc.PublicName<>nil then
@@ -6519,49 +6539,50 @@ begin
     // finish interface/implementation/nested procedure
     if (ProcName<>'') and ProcNeedsBody(Proc) then
       begin
-      // check if there is a forward declaration
-      //writeln('TPasResolver.FinishProcedureType ',GetObjName(TopScope),' ',GetObjName(Scopes[ScopeCount-2]));
-      ParentScope:=GetParentLocalScope as TPasIdentifierScope;
-      //writeln('TPasResolver.FinishProcedureType FindForward2 ParentScope=',GetObjName(ParentScope),'=',GetObjName(ParentScope.Element),' Proc=',GetObjName(Proc),' at ',GetElementSourcePosStr(Proc));
-      DeclProc:=FindProcSameSignature(ProcName,Proc,ParentScope,true);
-      //writeln('TPasResolver.FinishProcedureType FindForward3 DeclProc=',GetObjName(DeclProc),' Proc.Parent=',GetObjName(Proc.Parent));
-      //if DeclProc<>nil then writeln('TPasResolver.FinishProcedureType DeclProc at ',GetElementSourcePosStr(DeclProc));
-      if (DeclProc=nil) and (Proc.Parent.ClassType=TImplementationSection) then
-        DeclProc:=FindProcSameSignature(ProcName,Proc,
-          (Proc.GetModule.InterfaceSection.CustomData) as TPasIdentifierScope,true);
-      //writeln('TPasResolver.FinishProcedureType FindForward4 ',GetObjName(DeclProc),' at ',GetElementSourcePosStr(DeclProc));
-      if (DeclProc<>nil) then
-        begin
-        if ProcNeedsImplProc(DeclProc) then
+      if not (ppsfIsSpecialized in ProcScope.Flags) then
+        begin
+        // check if there is a forward declaration
+        //writeln('TPasResolver.FinishProcedureType ',GetObjName(TopScope),' ',GetObjName(Scopes[ScopeCount-2]));
+        ParentScope:=GetParentLocalScope as TPasIdentifierScope;
+        //writeln('TPasResolver.FinishProcedureType FindForward2 ParentScope=',GetObjName(ParentScope),'=',GetObjName(ParentScope.Element),' Proc=',GetObjName(Proc),' at ',GetElementSourcePosStr(Proc));
+        DeclProc:=FindProcSameSignature(ProcName,Proc,ParentScope,true);
+        //writeln('TPasResolver.FinishProcedureType FindForward3 DeclProc=',GetObjName(DeclProc),' Proc.Parent=',GetObjName(Proc.Parent));
+        //if DeclProc<>nil then writeln('TPasResolver.FinishProcedureType DeclProc at ',GetElementSourcePosStr(DeclProc));
+        if (DeclProc=nil) and (Proc.Parent.ClassType=TImplementationSection) then
+          DeclProc:=FindProcSameSignature(ProcName,Proc,
+            (Proc.GetModule.InterfaceSection.CustomData) as TPasIdentifierScope,true);
+        //writeln('TPasResolver.FinishProcedureType FindForward4 ',GetObjName(DeclProc),' at ',GetElementSourcePosStr(DeclProc));
+        if (DeclProc<>nil) then
           begin
-          // found forward declaration
-          DeclProcScope:=DeclProc.CustomData as TPasProcedureScope;
-          if DeclProcScope.ImplProc<>nil then
-            RaiseMsg(20180318222430,nDuplicateIdentifier,sDuplicateIdentifier,
-              [DeclProcScope.ImplProc.Name,GetElementSourcePosStr(DeclProcScope.ImplProc)],Proc);
-          // connect
-          {$IFDEF VerbosePasResolver}
-          writeln('TPasResolver.FinishProcedureHeader forward found: Proc2=',GetTreeDbg(DeclProc),' ',GetElementSourcePosStr(DeclProc),' IsForward=',DeclProc.IsForward,' Parent=',GetObjName(DeclProc.Parent));
-          {$ENDIF}
-          CheckProcSignatureMatch(DeclProc,Proc,true);
-          DeclProcScope.ImplProc:=Proc;
-          ProcScope:=Proc.CustomData as TPasProcedureScope;
-          ProcScope.DeclarationProc:=DeclProc;
-          // remove ImplProc from scope
-          (ParentScope as TPasIdentifierScope).RemoveLocalIdentifier(Proc);
-          // replace arguments with declaration arguments
-          ReplaceProcScopeImplArgsWithDeclArgs(ProcScope);
-          exit;
-          end
-        else
-          RaiseMsg(20180318220543,nDuplicateIdentifier,sDuplicateIdentifier,
-            [DeclProc.Name,GetElementSourcePosStr(DeclProc)],Proc);
+          if ProcNeedsImplProc(DeclProc) then
+            begin
+            // found forward declaration
+            DeclProcScope:=DeclProc.CustomData as TPasProcedureScope;
+            if DeclProcScope.ImplProc<>nil then
+              RaiseMsg(20180318222430,nDuplicateIdentifier,sDuplicateIdentifier,
+                [DeclProcScope.ImplProc.Name,GetElementSourcePosStr(DeclProcScope.ImplProc)],Proc);
+            // connect
+            {$IFDEF VerbosePasResolver}
+            writeln('TPasResolver.FinishProcedureHeader forward found: Proc2=',GetTreeDbg(DeclProc),' ',GetElementSourcePosStr(DeclProc),' IsForward=',DeclProc.IsForward,' Parent=',GetObjName(DeclProc.Parent));
+            {$ENDIF}
+            CheckProcSignatureMatch(DeclProc,Proc,true);
+            DeclProcScope.ImplProc:=Proc;
+            ProcScope.DeclarationProc:=DeclProc;
+            // remove ImplProc from scope
+            (ParentScope as TPasIdentifierScope).RemoveLocalIdentifier(Proc);
+            // replace arguments with declaration arguments
+            ReplaceProcScopeImplArgsWithDeclArgs(ProcScope);
+            exit;
+            end
+          else
+            RaiseMsg(20180318220543,nDuplicateIdentifier,sDuplicateIdentifier,
+              [DeclProc.Name,GetElementSourcePosStr(DeclProc)],Proc);
+          end;
         end;
       end
     else
       begin
       // forward declaration
-      ProcScope:=Proc.CustomData as TPasProcedureScope;
       // ToDo: store the scanner flags *before* it has parsed the token after the proc
       StoreScannerFlagsInProc(ProcScope);
       end;
@@ -6727,22 +6748,8 @@ begin
     RaiseMsg(20170216151717,nInvalidXModifierY,sInvalidXModifierY,[GetElementTypeName(ImplProc),'export'],ImplProc);
 
   ProcName:=ImplProc.Name;
-  {$IFDEF VerbosePasResolver}
-  writeln('TPasResolver.FinishMethodBodyHeader searching declaration "',ProcName,'" ...');
-  {$ENDIF}
-
-  repeat
-    p:=Pos('.',ProcName);
-    if p<1 then break;
-    Delete(ProcName,1,p);
-  until false;
-
-  // search ImplProc in class
-  if not IsValidIdent(ProcName) then
-    RaiseNotYetImplemented(20160922163421,ImplProc.ProcType);
-
-  // search proc in class/record
   ImplProcScope:=ImplProc.CustomData as TPasProcedureScope;
+
   ClassOrRecScope:=ImplProcScope.ClassRecScope;
   if ClassOrRecScope=nil then
     RaiseInternalError(20161013172346);
@@ -6750,32 +6757,61 @@ begin
   if ImplProcScope.GroupScope=nil then
     RaiseInternalError(20190120135017);
 
-  if ImplProc.ClassType=TPasClassConstructor then
-    DeclProc:=ClassOrRecScope.ClassConstructor
-  else if ImplProc.ClassType=TPasClassDestructor then
-    DeclProc:=ClassOrRecScope.ClassDestructor
+  repeat
+    p:=Pos('.',ProcName);
+    if p<1 then break;
+    Delete(ProcName,1,p);
+  until false;
+
+  if ImplProcScope.DeclarationProc=nil then
+    begin
+    {$IFDEF VerbosePasResolver}
+    writeln('TPasResolver.FinishMethodImplHeader searching declaration "',ImplProc.Name,'" ...');
+    {$ENDIF}
+    // search ImplProc in class
+    if not IsValidIdent(ProcName) then
+      RaiseNotYetImplemented(20160922163421,ImplProc.ProcType);
+
+    // search proc in class/record
+    if ImplProc.ClassType=TPasClassConstructor then
+      DeclProc:=ClassOrRecScope.ClassConstructor
+    else if ImplProc.ClassType=TPasClassDestructor then
+      DeclProc:=ClassOrRecScope.ClassDestructor
+    else
+      DeclProc:=FindProcSameSignature(ProcName,ImplProc,ClassOrRecScope,false);
+    if DeclProc=nil then
+      RaiseIdentifierNotFound(20170216151720,ImplProc.Name,ImplProc.ProcType);
+    DeclProcScope:=DeclProc.CustomData as TPasProcedureScope;
+    ImplProc.ProcType.IsOfObject:=DeclProc.ProcType.IsOfObject;
+
+    // connect method declaration and body
+    if DeclProcScope.ImplProc<>nil then
+      RaiseMsg(20180212094546,nDuplicateIdentifier,sDuplicateIdentifier,
+        [DeclProcScope.ImplProc.Name,GetElementSourcePosStr(DeclProcScope.ImplProc)],
+        ImplProc);
+    if DeclProc.IsAbstract then
+      RaiseMsg(20170216151722,nAbstractMethodsMustNotHaveImplementation,sAbstractMethodsMustNotHaveImplementation,[],ImplProc);
+    if DeclProc.IsExternal then
+      RaiseXExpectedButYFound(20170216151725,'method','external method',ImplProc);
+    CheckProcSignatureMatch(DeclProc,ImplProc,true);
+    ImplProcScope.DeclarationProc:=DeclProc;
+    DeclProcScope.ImplProc:=ImplProc;
+
+    // replace arguments in scope with declaration arguments
+    ReplaceProcScopeImplArgsWithDeclArgs(ImplProcScope);
+    end
+  else if ppsfIsSpecialized in ImplProcScope.Flags then
+    begin
+    {$IFDEF VerbosePasResolver}
+    writeln('TPasResolver.FinishMethodImplHeader specialized "',ImplProc.Name,'" ...');
+    {$ENDIF}
+    DeclProc:=ImplProcScope.DeclarationProc;
+    DeclProcScope:=DeclProc.CustomData as TPasProcedureScope;
+    if DeclProcScope.ImplProc<>ImplProc then
+      RaiseNotYetImplemented(20190804182220,ImplProc);
+    end
   else
-    DeclProc:=FindProcSameSignature(ProcName,ImplProc,ClassOrRecScope,false);
-  if DeclProc=nil then
-    RaiseIdentifierNotFound(20170216151720,ImplProc.Name,ImplProc.ProcType);
-  DeclProcScope:=DeclProc.CustomData as TPasProcedureScope;
-  ImplProc.ProcType.IsOfObject:=DeclProc.ProcType.IsOfObject;
-
-  // connect method declaration and body
-  if DeclProcScope.ImplProc<>nil then
-    RaiseMsg(20180212094546,nDuplicateIdentifier,sDuplicateIdentifier,
-      [DeclProcScope.ImplProc.Name,GetElementSourcePosStr(DeclProcScope.ImplProc)],
-      ImplProc);
-  if DeclProc.IsAbstract then
-    RaiseMsg(20170216151722,nAbstractMethodsMustNotHaveImplementation,sAbstractMethodsMustNotHaveImplementation,[],ImplProc);
-  if DeclProc.IsExternal then
-    RaiseXExpectedButYFound(20170216151725,'method','external method',ImplProc);
-  CheckProcSignatureMatch(DeclProc,ImplProc,true);
-  ImplProcScope.DeclarationProc:=DeclProc;
-  DeclProcScope.ImplProc:=ImplProc;
-
-  // replace arguments in scope with declaration arguments
-  ReplaceProcScopeImplArgsWithDeclArgs(ImplProcScope);
+    RaiseNotYetImplemented(20190804181222,ImplProc);
 
   if not DeclProc.IsStatic then
     begin
@@ -6828,7 +6864,7 @@ begin
     end;
 
   {$IFDEF VerbosePasResolver}
-  writeln('TPasResolver.FinishMethodBodyHeader END of searching proc "',ImplProc.Name,'" ...');
+  writeln('TPasResolver.FinishMethodBodyHeader END "',ImplProc.Name,'" ...');
   {$ENDIF}
 end;
 
@@ -10725,6 +10761,8 @@ var
   DeclEl: TPasElement;
   Proc: TPasProcedure;
   aClassOrRec: TPasMembersType;
+  ClassOrRecScope: TPasClassOrRecordScope;
+  SpecializedTypes: TObjectList;
 begin
   if IsElementSkipped(El) then exit;
   if El is TPasDeclarations then
@@ -10745,9 +10783,19 @@ begin
   else if El is TPasMembersType then
     begin
     aClassOrRec:=TPasMembersType(El);
-    if (aClassOrRec is TPasClassType)
-        and (TPasClassType(aClassOrRec).ObjKind in [okInterface,okDispInterface])
-        then exit;
+    if (aClassOrRec is TPasClassType) then
+      begin
+      if (TPasClassType(aClassOrRec).ObjKind in [okInterface,okDispInterface]) then
+        exit;
+      if TPasClassType(aClassOrRec).IsForward then
+        exit;
+      end;
+    ClassOrRecScope:=aClassOrRec.CustomData as TPasClassOrRecordScope;
+    if ClassOrRecScope.SpecializedFrom<>nil then
+      exit;
+    // finish implementation of (generic) class/record
+    if ClassOrRecScope.GenericStep<>psgsInterfaceParsed then
+      RaiseNotYetImplemented(20190804115324,El);
     for i:=0 to aClassOrRec.Members.Count-1 do
       begin
       DeclEl:=TPasElement(aClassOrRec.Members[i]);
@@ -10760,6 +10808,13 @@ begin
             [GetElementTypeName(Proc),Proc.Name],Proc);
         end;
       end;
+    ClassOrRecScope.GenericStep:=psgsImplementationParsed;
+
+    // finish specializations
+    SpecializedTypes:=ClassOrRecScope.SpecializedTypes;
+    if SpecializedTypes<>nil then
+      for i:=0 to SpecializedTypes.Count-1 do
+        SpecializeGenTypeImpl(aClassOrRec,TPSSpecializedItem(SpecializedTypes[i]));
     end;
 end;
 
@@ -10820,6 +10875,10 @@ begin
     FinishSection(TPasSectionScope(TopScope).Element as TPasSection);
   if TopScope is TPasModuleScope then
     TPasModuleScope(TopScope).BoolSwitches:=CurrentParser.Scanner.CurrentBoolSwitches;
+  {$IFDEF VerbosePasResolver}
+  if FPendingForwardProcs.IndexOf(El)=0 then
+    RaiseNotYetImplemented(20190804114718,El);
+  {$ENDIF}
   FPendingForwardProcs.Add(El); // check forward declarations at the end
   Scope:=TPasSectionScope(PushScope(El,ScopeClass_Section));
   Scope.BoolSwitches:=CurrentParser.Scanner.CurrentBoolSwitches;
@@ -10853,6 +10912,10 @@ begin
     RaiseInvalidScopeForElement(20160922163508,El);
   if El.Name<>'' then begin
     AddIdentifier(TPasIdentifierScope(TopScope),El.Name,El,pikSimple);
+    {$IFDEF VerbosePasResolver}
+    if FPendingForwardProcs.IndexOf(El)=0 then
+      RaiseNotYetImplemented(20190804114737,El);
+    {$ENDIF}
     FPendingForwardProcs.Add(El); // check forward declarations at the end
   end;
 
@@ -10931,6 +10994,10 @@ begin
   else
     AddIdentifier(CurScope,El.Name,El,pikSimple);
 
+  {$IFDEF VerbosePasResolver}
+  if FPendingForwardProcs.IndexOf(El)>=0 then
+    RaiseNotYetImplemented(20190804114746,El);
+  {$ENDIF}
   FPendingForwardProcs.Add(El); // check forward declarations at the end
 end;
 
@@ -11109,107 +11176,129 @@ begin
   // Note: El.ProcType is nil !  It is parsed later.
 
   HasDot:=Pos('.',ProcName)>1;
-  IsClassConDestructor:=(El.ClassType=TPasClassConstructor)
-      or (El.ClassType=TPasClassDestructor);
-  if (not HasDot) and IsClassConDestructor then
-    begin
-    if ProcName='' then
-      RaiseNotYetImplemented(20181231145302,El);
-    if not (LocalScope is TPasClassOrRecordScope) then
-      RaiseInvalidScopeForElement(20181231143831,El);
-    ClassOrRecScope:=TPasClassOrRecordScope(LocalScope);
-    if El.ClassType=TPasClassConstructor then
-      AddClassConDestructor(ClassOrRecScope,TPasProcedure(ClassOrRecScope.ClassConstructor))
-    else
-      AddClassConDestructor(ClassOrRecScope,TPasProcedure(ClassOrRecScope.ClassDestructor));
-    end;
+  if El.CustomData is TPasProcedureScope then
+    begin
+    // adding a specialized implementation proc
+    ProcScope:=TPasProcedureScope(El.CustomData);
+    ClassOrRecScope:=ProcScope.ClassRecScope;
+    if ClassOrRecScope=nil then
+      RaiseNotYetImplemented(20190804175307,El);
+    ClassOrRecType:=TPasMembersType(ClassOrRecScope.Element);
+    if GetTypeParameterCount(ClassOrRecType)>0 then
+      RaiseNotYetImplemented(20190804175518,El);
+    if ProcScope.GroupScope<>nil then
+      RaiseNotYetImplemented(20190804175451,El);
 
-  if (not HasDot) and (ProcName<>'')
-      and not IsClassConDestructor // the name of a class con/destructor is irrelevant
-  then
+    PushScope(ProcScope);
+    end
+  else
     begin
-    // add proc name to scope
-    AddIdentifier(TPasIdentifierScope(CurScope),ProcName,El,pikProc);
-    end;
+    IsClassConDestructor:=(El.ClassType=TPasClassConstructor)
+        or (El.ClassType=TPasClassDestructor);
+    if (not HasDot) and IsClassConDestructor then
+      begin
+      if ProcName='' then
+        RaiseNotYetImplemented(20181231145302,El);
+      if not (LocalScope is TPasClassOrRecordScope) then
+        RaiseInvalidScopeForElement(20181231143831,El);
+      ClassOrRecScope:=TPasClassOrRecordScope(LocalScope);
+      if El.ClassType=TPasClassConstructor then
+        AddClassConDestructor(ClassOrRecScope,TPasProcedure(ClassOrRecScope.ClassConstructor))
+      else
+        AddClassConDestructor(ClassOrRecScope,TPasProcedure(ClassOrRecScope.ClassDestructor));
+      end;
 
-  ProcScope:=TPasProcedureScope(PushScope(El,FScopeClass_Proc));
-  ProcScope.ModeSwitches:=CurrentParser.CurrentModeswitches;
-  if HasDot then
-    begin
-    // method implementation -> search class
-    {$IFDEF VerbosePasResolver}
-    writeln('TPasResolver.AddProcedure searching class of "',ProcName,'" ...');
-    {$ENDIF}
-    ClassOrRecType:=nil;
-    repeat
-      p:=Pos('.',ProcName);
-      if p<1 then
-        begin
-        if ClassOrRecType=nil then
-          RaiseInternalError(20161013170829);
-        break;
-        end;
-      aClassName:=LeftStr(ProcName,p-1);
-      Delete(ProcName,1,p);
+    if (not HasDot) and (ProcName<>'')
+        and not IsClassConDestructor // the name of a class con/destructor is irrelevant and cannot be referenced
+    then
+      begin
+      // add proc name to scope
+      AddIdentifier(TPasIdentifierScope(CurScope),ProcName,El,pikProc);
+      end;
+
+    ProcScope:=TPasProcedureScope(PushScope(El,FScopeClass_Proc));
+    ProcScope.ModeSwitches:=CurrentParser.CurrentModeswitches;
+    if HasDot then
+      begin
+      // method implementation -> search class
       {$IFDEF VerbosePasResolver}
-      writeln('TPasResolver.AddProcedure searching class "',aClassName,'" ProcName="',ProcName,'" ...');
+      writeln('TPasResolver.AddProcedure searching class of "',ProcName,'" ...');
       {$ENDIF}
-      if not IsValidIdent(aClassName) then
-        RaiseNotYetImplemented(20161013170844,El);
+      ClassOrRecType:=nil;
+      repeat
+        p:=Pos('.',ProcName);
+        if p<1 then
+          begin
+          if ClassOrRecType=nil then
+            RaiseInternalError(20161013170829);
+          break;
+          end;
+        aClassName:=LeftStr(ProcName,p-1);
+        Delete(ProcName,1,p);
+        {$IFDEF VerbosePasResolver}
+        writeln('TPasResolver.AddProcedure searching class "',aClassName,'" ProcName="',ProcName,'" ...');
+        {$ENDIF}
+        if not IsValidIdent(aClassName) then
+          RaiseNotYetImplemented(20161013170844,El);
 
-      if ClassOrRecType<>nil then
-        begin
-        ClassOrRecScope:=TPasClassOrRecordScope(ClassOrRecType.CustomData);
-        Identifier:=ClassOrRecScope.FindLocalIdentifier(aClassName);
-        if Identifier=nil then
-          RaiseIdentifierNotFound(20180430130635,aClassName,El)
+        if ClassOrRecType<>nil then
+          begin
+          ClassOrRecScope:=TPasClassOrRecordScope(ClassOrRecType.CustomData);
+          Identifier:=ClassOrRecScope.FindLocalIdentifier(aClassName);
+          if Identifier=nil then
+            RaiseIdentifierNotFound(20180430130635,aClassName,El)
+          else
+            CurEl:=Identifier.Element;
+          end
         else
-          CurEl:=Identifier.Element;
-        end
-      else
-        CurEl:=FindElementWithoutParams(aClassName,El,false);
+          CurEl:=FindElementWithoutParams(aClassName,El,false);
 
-      if not (CurEl is TPasMembersType) then
-        begin
-        aClassName:=LeftStr(El.Name,length(El.Name)-length(ProcName)-1);
-        {$IFDEF VerbosePasResolver}
-        writeln('TPasResolver.AddProcedure searching class "',aClassName,'" ProcName="',ProcName,'" found: '+GetObjName(CurEl));
-        {$ENDIF}
-        RaiseXExpectedButYFound(20170216152557,
-          'class',aClassname+':'+GetElementTypeName(CurEl),El);
-        end;
-      ClassOrRecType:=TPasMembersType(CurEl);
-      if ClassOrRecType is TPasClassType then
-        begin
-        if not (TPasClassType(ClassOrRecType).ObjKind in
-            ([okClass]+okAllHelpers)) then
+        if not (CurEl is TPasMembersType) then
           begin
           aClassName:=LeftStr(El.Name,length(El.Name)-length(ProcName)-1);
-          RaiseXExpectedButYFound(20180321161722,
+          {$IFDEF VerbosePasResolver}
+          writeln('TPasResolver.AddProcedure searching class "',aClassName,'" ProcName="',ProcName,'" found: '+GetObjName(CurEl));
+          {$ENDIF}
+          RaiseXExpectedButYFound(20170216152557,
             'class',aClassname+':'+GetElementTypeName(CurEl),El);
-          end
-        end;
-      if ClassOrRecType.GetModule<>El.GetModule then
-        begin
-        aClassName:=LeftStr(El.Name,length(El.Name)-length(ProcName)-1);
-        RaiseMsg(20180211230432,nMethodClassXInOtherUnitY,sMethodClassXInOtherUnitY,
-          [aClassName,ClassOrRecType.GetModule.Name],El);
-        end;
-    until false;
+          end;
+        ClassOrRecType:=TPasMembersType(CurEl);
+        if ClassOrRecType is TPasClassType then
+          begin
+          if not (TPasClassType(ClassOrRecType).ObjKind in
+              ([okClass]+okAllHelpers)) then
+            begin
+            aClassName:=LeftStr(El.Name,length(El.Name)-length(ProcName)-1);
+            RaiseXExpectedButYFound(20180321161722,
+              'class',aClassname+':'+GetElementTypeName(CurEl),El);
+            end
+          end;
+        if ClassOrRecType.GetModule<>El.GetModule then
+          begin
+          aClassName:=LeftStr(El.Name,length(El.Name)-length(ProcName)-1);
+          RaiseMsg(20180211230432,nMethodClassXInOtherUnitY,sMethodClassXInOtherUnitY,
+            [aClassName,ClassOrRecType.GetModule.Name],El);
+          end;
+      until false;
 
-    if not IsValidIdent(ProcName) then
-      RaiseNotYetImplemented(20161013170956,El);
+      if not IsValidIdent(ProcName) then
+        RaiseNotYetImplemented(20161013170956,El);
 
-    ProcScope.VisibilityContext:=ClassOrRecType;
-    ProcScope.ClassRecScope:=NoNil(ClassOrRecType.CustomData) as TPasClassOrRecordScope;
+      ProcScope.VisibilityContext:=ClassOrRecType;
+      ProcScope.ClassRecScope:=NoNil(ClassOrRecType.CustomData) as TPasClassOrRecordScope;
+      end; // HasDot=true
+    end;
+
+  if HasDot then
+    begin
+    // create GroupScope
     ProcScope.GroupScope:=CreateGroupScope(ClassOrRecType);
     while ClassOrRecType.Parent is TPasMembersType do
       begin
       ClassOrRecType:=TPasMembersType(ClassOrRecType.Parent);
       GroupScope_AddTypeAndAncestors(ProcScope.GroupScope,ClassOrRecType);
       end;
-
-    end;// HasDot=true
+    end;
 end;
 
 procedure TPasResolver.AddArgument(El: TPasArgument);
@@ -14198,7 +14287,7 @@ function TPasResolver.CheckSpecializeConstraints(El: TPasSpecializeType
 var
   Params, GenericTemplateList: TFPList;
   i, j: Integer;
-  P: TPasElement;
+  P, ParentEl: TPasElement;
   ParamType, DestType: TPasType;
   ResolvedEl, ResolvedConstraint: TPasResolverResult;
   GenTempl: TPasGenericTemplateType;
@@ -14294,6 +14383,19 @@ begin
       end;
       end;
     end;
+
+  if Result then
+    begin
+    // check ParentEl types are specialized
+    ParentEl:=DestType.Parent;
+    while ParentEl<>nil do
+      begin
+      if (ParentEl is TPasGenericType)
+          and (GetTypeParameterCount(TPasGenericType(ParentEl))>0) then
+        exit(false); // parent is not specialized
+      ParentEl:=ParentEl.Parent;
+      end;
+    end;
 end;
 
 function TPasResolver.CreateSpecializedType(El: TPasSpecializeType;
@@ -14357,7 +14459,7 @@ begin
     NewEl.Release{$IFDEF CheckPasTreeRefCount}('CreateElement'){$ENDIF}; // fix refcount
 
   if GenScope.GenericStep>=psgsInterfaceParsed then
-    SpecializeInterface(GenericType,Result);
+    SpecializeGenTypeIntf(GenericType,Result);
 
   {$IFDEF VerbosePasResolver}
   writeln('TPasResolver.CreateSpecializedType FinishTypeDef:');
@@ -14371,6 +14473,9 @@ begin
   for i:=0 to FScopeCount-1 do
     writeln('  ',i,'/',FScopeCount,' ',GetObjName(FScopes[i]));
   {$ENDIF}
+
+  if GenScope.GenericStep>=psgsImplementationParsed then
+    SpecializeGenTypeImpl(GenericType,Result);
 end;
 
 function TPasResolver.InitSpecializeScopes(El: TPasElement): integer;
@@ -14423,7 +14528,7 @@ begin
   PushParentScopes(El.Parent);
 end;
 
-procedure TPasResolver.SpecializeInterface(GenericType: TPasGenericType;
+procedure TPasResolver.SpecializeGenTypeIntf(GenericType: TPasGenericType;
   SpecializedItem: TPSSpecializedItem);
 var
   GenericTemplateTypes: TFPList;
@@ -14434,7 +14539,7 @@ var
   HeaderScope: TPasClassHeaderScope;
 begin
   if SpecializedItem.Step<>psssNone then
-    RaiseNotYetImplemented(20190801224849,GenericType,GetObjName(SpecializedItem.SpecializedType));
+    exit;
   SpecializedItem.Step:=psssInterfaceBuilding;
   GenericTemplateTypes:=GenericType.GenericTemplateTypes;
   SpecType:=SpecializedItem.SpecializedType;
@@ -14463,7 +14568,8 @@ begin
       RaiseNotYetImplemented(20190730182858,GenClassType);
     NewClassType.IsExternal:=GenClassType.IsExternal;
     NewClassType.IsShortDefinition:=GenClassType.IsShortDefinition;
-    // ToDo GUIDExpr
+    if GenClassType.GUIDExpr<>nil then
+      SpecializeElExpr(GenClassType,NewClassType,GenClassType.GUIDExpr,NewClassType.GUIDExpr);
     NewClassType.Modifiers.Assign(GenClassType.Modifiers);
     // ToDo NewClassType.Interfaces
     NewClassType.ExternalNameSpace:=GenClassType.ExternalNameSpace;
@@ -14494,6 +14600,113 @@ begin
   FinishTypeDef(SpecType);
 end;
 
+procedure TPasResolver.SpecializeGenTypeImpl(GenericType: TPasGenericType;
+  SpecializedItem: TPSSpecializedItem);
+var
+  SpecType: TPasGenericType;
+  GenClassOrRec, SpecClassOrRec: TPasMembersType;
+  GenMember, SpecMember, ImplParent: TPasElement;
+  GenIntfProc, GenImplProc, SpecImplProc, SpecIntfProc: TPasProcedure;
+  GenIntfProcScope, SpecIntfProcScope, GenImplProcScope,
+    SpecImplProcScope: TPasProcedureScope;
+  NewClass: TPTreeElement;
+  OldStashCount, i: Integer;
+  SpecClassOrRecScope: TPasClassOrRecordScope;
+  GenScope: TPasGenericScope;
+begin
+  // check generic type is resolved completely
+  GenScope:=TPasGenericScope(GenericType.CustomData);
+  if GenScope.GenericStep<psgsImplementationParsed then
+    RaiseNotYetImplemented(20190804174019,GenericType,GetObjName(SpecializedItem.SpecializedType));
+
+  // check specialized type step
+  if SpecializedItem.Step<psssInterfaceFinished then
+    RaiseNotYetImplemented(20190804120128,GenericType,GetObjName(SpecializedItem.SpecializedType));
+  if SpecializedItem.Step>psssInterfaceFinished then
+    exit;
+  SpecializedItem.Step:=psssImplementationBuilding;
+
+  SpecType:=SpecializedItem.SpecializedType;
+
+  // specialize all methods
+  if GenericType is TPasMembersType then
+    begin
+    GenClassOrRec:=TPasMembersType(GenericType);
+    SpecClassOrRec:=TPasMembersType(SpecType);
+    SpecClassOrRecScope:=TPasClassOrRecordScope(SpecClassOrRec.CustomData);
+
+    {$IFDEF VerbosePasResolver}
+    writeln('TPasResolver.FinishClassType RestoreStashedScopes ',GetObjName(SpecializedItem.SpecializedType),' ',ScopeCount,' FStashScopeCount=',FStashScopeCount);
+    {$ENDIF}
+    ImplParent:=nil;
+    OldStashCount:=FStashScopeCount;
+
+    for i:=0 to GenClassOrRec.Members.Count-1 do
+      begin
+      GenMember:=TPasElement(GenClassOrRec.Members[i]);
+      if GenMember is TPasProcedure then
+        begin
+        GenIntfProc:=TPasProcedure(GenMember);
+        if GenIntfProc.IsAbstract or GenIntfProc.IsExternal then continue;
+        GenIntfProcScope:=TPasProcedureScope(GenIntfProc.CustomData);
+        GenImplProc:=GenIntfProcScope.ImplProc;
+        if GenImplProc=nil then
+          RaiseNotYetImplemented(20190804122134,GenIntfProc);
+        GenImplProcScope:=TPasProcedureScope(GenImplProc.CustomData);
+        SpecMember:=TPasElement(SpecClassOrRec.Members[i]);
+        if SpecMember.Name<>GenMember.Name then
+          RaiseNotYetImplemented(20190804124220,GenMember,GetObjName(SpecMember));
+        SpecIntfProc:=SpecMember as TPasProcedure;
+        SpecIntfProcScope:=TPasProcedureScope(SpecIntfProc.CustomData);
+        NewClass:=TPTreeElement(GenImplProc.ClassType);
+
+        {$IFDEF VerbosePasResolver}
+        writeln('TPasResolver.SpecializeGenTypeImpl Specialize GenImplProc: ',GetObjName(GenImplProc));
+        {$ENDIF}
+
+        if ImplParent=nil then
+          begin
+          // switch scope (e.g. unit implementation section)
+          ImplParent:=GenImplProc.Parent;
+          OldStashCount:=InitSpecializeScopes(ImplParent);
+          {$IFDEF VerbosePasResolver}
+          writeln('TPasResolver.SpecializeGenTypeImpl Specialize implprocs: ',GetObjName(SpecType),' ',ScopeCount,' FStashScopeCount=',FStashScopeCount,' TopScope=',GetObjName(TopScope));
+          {$ENDIF}
+          end
+        else if ImplParent<>GenImplProc.Parent then
+          RaiseNotYetImplemented(20190804130322,GenImplProc,GetObjName(ImplParent));
+
+        // create impl proc
+        SpecImplProc:=TPasProcedure(NewClass.Create(GenImplProc.Name,GenImplProc.Parent));
+        SpecIntfProcScope.ImplProc:=SpecImplProc;
+        if SpecializedItem.ImplProcs=nil then
+          SpecializedItem.ImplProcs:=TFPList.Create;
+        SpecializedItem.ImplProcs.Add(SpecImplProc);
+
+        // create impl proc scope
+        SpecImplProcScope:=TPasProcedureScope(CreateScope(SpecImplProc,FScopeClass_Proc));
+        SpecImplProcScope.Flags:=[ppsfIsSpecialized];
+        SpecImplProcScope.DeclarationProc:=SpecIntfProc;
+        SpecImplProcScope.ModeSwitches:=GenImplProcScope.Modeswitches;
+        SpecImplProcScope.BoolSwitches:=GenImplProcScope.BoolSwitches;
+        SpecImplProcScope.VisibilityContext:=SpecClassOrRec;
+        SpecImplProcScope.ClassRecScope:=SpecClassOrRecScope;
+
+        // specialize props
+        SpecializeElement(GenImplProc,SpecImplProc);
+        end;
+      end;
+
+    if ImplParent<>nil then
+      begin
+      // restore scope
+      RestoreStashedScopes(OldStashCount);
+      end;
+    end;
+
+  SpecializedItem.Step:=psssImplementationFinished;
+end;
+
 procedure TPasResolver.SpecializeMembers(GenMembersType,
   SpecMembersType: TPasMembersType);
 var
@@ -14510,7 +14723,6 @@ begin
     NewEl:=TPasElement(NewClass.Create(GenEl.Name,SpecMembersType));
     SpecMembersType.Members.Add(NewEl);
     SpecializeElement(GenEl,NewEl);
-    FinishDeclaration(NewEl);
     end;
 end;
 
@@ -14525,7 +14737,29 @@ begin
   if C=TPasVariable then
     begin
     AddVariable(TPasVariable(SpecEl));
-    SpecializeVariable(TPasVariable(GenEl),TPasVariable(SpecEl))
+    SpecializeVariable(TPasVariable(GenEl),TPasVariable(SpecEl));
+    end
+  else if C=TPasArgument then
+    begin
+    AddArgument(TPasArgument(SpecEl));
+    SpecializeArgument(TPasArgument(GenEl),TPasArgument(SpecEl));
+    end
+  else if C=TPasImplBeginBlock then
+    SpecializeImplBlock(TPasImplBeginBlock(GenEl),TPasImplBeginBlock(SpecEl))
+  else if C=TProcedureBody then
+    begin
+    AddProcedureBody(TProcedureBody(SpecEl));
+    SpecializeProcedureBody(TProcedureBody(GenEl),TProcedureBody(SpecEl));
+    end
+  else if C.InheritsFrom(TPasProcedure) then
+    begin
+    AddProcedure(TPasProcedure(SpecEl));
+    SpecializeProcedure(TPasProcedure(GenEl),TPasProcedure(SpecEl));
+    end
+  else if C.InheritsFrom(TPasProcedureType) then
+    begin
+    AddType(TPasProcedureType(SpecEl));
+    SpecializeProcedureType(TPasProcedureType(GenEl),TPasProcedureType(SpecEl));
     end
   else
     RaiseNotYetImplemented(20190728151215,GenEl);
@@ -14547,11 +14781,16 @@ procedure TPasResolver.SpecializeVariable(GenEl, SpecEl: TPasVariable);
 begin
   SpecializeElType(GenEl,SpecEl,GenEl.VarType,SpecEl.VarType);
   SpecEl.VarModifiers:=GenEl.VarModifiers;
-  //LibraryName : TPasExpr; // libname of modifier external
-  //ExportName : TPasExpr; // symbol name of modifier external, export and public
+  if GenEl.LibraryName<>nil then
+    SpecializeElExpr(GenEl,SpecEl,GenEl.LibraryName,SpecEl.LibraryName);
+  if GenEl.ExportName<>nil then
+    SpecializeElExpr(GenEl,SpecEl,GenEl.ExportName,SpecEl.ExportName);
   SpecEl.Modifiers:=GenEl.Modifiers;
-  //AbsoluteExpr: TPasExpr;
-  //Expr: TPasExpr;
+  if GenEl.AbsoluteExpr<>nil then
+    SpecializeElExpr(GenEl,SpecEl,GenEl.AbsoluteExpr,SpecEl.AbsoluteExpr);
+  if GenEl.Expr<>nil then
+    SpecializeElExpr(GenEl,SpecEl,GenEl.Expr,SpecEl.Expr);
+  FinishVariable(SpecEl);
 end;
 
 procedure TPasResolver.SpecializeElType(GenEl, SpecEl: TPasElement;
@@ -14576,12 +14815,168 @@ begin
       SpecElType.Release{$IFDEF CheckPasTreeRefCount}('ResolveTypeReference'){$ENDIF};
     SpecElType:=GenElType;
     SpecElType.AddRef{$IFDEF CheckPasTreeRefCount}('ResolveTypeReference'){$ENDIF};
-    end
-  else
+    exit;
+    end;
+  // e.g. anonymous type
+  RaiseNotYetImplemented(20190728152244,GenEl);
+end;
+
+procedure TPasResolver.SpecializeElExpr(GenEl, SpecEl: TPasElement;
+  GenElExpr: TPasExpr; var SpecElExpr: TPasExpr);
+begin
+  if GenElExpr=nil then exit;
+  if GenElExpr.Parent<>GenEl then
     begin
-    // e.g. anonymous type
-    RaiseNotYetImplemented(20190728152244,GenEl);
+    // reference
+    if SpecElExpr<>nil then
+      RaiseNotYetImplemented(20190803220248,SpecEl,GetObjName(SpecElExpr));
+    SpecElExpr:=GenElExpr;
+    SpecElExpr.AddRef{$IFDEF CheckPasTreeRefCount}('SpecializeElExpr'){$ENDIF};
+    exit;
     end;
+  // normal expression
+  RaiseNotYetImplemented(20190803220358,GenEl);
+end;
+
+procedure TPasResolver.SpecializeProcedure(GenEl, SpecEl: TPasProcedure);
+var
+  GenProcType: TPasProcedureType;
+  NewClass: TPTreeElement;
+  SpecProcScope: TPasProcedureScope;
+  GenBody: TProcedureBody;
+begin
+  SpecializePasElementProperties(GenEl,SpecEl);
+
+  SpecProcScope:=SpecEl.CustomData as TPasProcedureScope;
+  Include(SpecProcScope.Flags,ppsfIsSpecialized);
+
+  if GenEl.PublicName<>nil then
+    SpecializeElExpr(GenEl,SpecEl,GenEl.PublicName,SpecEl.PublicName);
+  if GenEl.LibrarySymbolName<>nil then
+    SpecializeElExpr(GenEl,SpecEl,GenEl.LibrarySymbolName,SpecEl.LibrarySymbolName);
+  if GenEl.LibraryExpr<>nil then
+    SpecializeElExpr(GenEl,SpecEl,GenEl.LibraryExpr,SpecEl.LibraryExpr);
+  if GenEl.DispIDExpr<>nil then
+    SpecializeElExpr(GenEl,SpecEl,GenEl.DispIDExpr,SpecEl.DispIDExpr);
+  if GenEl.MessageExpr<>nil then
+    SpecializeElExpr(GenEl,SpecEl,GenEl.MessageExpr,SpecEl.MessageExpr);
+  SpecEl.MessageName:=GenEl.MessageName;
+  SpecEl.MessageType:=GenEl.MessageType;
+  SpecEl.AliasName:=GenEl.AliasName;
+  SpecEl.Modifiers:=GenEl.Modifiers;
+  if GenEl.ProcType<>nil then
+    begin
+    GenProcType:=GenEl.ProcType;
+    if GenProcType.Parent<>GenEl then
+      RaiseNotYetImplemented(20190803212426,GenEl,GetObjName(GenProcType.Parent));
+    NewClass:=TPTreeElement(GenProcType.ClassType);
+    SpecEl.ProcType:=TPasProcedureType(NewClass.Create(GenProcType.Name,SpecEl));
+    SpecializeElement(GenProcType,SpecEl.ProcType);
+    end;
+  if GenEl.Body<>nil then
+    begin
+    GenBody:=GenEl.Body;
+    if GenBody.Parent<>GenEl then
+      RaiseNotYetImplemented(20190804183308,GenEl,GetObjName(GenBody.Parent));
+    NewClass:=TPTreeElement(GenBody.ClassType);
+    SpecEl.Body:=TProcedureBody(NewClass.Create(GenBody.Name,SpecEl));
+    SpecializeElement(GenBody,SpecEl.Body);
+    end;
+
+  if length(GenEl.NameParts)>0 then RaiseNotYetImplemented(20190803215418,GenEl);
+
+  FinishProcedure(SpecEl);
+end;
+
+procedure TPasResolver.SpecializeProcedureType(GenEl, SpecEl: TPasProcedureType
+  );
+var
+  GenResultEl, NewResultEl: TPasResultElement;
+  NewClass: TPTreeElement;
+  i: Integer;
+  GenArg, NewArg: TPasArgument;
+begin
+  // Args
+  for i:=0 to GenEl.Args.Count-1 do
+    begin
+    GenArg:=TPasArgument(GenEl.Args[i]);
+    if GenArg.Parent<>GenEl then
+      RaiseNotYetImplemented(20190803213700,GenArg,GetObjName(GenArg.Parent));
+    NewClass:=TPTreeElement(GenArg.ClassType);
+    NewArg:=TPasArgument(NewClass.Create(GenArg.Name,SpecEl));
+    SpecEl.Args.Add(NewArg);
+    SpecializeElement(GenArg,NewArg);
+    end;
+  // properties
+  SpecEl.CallingConvention:=GenEl.CallingConvention;
+  SpecEl.Modifiers:=GenEl.Modifiers;
+
+  // function result
+  if SpecEl is TPasFunctionType then
+    begin
+    GenResultEl:=TPasFunctionType(GenEl).ResultEl;
+    if GenResultEl.Parent<>GenEl then
+      RaiseNotYetImplemented(20190803212935,GenEl,GetObjName(GenResultEl.Parent));
+    NewClass:=TPTreeElement(GenResultEl.ClassType);
+    NewResultEl:=TPasResultElement(NewClass.Create(GenResultEl.Name,SpecEl));
+    TPasFunctionType(SpecEl).ResultEl:=NewResultEl;
+    SpecializeElType(GenResultEl,NewResultEl,GenResultEl.ResultType,NewResultEl.ResultType);
+    end;
+
+  FinishProcedureType(SpecEl);
+end;
+
+procedure TPasResolver.SpecializeProcedureBody(GenEl, SpecEl: TProcedureBody);
+var
+  GenBody, NewBody: TPasImplBlock;
+  NewClass: TPTreeElement;
+begin
+  SpecializeDeclarations(GenEl,SpecEl);
+
+  if GenEl.Body<>nil then
+    begin
+    GenBody:=GenEl.Body;
+    if GenBody.Parent<>GenEl then
+      RaiseNotYetImplemented(20190804184934,GenBody);
+    NewClass:=TPTreeElement(GenBody.ClassType);
+    NewBody:=TPasImplBlock(NewClass.Create(GenBody.Name,SpecEl));
+    SpecEl.Body:=NewBody;
+    SpecializeElement(GenBody,NewBody);
+    end;
+end;
+
+procedure TPasResolver.SpecializeDeclarations(GenEl, SpecEl: TPasDeclarations);
+begin
+  if SpecEl=nil then ;
+  if GenEl.Declarations.Count>0 then
+    RaiseNotYetImplemented(20190804184718,GenEl);
+  //ToDo: Declarations: TFPList; // list of TPasElement
+  //ToDo: Attributes, // TPasAttributes
+  //ToDo: Classes,    // TPasClassType, TPasRecordType
+  //ToDo: Consts,     // TPasConst
+  //ToDo: ExportSymbols,// TPasExportSymbol
+  //ToDo: Functions,  // TPasProcedure
+  //ToDo: Properties, // TPasProperty
+  //ToDo: ResStrings, // TPasResString
+  //ToDo: Types,      // TPasType, except TPasClassType, TPasRecordType
+  //ToDo: Variables   // TPasVariable, not descendants
+end;
+
+procedure TPasResolver.SpecializeArgument(GenEl, SpecEl: TPasArgument);
+begin
+  SpecEl.Access:=GenEl.Access;
+  SpecializeElType(GenEl,SpecEl,GenEl.ArgType,SpecEl.ArgType);
+  if GenEl.ValueExpr<>nil then
+    SpecializeElExpr(GenEl,SpecEl,GenEl.ValueExpr,SpecEl.ValueExpr);
+
+  FinishArgument(SpecEl);
+end;
+
+procedure TPasResolver.SpecializeImplBlock(GenEl, SpecEl: TPasImplBlock);
+begin
+  if SpecEl=nil then ;
+  if GenEl.Elements.Count>0 then
+    RaiseNotYetImplemented(20190804185503,GenEl);
 end;
 
 function TPasResolver.CheckAssignCompatibilityCustom(const LHS,

+ 1 - 1
packages/fcl-passrc/src/pastree.pp

@@ -840,7 +840,7 @@ type
     function ElementTypeName: string; override;
     function GetDeclaration(full : boolean) : string; override;
     procedure GetArguments(List : TStrings);
-    function CreateArgument(const AName, AUnresolvedTypeName: string):TPasArgument;
+    function CreateArgument(const AName, AUnresolvedTypeName: string): TPasArgument; // not used by TPasParser
     procedure ForEachCall(const aMethodCall: TOnForEachPasElement;
       const Arg: Pointer); override;
   public

+ 26 - 0
packages/fcl-passrc/tests/tcresolvegenerics.pas

@@ -38,6 +38,7 @@ type
     procedure TestGen_Class;
     procedure TestGen_ClassDelphi;
     procedure TestGen_ClassForward;
+    procedure TestGen_Class_Method;
     // ToDo: specialize inside generic fail
     // ToDo: generic class forward (constraints must be repeated)
     // ToDo: generic class forward  constraints mismatch fail
@@ -286,6 +287,31 @@ begin
   ParseProgram;
 end;
 
+procedure TTestResolveGenerics.TestGen_Class_Method;
+begin
+  StartProgram(false);
+  Add([
+  '{$mode objfpc}',
+  'type',
+  '  TObject = class end;',
+  '  {#Typ}T = word;',
+  '  generic TBird<{#Templ}T> = class',
+  '    function Fly(p:T): T; virtual; abstract;',
+  '    function Run(p:T): T;',
+  '  end;',
+  'function TBird.Run(p:T): T;',
+  'begin',
+  'end;',
+  'var',
+  '  b: specialize TBird<word>;',
+  '  {=Typ}w: T;',
+  'begin',
+  '  w:=b.Fly(w);',
+  '  w:=b.Run(w);',
+  '']);
+  ParseProgram;
+end;
+
 initialization
   RegisterTests([TTestResolveGenerics]);
 

+ 2 - 1
packages/pastojs/src/pas2jsfiler.pp

@@ -460,7 +460,8 @@ const
     );
 
   PCUProcedureScopeFlagNames: array[TPasProcedureScopeFlag] of string = (
-    'GrpOverload'
+    'GrpOverload',
+    'ppsfIsSpecialized'
     );
 
   PCUDefaultPSRefAccess = psraRead;