Bug 22241 – Compiler fails to match a more specialized overload

Status
NEW
Severity
major
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2021-08-25T19:48:05Z
Last change time
2024-12-13T19:18:09Z
Keywords
rejects-valid, spec
Assigned to
No Owner
Creator
Max Samukha
Moved to GitHub: dmd#19975 →

Comments

Comment #0 by maxsamukha — 2021-08-25T19:48:05Z
In the following, the specialized parameter (int a) takes over the general one (T a) as expected: int foo()(int a) { return 1; } int foo(T)(T a) { return 2; } void main() { int x; assert(foo(x) == 1); // ok assert(foo("a") == 2); // ok } 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.
Comment #1 by razvan.nitu1305 — 2023-07-11T09:49:28Z
(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?
Comment #2 by maxsamukha — 2023-07-11T18:33:49Z
(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.
Comment #3 by robert.schadek — 2024-12-13T19:18:09Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/19975 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB