April 26
https://issues.dlang.org/show_bug.cgi?id=24522

          Issue ID: 24522
           Summary: Formation and inference of nested type sequences
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Severity: major
          Priority: P1
         Component: dmd
          Assignee: nobody@puremagic.com
          Reporter: qs.il.paperinik@gmail.com

For a function template, `f(Ts...)(ref Ts args)` works as intended:
The number and `ref`-ness of parameters can be inferred from arguments.

This works because `ref` is a storage class.

If we replace `ref` by ´const`, it works as well:
```d
void f(Ts...)(const Ts args)
{
    static foreach (alias arg; args)
    {
        pragma(msg, typeof(arg));
    }
}
void main()
{
    int i;
    f(&i, &i);
}
```

Prints
```
const(int*)
const(int*)
```
as expected.

Use a type constructor instead of a storage class:
```d
void f(Ts...)(const(Ts) args)
{
    static foreach (alias arg; args)
    {
        pragma(msg, typeof(arg));
    }
}
void main()
{
    int i;
    f(&i, &i);
}
```
Prints
```
int*
int*
```
Const is completely ignored!


Coming from C++, one would assume that the following works:
```d
void f(Ts...)(Ts* args)
{
    static foreach (alias arg; args)
    {
        pragma(msg, typeof(arg));
    }
}
void main()
{
    int i;
    f(&i, &i);
}
```
But it fails:
```
Error: template `onlineapp.f` is not callable using argument types `!()(int*,
int*)`
```
And it’s not that the compiler just can’t do the inference,
providing arguments explicitly:
```d
void main()
{
    int i;
    f!(int, int)(&i, &i);
}
```
Fails with the following error:
```
Error: cannot have pointer to `(int, int)`
```

Even weirder, using slice types:
Inference fails, but using explicit template arguments:
```d
void f(Ts...)(Ts[] args)
{
    static foreach (alias arg; args)
    {
        pragma(msg, typeof(arg));
    }
}
void main()
{
    int i;
    f!(int, int)([i], [i]);
}
```
The template instantiation succeeds,
it prints
```
int
int
```
which is weird,
and then fails with an error:
```
Error: template `onlineapp.f` is not callable using argument types `!()(int[],
int[])`
```

Other, probably less thought-of type suffixes are function pointer and delegate
types:
```d
void f(Ts...)(Ts function(int) args)
{
        static foreach (alias arg; args)
        pragma(msg, typeof(arg));
}
void main()
{
    int i;
    f((int x) => x);
}
```
Fails:
```
Error: template `onlineapp.f` is not callable using argument types `!()(int
function(int x) pure nothrow @nogc @safe)`
```
And with explicit template arguments:
```d
void f(Ts...)(Ts function(int) args)
{
        static foreach (alias arg; args)
        pragma(msg, typeof(arg));
}
void main()
{
    int i;
    f!int(x => x);
}
```
Also fails:
```
Error: functions cannot return a sequence (use `std.typecons.Tuple`)
```

My sense is that when a type tuple is to be inferred and type constructors and
type suffixes are applied to it, that should expand element-wise:
`const(Ts)[]` expands to `(const(T[0])[],...,const(T[$-1])[])`,
and inferring the length and elements of `Ts` should work as well:
Inferring the length is trivial,
and if the length is inferred, inferring the element types should work as well,
since it works for single parameters.

--