Comment #0 by bus_dbugzilla — 2016-09-09T18:31:06Z
-----------------------------------
$ cat test.d
import std.typecons;
void foo(T)(Nullable!T value)
{ }
void foo()(int i)
{ }
void main()
{
Nullable!int x;
foo(x);
}
$ dmd -run test.d
core.exception.AssertError@/home/nick/.dvm/compilers/dmd-2.071.1/linux/bin/../../src/phobos/std/typecons.d(2075): Called `get' on null Nullable!int.
-----------------------------------
WTF?!?!?
Removing the "int" overload makes the error go away.
Comment #1 by bus_dbugzilla — 2016-09-09T18:37:39Z
Problem appears to have been introduced in 2.064
Comment #2 by ag0aep6g — 2016-09-09T18:55:05Z
Without phobos:
----
struct Nullable(T)
{
T x;
alias x this;
}
void foo(T)(Nullable!T value) {}
void foo()(int i) { assert(false); /* hit */ }
void main() { foo(Nullable!int()); }
----
The second overload being selected is surprising, because it involves an implicit conversion whereas the first overload would be an exact match. I can't find anything in the spec about how IFTI interacts with overloading.
Comment #3 by bugzilla — 2016-10-13T23:48:39Z
(In reply to ag0aep6g from comment #2)
> void foo(T)(Nullable!T value) {}
Considered:
"match with conversion for initial template arguments"
"exact match for inferred template arguments"
> void foo()(int i) { assert(false); /* hit */ }
Considered:
"exact match for initial template arguments"
"exact match for inferred template arguments"
And so the second match is better. The relevant line in the source code is "matchTiargs = MATCHconvert;" at:
https://github.com/dlang/dmd/blob/master/src/dtemplate.d#L1916
This is because the parameter 'T' is deduced from argument 'Nullable!int', rather than being supplied directly.
Whether this is correct or not is debatable, I think the template rules are excessively complex, but they are the result of constant complaints and revision. I am extremely reluctant to change them further, because that will inevitably result in hard-to-explain breakage, like this one, which was apparently introduced in 2.064. If someone wants to find the specific PR that did it, I'd appreciate it.
(In reply to Walter Bright from comment #3)
> (In reply to ag0aep6g from comment #2)
> > void foo(T)(Nullable!T value) {}
>
> Considered:
> "match with conversion for initial template arguments"
Here "with conversion" means that it needs template argument inference, right?
> "exact match for inferred template arguments"
>
> > void foo()(int i) { assert(false); /* hit */ }
>
> Considered:
> "exact match for initial template arguments"
> "exact match for inferred template arguments"
But this one is not an exact match. It involves an `alias this` conversion from Nullable!int to int.
As far as I can tell, it should be:
"match with conversion for initial template arguments"
"match with conversion for inferred template arguments"
Or maybe just "match with conversion" since there are no template parameters. The empty template parentheses can actually be omitted without changing the behavior of the code.
Comment #6 by code — 2016-10-16T11:01:20Z
I think we still have a few weird orderings for the new function vs. template overloads, and also within the existing template overloads.
Part of those are simply caused by the way the current ordering is implemented.
Discussing this is quite tricky and doesn't make sense for single examples.
If someone would want to spend the effort on a DIP to come up w/ a sound and simpler partial ordering, that is implementable in a backward compatible way, it would probably be a welcome effort.
Don't think it's an urgent topic though.
Comment #7 by github-bugzilla — 2016-10-16T11:01:35Z