[fpc-pascal] generic proc inference

Mattias Gaertner nc-gaertnma at netcologne.de
Mon Oct 7 11:39:45 CEST 2019


On Sun, 6 Oct 2019 18:16:16 -0400
Ryan Joseph <genericptr at gmail.com> wrote:

>[...]
> I think my logic is different from what you expect though and I’m
> happy to change it if we need to.
> 
> There’s the comment I left in the code for the
> “try_implicit_specialization” function.
> 
> { 	  find generic procsyms by param count, starting from
>           number of parsed params. if a procsym is found then
>           validate via tcallcandidates and build list of *unique*
>           types for use when specializing.
>         
>           inferred generic types are evaluated by inserting
>           non-repating types into the list in linear order.
>             (1,'string') = <Integer,String>
>             (1,2,3,4,5,6) = <Integer>
>             ('a','b') = <String>
>             ('string',1) = <String,Integer>
>             ('a',1,'b',2,'c') = <String,Integer>
> }

I'm baffled. That's more basic algorithm than I expected. ;)

This means you don't support:
generic procedure Run<S,T>(a: T; b:S); overload;

And the following compiles, but fails on run, as T becomes an array
instead of the element type:
generic procedure Run<T>(a: array of T); overload;


> I think for this example my logic does: T = integer, U = TObject
> because the first 2 integers params are repeating so they both
> consume the single T and then the TObject consumes the U. That means
> the second param “1” is being passed for a TObject type. 
> 
> generic procedure DoThis<T,U>(msg: T; param1: U; param2: TObject);
> 
> DoThis(1, 1, TObject.Create); // DoThis(msg: integer; param1:
> TObject; param2: TObject);
> 
> I used this logic because it works for repeating patterns but it’s
> not very intuitive in cases where the arguments are the same number
> as the generic parameters.
> 
> What should be the rule here?

IMO the algorithm should look at the declarations instead of blindly
mapping the argument types to the generic type params.
If you want to keep the simple algorithm, then you should add
some checks and give an error if the function does not support the
algorithm.


> >> How does Delphi implicitly specialize this?  
> > 
> > DoThis(1,1,nil); // T and U become shortint
> > DoThis('aa','aa',nil); // T and U become string  
> 
> So Delphi seems to match by index so param 1 = generic param 1. With
> repeating patterns this breaks downs but maybe it’s a special case if
> the function parameter count matches the generic parameter count?

Delphi does not simply match the index. For example this works as expected (I shortened the example):

generic procedure Run<T>(a: array of T); overload;
var
  p: PTypeInfo;
begin
  p:=TypeInfo(T);
  writeln(p^.Name);
end;

var a: array of boolean;
begin
  Run(a); // writes "boolean"
end;

Mattias


More information about the fpc-pascal mailing list