Template type inference problem
Dennis
dkorpel at gmail.com
Fri Oct 4 10:12:04 UTC 2024
On Wednesday, 2 October 2024 at 08:55:15 UTC, Manu wrote:
> Does anyone understand why this doesn't work?
If you separate the two parameters into two functions:
```
void f0(T)(const(T)[] x) { pragma(msg, "f0.T = ", T); }
void f1(T)(const(T)* x) { pragma(msg, "f1.T = ", T); }
```
And call `f0(x); f1(&y)`, you get:
```
f0.T = int*
f1.T = const(int)*
```
[The current
logic](https://github.com/dlang/dmd/blob/f0a2ac5588c780424f1f375b929e842ff07961a2/compiler/src/dmd/dtemplate.d#L1525-L1538) can't unify these two deductions of `T`.
Why is T inferred as `const(int)*` when it could also match
`int*` here? The function responsible for matching different
const levels is `deduceTypeHelper`, and when you match const(U)
with const(T), it strips away only the top level const. So
`const(int*)` becomes `const(int)*`, but not `int*`.
So why not strip all levels?
```diff
--- a/compiler/src/dmd/dtemplate.d
+++ b/compiler/src/dmd/dtemplate.d
@@ -1122,6 +1122,10 @@ MATCH deduceTypeHelper(Type t, out Type
at, Type tparam)
return MATCH.exact;
}
case X(MODFlags.const_, MODFlags.const_):
+ {
+ at = t.unqualify(tparam.mod);
+ return MATCH.exact;
+ }
case X(MODFlags.wild, MODFlags.wild):
```
Even doing this just for `const` breaks Phobos, and probably many
other projects.
```D
void formatValueImpl(Writer, T, Char)(auto ref Writer w, scope
const(T) obj, /*...*/) /*...*/
{
// Error: cannot implicitly convert expression `obj` of type
`const(char[])` to `char[]`
Unqual!(const(StringTypeOf!T)) val = obj; // for `alias
this`, see bug5371
formatRange(w, val, f);
}
```
So perhaps the unification logic can be improved. There's already
a check for unifying classes based on implicit conversion, but it
only works in one order:
```D
void f(T)(const T* x, const T* y) { }
void main()
{
const Object o;
const Throwable t;
f(&o, &t); // Fine
f(&t, &o); // Error
f!Object(&t, &o); // Fine
}
```
This doesn't work with mutable parameters btw, because pointers
to class types are only covariant when they are const. (Why is
that? I don't know.)
```D
static assert(is(Throwable* : Object*)); // Fails
static assert(is(const(Throwable)* : const(Object)*)); // Passes
```
Without const AND without pointers there is logic to find a
common type, independent of order though:
```
void f(T)(T x, T y) { }
void main()
{
Object o;
Throwable t;
f(o, t); // Fine
f(t, o); // Fine
}
```
So yeah... I might be missing good rationale, but it looks like
an inconsistent mess right now.
More information about the Digitalmars-d
mailing list