[Issue 24522] New: Formation and inference of nested type sequences
d-bugmail at puremagic.com
d-bugmail at puremagic.com
Fri Apr 26 16:00:32 UTC 2024
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 at puremagic.com
Reporter: qs.il.paperinik at 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.
--
More information about the Digitalmars-d-bugs
mailing list