It's basically Hindley-Milner.

FeepingCreature feepingcreature at gmail.com
Fri Mar 24 09:44:28 UTC 2023


On Friday, 24 March 2023 at 09:30:30 UTC, FeepingCreature wrote:
> You're misunderstanding the problem.
>
> When you call a template function, DMD (and C++) performs IFTI, 
> implicit function template instantiation. This requires 
> *reverse-engineering* a type T that fulfills the requirement 
> for the function call.

It's important to understand that IFTI does something *completely 
different* than normal type inference: it does *backwards* type 
inference. It's more similar to [Hindley-Milner] than D's normal 
"forward" type resolution.

For instance, if you write a template like this:

```
void foo(T)(void delegate(T) dg) { }
foo((int i) {});
```

Then the compiler infers `T` as `int` by recursing on the 
expression "`void delegate(T)` = `void delegate(int)`". It takes 
the explicit template parameters and calling parameter types and 
uses them as nodes in an algebraic system, that it can use to 
*solve for* the template parameter types.

Or if you write a template like this:

```
T foo(T)(T a, T b) { }
foo(2, 3.5);
```

Then the compiler starts with two algebraic expressions: `int : 
T` and `double : T` (`:` meaning "is convertible to"), which it 
solves by *unifying* `int` and `double` into `double`.

It is important to understand that `T` here is a **free 
variable**, not yet a type; the point is to *assign it* a type. 
So we cannot instantiate a template with `T`, because we can only 
instantiate templates with concrete types.

Finally, in our example:

```
alias A(T) = B!T;
void foo(T)(A!T) {}
foo(B!int);
```

The compiler starts with an expression `B!int = A!T`, and is 
trying to solve for T.

It looks at `A!T`, and it thinks: "hm, the other term could be a 
template instantiation of the template `A` with something." But 
`B!T` is a template instantiation of `B`, not `A`, so it fails to 
match.

If we insert the missing step, what the compiler should do is: 
"Ah, `B` is a 'trivial alias' (like `using` in C++), so I can 
*syntactically substitute* it with its content", and create the 
new expression `B!int = B!T`. Then it can resolve this by noting 
that *the concrete type* `B!int` is an instance of `B` with the 
type `int`, and thus gain the new expression `T = int`, which 
solves the algebraic system.

[Hindley-Milner]: 
https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system


More information about the Digitalmars-d mailing list