Browse Source

fcl-passrc: useanalyzer: check specialized and half specialized type

git-svn-id: trunk@42811 -
Mattias Gaertner 6 years ago
parent
commit
f61641accc
1 changed files with 50 additions and 24 deletions
  1. 50 24
      packages/fcl-passrc/src/pasuseanalyzer.pas

+ 50 - 24
packages/fcl-passrc/src/pasuseanalyzer.pas

@@ -252,6 +252,7 @@ type
     function ElementVisited(El: TPasElement; Mode: TPAUseMode): boolean; overload;
     function ElementVisited(El: TPasElement; Mode: TPAUseMode): boolean; overload;
     function ElementVisited(El: TPasElement; OtherCheck: TPAOtherCheckedEl): boolean; overload;
     function ElementVisited(El: TPasElement; OtherCheck: TPAOtherCheckedEl): boolean; overload;
     procedure MarkImplScopeRef(El, RefEl: TPasElement; Access: TPSRefAccess);
     procedure MarkImplScopeRef(El, RefEl: TPasElement; Access: TPSRefAccess);
+    function CanSkipGenericType(El: TPasGenericType): boolean;
     procedure UseElement(El: TPasElement; Access: TResolvedRefAccess;
     procedure UseElement(El: TPasElement; Access: TResolvedRefAccess;
       UseFull: boolean); virtual;
       UseFull: boolean); virtual;
     procedure UseTypeInfo(El: TPasElement); virtual;
     procedure UseTypeInfo(El: TPasElement); virtual;
@@ -300,6 +301,7 @@ type
     function IsExport(El: TPasElement): boolean;
     function IsExport(El: TPasElement): boolean;
     function IsIdentifier(El: TPasElement): boolean;
     function IsIdentifier(El: TPasElement): boolean;
     function IsImplBlockEmpty(El: TPasImplBlock): boolean;
     function IsImplBlockEmpty(El: TPasImplBlock): boolean;
