Browse Source

* fix #39681: also handle the result type of a specialized procvar when checking for a possible implicit specialization
+ added test

Sven/Sarah Barth 3 years ago
parent
commit
76753438ed
2 changed files with 62 additions and 19 deletions
  1. 39 19
      compiler/pgenutil.pas
  2. 23 0
      tests/webtbs/tw39681.pp

+ 39 - 19
compiler/pgenutil.pas

@@ -923,6 +923,30 @@ uses
       }
 
       function handle_procvars(genericparams:tfphashlist;callerparams:tfplist;target_def:tdef;caller_def:tdef):boolean;
+        var
+          newparams : tfphashlist;
+
+        procedure handle_generic_param(targetparadef,callerparadef:tdef);
+          var
+            key : string;
+            index : integer;
+          begin
+            if not assigned(callerparadef.typesym) then
+              internalerror(2021020908);
+
+            key:=generic_param_hash(targetparadef);
+
+            { the generic param must not already be used }
+            index:=genericparams.findindexof(key);
+            if index<0 then
+              begin
+                { add the type to the list }
+                index:=newparams.findindexof(key);
+                if index<0 then
+                  newparams.add(key,callerparadef.typesym);
+              end;
+          end;
+
         var
           i,j : integer;
           paravar : tparavarsym;
@@ -930,9 +954,6 @@ uses
           caller_proc : tprocvardef;
           target_proc_para,
           caller_proc_para : tparavarsym;
-          newparams : tfphashlist;
-          key : string;
-          index : integer;
           valid_params : integer;
         begin
           result := false;
@@ -977,26 +998,25 @@ uses
                   { find the generic param name in the generic def parameters }
                   j:=target_proc.genericdef.genericparas.findindexof(paravar.vardef.typesym.name);
 
-                  target_def:=ttypesym(target_proc.genericparas[j]).typedef;
-                  caller_def:=caller_proc_para.vardef;
-
-                  if not assigned(caller_def.typesym) then
-                    internalerror(2021020908);
+                  handle_generic_param(ttypesym(target_proc.genericparas[j]).typedef,caller_proc_para.vardef);
+                end;
 
-                  key:=generic_param_hash(target_def);
+              inc(valid_params);
+            end;
 
-                  { the generic param must not already be used }
-                  index:=genericparams.findindexof(key);
-                  if index<0 then
-                    begin
-                      { add the type to the list }
-                      index:=newparams.findindexof(key);
-                      if index<0 then
-                        newparams.add(key,caller_def.typesym);
-                    end;
+          if assigned(target_proc.returndef) and not is_void(target_proc.returndef) then
+            begin
+              { or check for exact? }
+              if compare_defs(caller_proc.returndef,target_proc.returndef,nothingn)<te_equal then
+                begin
+                  newparams.free;
+                  exit(false);
                 end;
 
-              inc(valid_params);
+              if sp_generic_para in target_proc.returndef.typesym.symoptions then
+                begin
+                  handle_generic_param(target_proc.returndef,caller_proc.returndef);
+                end;
             end;
 
           { if the count of valid params matches the target then

+ 23 - 0
tests/webtbs/tw39681.pp

@@ -0,0 +1,23 @@
+{ %NORUN }
+
+program tw39681;
+
+{$mode objfpc}{$H+}
+{$ModeSwitch implicitfunctionspecialization}
+
+type
+  generic TFunc<TResult> = function: TResult;
+
+generic procedure Bar<T>(f: specialize TFunc<T>);
+begin
+end;
+
+function Foo: Integer;
+begin
+end;
+
+begin
+  specialize Bar<Integer>(@Foo); // works
+  Bar(@Foo); // Error
+end.
+