Jump to page: 1 2
Thread overview
Template type inference problem
4 days ago
Manu
4 days ago
kdevel
3 days ago
Manu
3 days ago
Manu
3 days ago
Salih Dincer
4 days ago
Salih Dincer
3 days ago
Manu
3 days ago
Timon Gehr
2 days ago
Dennis
1 day ago
Timon Gehr
1 day ago
Salih Dincer
4 days ago
Does anyone understand why this doesn't work?

void f(T)(const(T)[] x, const(T)* y) {}
void test()
{
    int*[] x;
    const int* y;
    f(x, &y);
}

error : template `f` is not callable using argument types `!()(int*[],
const(int*)*)`
        Candidate is: `f(T)(const(T)[] x, const(T)* y)`

Should this work? It looks like it should work to me.
...assuming T is inferred to be `int*`... which it's not clear why it
wouldn't be?

The argument `y` is an exact match. The argument `x` requires a const promotion, and then T can be inferred correctly. Perhaps it's the order of that operation that it can't deal with?

I kinda reckon this is a bug...


4 days ago
On Wednesday, 2 October 2024 at 08:55:15 UTC, Manu wrote:
> Does anyone understand why this doesn't work?
>
> void f(T)(const(T)[] x, const(T)* y) {}
> void test()
> {
>     int*[] x;
>     const int* y;
>     f(x, &y);
> }
>
> error : template `f` is not callable using argument types `!()(int*[],
> const(int*)*)`
>         Candidate is: `f(T)(const(T)[] x, const(T)* y)`
>
> Should this work? It looks like it should work to me.
> ...assuming T is inferred to be `int*`... which it's not clear why it
> wouldn't be?
>
> The argument `y` is an exact match.

The second actual parameter to f!int is &y not y.

> The argument `x` requires a const promotion,

The type of x is int*[] and not const(int) [];


4 days ago

On Wednesday, 2 October 2024 at 08:55:15 UTC, Manu wrote:

>

Does anyone understand why this doesn't work?

void f(T)(const(T)[] x, const(T)* y) {}

...

Looking at the protofunction, the test() function should look like this:

void test()
{
    int[] x;
    int* y;
    f(x, y);
}

SDB@79

3 days ago
On Wed, 2 Oct 2024 at 20:16, Salih Dincer via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On Wednesday, 2 October 2024 at 08:55:15 UTC, Manu wrote:
> > Does anyone understand why this doesn't work?
> >
> > ```d
> > void f(T)(const(T)[] x, const(T)* y) {}
> > ```
> > ...
>
> Looking at the protofunction, the test() function should look
> like this:
>
> ```d
> void test()
> {
>      int[] x;
>      int* y;
>      f(x, y);
> }
> ```
>
> SDB@79
>

That's not the code in question.


3 days ago
On Wed, 2 Oct 2024 at 20:06, kdevel via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On Wednesday, 2 October 2024 at 08:55:15 UTC, Manu wrote:
> > Does anyone understand why this doesn't work?
> >
> > void f(T)(const(T)[] x, const(T)* y) {}
> > void test()
> > {
> >     int*[] x;
> >     const int* y;
> >     f(x, &y);
> > }
> >
> > error : template `f` is not callable using argument types
> > `!()(int*[],
> > const(int*)*)`
> >         Candidate is: `f(T)(const(T)[] x, const(T)* y)`
> >
> > Should this work? It looks like it should work to me.
> > ...assuming T is inferred to be `int*`... which it's not clear
> > why it
> > wouldn't be?
> >
> > The argument `y` is an exact match.
>
> The second actual parameter to f!int is &y not y.
>

Yes, the `y` argument is `const(int*)*`, so `T` must be inferred `int*`

> The argument `x` requires a const promotion,
>
> The type of x is int*[] and not const(int) [];


Right, `x` is `int*[]`, and matching the argument `const(T)[]` required const promotion `int*[]` -> `const(int*)[]`, which is a perfectly normal promotion. In which case, `T` is `int*`, matching with `y`, and so `T` can be properly inferred.

If you remove the `*` from `x` and `y`, the `T` inference works properly...
so something about `T` being inferred as `int*` rather than an `int` causes
the type inference to fail.
The non-uniformity looks like a bug, unless there's a reasonable
explanation that I've missed.


3 days ago
Here's a clearer presentation of the issue:

void f(T)(const(T)[] x, const(T)* y) {}
void test()
{
    // this works; f(T) is inferred as f!int
    int[] x;
    const int y;
    f(x, &y);

    // fails: expected that f(T) is inferred as f!(int*)
    int*[] a;
    const int* b;
    f(a, &b);
}

Removing `const` from `y` and `b` makes the problem go away, so I think this is a bug in some interaction between the type deduction logic and parameter const promotion?


On Thu, 3 Oct 2024 at 09:34, Manu <turkeyman@gmail.com> wrote:

> On Wed, 2 Oct 2024 at 20:06, kdevel via Digitalmars-d < digitalmars-d@puremagic.com> wrote:
>
>> On Wednesday, 2 October 2024 at 08:55:15 UTC, Manu wrote:
>> > Does anyone understand why this doesn't work?
>> >
>> > void f(T)(const(T)[] x, const(T)* y) {}
>> > void test()
>> > {
>> >     int*[] x;
>> >     const int* y;
>> >     f(x, &y);
>> > }
>> >
>> > error : template `f` is not callable using argument types
>> > `!()(int*[],
>> > const(int*)*)`
>> >         Candidate is: `f(T)(const(T)[] x, const(T)* y)`
>> >
>> > Should this work? It looks like it should work to me.
>> > ...assuming T is inferred to be `int*`... which it's not clear
>> > why it
>> > wouldn't be?
>> >
>> > The argument `y` is an exact match.
>>
>> The second actual parameter to f!int is &y not y.
>>
>
> Yes, the `y` argument is `const(int*)*`, so `T` must be inferred `int*`
>
> > The argument `x` requires a const promotion,
>>
>> The type of x is int*[] and not const(int) [];
>
>
> Right, `x` is `int*[]`, and matching the argument `const(T)[]` required const promotion `int*[]` -> `const(int*)[]`, which is a perfectly normal promotion. In which case, `T` is `int*`, matching with `y`, and so `T` can be properly inferred.
>
> If you remove the `*` from `x` and `y`, the `T` inference works
> properly... so something about `T` being inferred as `int*` rather than an
> `int` causes the type inference to fail.
> The non-uniformity looks like a bug, unless there's a reasonable
> explanation that I've missed.
>


3 days ago
On 10/2/24 10:55, Manu wrote:
> Does anyone understand why this doesn't work?
> 
> void f(T)(const(T)[] x, const(T)* y) {}
> void test()
> {
>      int*[] x;
>      const int* y;
>      f(x, &y);
> }
> 
> error : template `f` is not callable using argument types `!()(int*[], const(int*)*)`
>          Candidate is: `f(T)(const(T)[] x, const(T)* y)`
> 
> Should this work? It looks like it should work to me.
> ...assuming T is inferred to be `int*`... which it's not clear why it wouldn't be?
> 
> The argument `y` is an exact match. The argument `x` requires a const promotion, and then T can be inferred correctly. Perhaps it's the order of that operation that it can't deal with?
> 
> I kinda reckon this is a bug...

Yes, I think it should work.
3 days ago

On Wednesday, 2 October 2024 at 23:43:43 UTC, Manu wrote:

>

Here's a clearer presentation of the issue:

void f(T)(const(T)[] x, const(T)* y) {}
void test()
{
    // this works; f(T) is inferred as f!int
    int[] x;
    const int y;
    f(x, &y);

A third possibility, the following code, also works:

const int*[] a;  
const int* b;

f(a, &b);

Interesting!

SDB@79

3 days ago

On Wednesday, 2 October 2024 at 08:55:15 UTC, Manu wrote:

>

Does anyone understand why this doesn't work?

void f(T)(const(T)[] x, const(T)* y) {}
void test()
{
    int*[] x;
    const int* y;
    f(x, &y);
}

I think it's a bug.

void f(T)(const(T)[] x, const(T)* y) {}

void f2(T)(const(T)[] x) { pragma(msg, T);}
void f3(T)(const(T)* y) { pragma(msg, T);}
void test()
{
    int*[] x;
    const int* y;
    f2(x);  // int *
    f3(&y); // const(int)*
    f!(const(int)*)(x, &y); // ok
}

I tried reversing the order to see if it figures out to use const(int)*, but it doesn't work.

-Steve

2 days ago

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 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?

--- 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.

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:

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.)

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.

« First   ‹ Prev
1 2