+    function IsSpecializedGenericType(El: TPasElement): boolean;
     procedure EmitMessage(Id: TMaxPrecInt; MsgType: TMessageType;
     procedure EmitMessage(Id: TMaxPrecInt; MsgType: TMessageType;
       MsgNumber: integer; Fmt: String;
       MsgNumber: integer; Fmt: String;
       const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
       const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
@@ -1007,6 +1009,27 @@ begin
     CheckImplRef;
     CheckImplRef;
 end;
 end;
 
 
+function TPasAnalyzer.CanSkipGenericType(El: TPasGenericType): boolean;
+begin
+  Result:=false;
+  if ScopeModule=nil then
+    begin
+    // analyze whole program
+    // -> should only reach fully specialized types
+    if not Resolver.IsFullySpecialized(El) then
+      RaiseNotSupported(20190817151437,El);
+    end
+  else
+    begin
+    // analyze a module
+    if ((El.GenericTemplateTypes<>nil) and (El.GenericTemplateTypes.Count>0)) then
+      // generic template -> analyze
+    else if not Resolver.IsFullySpecialized(El) then
+      // specialized -> skip
+      exit(true);
+    end;
+end;
+
 procedure TPasAnalyzer.UseElement(El: TPasElement; Access: TResolvedRefAccess;
 procedure TPasAnalyzer.UseElement(El: TPasElement; Access: TResolvedRefAccess;
   UseFull: boolean);
   UseFull: boolean);
 var
 var
@@ -1102,8 +1125,7 @@ begin
   else if C=TPasArrayType then
   else if C=TPasArrayType then
     begin
     begin
     ArrType:=TPasArrayType(El);
     ArrType:=TPasArrayType(El);
-    if (ScopeModule=nil) and not Resolver.IsFullySpecialized(ArrType) then
-      RaiseNotSupported(20190817151437,ArrType);
+    if CanSkipGenericType(ArrType) then exit;
     UseSubEl(ArrType.ElType);
     UseSubEl(ArrType.ElType);
     for i:=0 to length(ArrType.Ranges)-1 do
     for i:=0 to length(ArrType.Ranges)-1 do
       begin
       begin
@@ -1117,6 +1139,7 @@ begin
   else if C=TPasClassType then
   else if C=TPasClassType then
     begin
     begin
     ClassEl:=TPasClassType(El);
     ClassEl:=TPasClassType(El);
+    if CanSkipGenericType(ClassEl) then exit;
     if ClassEl.ObjKind=okInterface then
     if ClassEl.ObjKind=okInterface then
       begin
       begin
       // mark all used members
       // mark all used members
@@ -1135,6 +1158,7 @@ begin
   else if C=TPasRecordType then
   else if C=TPasRecordType then
     begin
     begin
     // published record: use all members
     // published record: use all members
+    if CanSkipGenericType(TPasRecordType(El)) then exit;
     Members:=TPasRecordType(El).Members;
     Members:=TPasRecordType(El).Members;
     for i:=0 to Members.Count-1 do
     for i:=0 to Members.Count-1 do
       begin
       begin
@@ -1149,8 +1173,7 @@ begin
   else if C.InheritsFrom(TPasProcedureType) then
   else if C.InheritsFrom(TPasProcedureType) then
     begin
     begin
     ProcType:=TPasProcedureType(El);
     ProcType:=TPasProcedureType(El);
-    if (ScopeModule=nil) and not Resolver.IsFullySpecialized(ProcType) then
-      RaiseNotSupported(20190817151554,ProcType);
+    if CanSkipGenericType(ProcType) then exit;
     for i:=0 to ProcType.Args.Count-1 do
     for i:=0 to ProcType.Args.Count-1 do
       UseSubEl(TPasArgument(ProcType.Args[i]).ArgType);
       UseSubEl(TPasArgument(ProcType.Args[i]).ArgType);
     if El is TPasFunctionType then
     if El is TPasFunctionType then
@@ -1913,8 +1936,7 @@ begin
     else if C=TPasArrayType then
     else if C=TPasArrayType then
       begin
       begin
       ArrType:=TPasArrayType(El);
       ArrType:=TPasArrayType(El);
-      if (ScopeModule=nil) and not Resolver.IsFullySpecialized(ArrType) then
-        RaiseNotSupported(20190817151449,ArrType);
+      if CanSkipGenericType(ArrType) then exit;
       if not MarkElementAsUsed(ArrType) then exit;
       if not MarkElementAsUsed(ArrType) then exit;
       for i:=0 to length(ArrType.Ranges)-1 do
       for i:=0 to length(ArrType.Ranges)-1 do
         UseExpr(ArrType.Ranges[i]);
         UseExpr(ArrType.Ranges[i]);
@@ -1944,7 +1966,10 @@ begin
       UseElType(El,TPasSetType(El).EnumType,Mode);
       UseElType(El,TPasSetType(El).EnumType,Mode);
       end
       end
     else if C.InheritsFrom(TPasProcedureType) then
     else if C.InheritsFrom(TPasProcedureType) then
-      UseProcedureType(TPasProcedureType(El))
+      begin
+      if CanSkipGenericType(TPasProcedureType(El)) then exit;
+      UseProcedureType(TPasProcedureType(El));
+      end
     else if C=TPasSpecializeType then
     else if C=TPasSpecializeType then
       UseSpecializeType(TPasSpecializeType(El),Mode)
       UseSpecializeType(TPasSpecializeType(El),Mode)
     else if C=TPasGenericTemplateType then
     else if C=TPasGenericTemplateType then
@@ -2021,8 +2046,7 @@ var
   aClass: TPasClassType;
   aClass: TPasClassType;
 begin
 begin
   FirstTime:=true;
   FirstTime:=true;
-  if (ScopeModule=nil) and not Resolver.IsFullySpecialized(El) then
-    RaiseNotSupported(20190817110919,El);
+  if CanSkipGenericType(El) then exit;
   case Mode of
   case Mode of
   paumAllExports: exit;
   paumAllExports: exit;
   paumAllPasUsable:
   paumAllPasUsable:
@@ -2516,7 +2540,6 @@ var
   i: Integer;
   i: Integer;
   Decl: TPasElement;
   Decl: TPasElement;
   Usage: TPAElement;
   Usage: TPAElement;
-  GenScope: TPasGenericScope;
 begin
 begin
   {$IFDEF VerbosePasAnalyzer}
   {$IFDEF VerbosePasAnalyzer}
   writeln('TPasAnalyzer.EmitDeclarationsHints ',GetElModName(El));
   writeln('TPasAnalyzer.EmitDeclarationsHints ',GetElModName(El));
@@ -2538,12 +2561,8 @@ begin
       if Usage=nil then
       if Usage=nil then
         begin
         begin
         // declaration was never used
         // declaration was never used
-        if Decl is TPasGenericType then
-          begin
-          GenScope:=Decl.CustomData as TPasGenericScope;
-          if GenScope.SpecializedItem<>nil then
-            continue;
-          end;
+        if IsSpecializedGenericType(Decl) then
+          continue;
         EmitMessage(20170311231734,mtHint,nPALocalXYNotUsed,
         EmitMessage(20170311231734,mtHint,nPALocalXYNotUsed,
           sPALocalXYNotUsed,[Decl.ElementTypeName,Decl.Name],Decl);
           sPALocalXYNotUsed,[Decl.ElementTypeName,Decl.Name],Decl);
         end;
         end;
@@ -2558,7 +2577,6 @@ var
   i: Integer;
   i: Integer;
   Member: TPasElement;
   Member: TPasElement;
   Members: TFPList;
   Members: TFPList;
-  GenScope: TPasGenericScope;
 begin
 begin
   {$IFDEF VerbosePasAnalyzer}
   {$IFDEF VerbosePasAnalyzer}
   writeln('TPasAnalyzer.EmitTypeHints ',GetElModName(El));
   writeln('TPasAnalyzer.EmitTypeHints ',GetElModName(El));
@@ -2574,12 +2592,7 @@ begin
       begin
       begin
       if (El is TPasClassType) and (TPasClassType(El).ObjKind=okInterface) then
       if (El is TPasClassType) and (TPasClassType(El).ObjKind=okInterface) then
         exit;
         exit;
-      if El is TPasGenericType then
-        begin
-        GenScope:=El.CustomData as TPasGenericScope;
-        if GenScope.SpecializedItem<>nil then
-          exit;
-        end;
+      if IsSpecializedGenericType(El) then exit;
 
 
       EmitMessage(20170312000025,mtHint,nPALocalXYNotUsed,
       EmitMessage(20170312000025,mtHint,nPALocalXYNotUsed,
         sPALocalXYNotUsed,[El.ElementTypeName,El.Name],El);
         sPALocalXYNotUsed,[El.ElementTypeName,El.Name],El);
@@ -2639,7 +2652,7 @@ begin
     begin
     begin
     // write without read
     // write without read
     if (vmExternal in El.VarModifiers)
     if (vmExternal in El.VarModifiers)
-        or ((El.Parent is TPasClassType) and (TPasClassType(El.Parent).IsExternal)) then
+        or ((El.Parent is TPasClassType) and TPasClassType(El.Parent).IsExternal) then
       exit;
       exit;
     if El.Visibility in [visPrivate,visStrictPrivate] then
     if El.Visibility in [visPrivate,visStrictPrivate] then
       EmitMessage(20170311234159,mtHint,nPAPrivateFieldIsAssignedButNeverUsed,
       EmitMessage(20170311234159,mtHint,nPAPrivateFieldIsAssignedButNeverUsed,
@@ -2970,6 +2983,19 @@ begin
   Result:=false;
   Result:=false;
 end;
 end;
 
 
+function TPasAnalyzer.IsSpecializedGenericType(El: TPasElement): boolean;
+var
+  GenScope: TPasGenericScope;
+begin
+  if El is TPasGenericType then
+    begin
+    GenScope:=El.CustomData as TPasGenericScope;
+    if (GenScope<>nil) and (GenScope.SpecializedItem<>nil) then
+      exit(true);
+    end;
+  Result:=false;
+end;
+
 procedure TPasAnalyzer.EmitMessage(Id: TMaxPrecInt; MsgType: TMessageType;
 procedure TPasAnalyzer.EmitMessage(Id: TMaxPrecInt; MsgType: TMessageType;
   MsgNumber: integer; Fmt: String;
   MsgNumber: integer; Fmt: String;
   const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
   const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};