Thread overview
[Issue 22241] Compiler fails to match a more specialized overload
Dec 17, 2022
Iain Buclaw
Jul 11, 2023
RazvanN
Jul 11, 2023
Max Samukha
December 17, 2022
https://issues.dlang.org/show_bug.cgi?id=22241

Iain Buclaw <ibuclaw@gdcproject.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Priority|P1                          |P2

--
July 11, 2023
https://issues.dlang.org/show_bug.cgi?id=22241

RazvanN <razvan.nitu1305@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |razvan.nitu1305@gmail.com

--- Comment #1 from RazvanN <razvan.nitu1305@gmail.com> ---
(In reply to Max Samukha from comment #0)

> But, if another general parameter is added, the "matches both" error occurs:
> 
> int foo(T)(T t, int a)
> {
>     return 1;
> }
> 
> int foo(T, U)(T t, U a)
> {
>     return 2;
> }
> 
> void main()
> {
>     int x;
>     assert(foo(0, x) == 1);
>     assert(foo(0, "a") == 2);
> }
> 
> onlineapp.d(14): Error: `onlineapp.foo` called with argument types `(int,
> int)` matches both...
> 
> Both should be either rejected or accepted.

In the first example, when `foo(x)` is encountered, the compiler selects the
first overload because it does not have to deduce any types for it
(`foo()(int)` is more specialized than `foo(T)(T a)`). In the second example,
when `foo(0, x)` is encountered the compiler needs to do deduction for both
overloads and after deduction it sees that both match equally => error. For
foo(0, "a") there is no ambiguity since the first overload does not match while
the second one does.

I can see an enhancement being made by counting the number of parameters for which deduction is necessary and choosing the overload with fewer deduced parameters, however, this gets nasty when combined with template constraints and other template magic. I don't think this enhancement is worth it.

This is intended behavior, so I would vote to close this as WONTFIX.

What do you think?

--
July 11, 2023
https://issues.dlang.org/show_bug.cgi?id=22241

--- Comment #2 from Max Samukha <maxsamukha@gmail.com> ---
(In reply to RazvanN from comment #1)

> both match equally

That's the problem. They do both match after deduction, but one of the patterns is still more specific than the other.

Also, in the following, slightly different case, type deduction doesn't seem to prevent the compiler from selecting the more specific one:

int foo(T: int)(T a)
{
    return 1;
}

int foo(T)(T a)
{
    return 2;
}

void main()
{
    int x;
    assert(foo(x) == 1); // ok
    assert(foo("a") == 2); // ok
}

(Somebody tried to explain to me why this works, but I didn't get it).

> What do you think?

I think that simply closing this as WONTFIX would be an admission of defeat. On the other hand, I understand that a proper fix would require a significant redesign/rewrite.

--