Bug 12510 – Templated overload ignored

Status
RESOLVED
Resolution
INVALID
Severity
regression
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2014-04-03T00:26:00Z
Last change time
2014-04-03T01:36:24Z
Assigned to
nobody
Creator
issues.dlang

Comments

Comment #0 by issues.dlang — 2014-04-03T00:26:37Z
This code results in infinite recursion: class C { bool foo(C rhs) { return false; } } bool foo(T, U)(T lhs, U rhs) if (is(T == class) && is(U == class) && is(typeof(lhs.foo(rhs)) == bool) && is(typeof(rhs.foo(lhs)) == bool)) { return true; } bool foo()(const C lhs, const C rhs) { return foo(cast()lhs, cast()rhs); } void main() { const C a = new C; const C b = new C; auto d = foo(a, b); } And whether a and b are const or not doesn't matter. The first overload is simply never called. It always calls the second overload. And making it so that the second overload isn't templatized has no effect. It used to be that this would compile, because it was working in this pull request: https://github.com/D-Programming-Language/druntime/pull/459 whereas that pull request now results in infinite recursion. I'd have to try it on several older versions of dmd though to figure out when it broke, but this definitely worked before. My first guess is that it broke when it was fixed so that templated and non-template functions could be overloaded. The fact that the first overload fails with const objects should force them to use the second overload (because C.foo isn't const), whereas if they're not const, then the first should match better than the second. And to make matters worse, if I change the code to class C { bool foo(C rhs) { return false; } } bool foo(T, U)(T lhs, U rhs) { return true; } bool foo()(const C lhs, const C rhs) { return foo(cast()lhs, cast()rhs); } void main() { const C a = new C; const C b = new C; auto d = foo(a, b); } it still compiles with the same result, whereas it _should_ result in a compilation error due to ambiguity, because both functions match equally well. Instead, the second function is always called, whether it's templatized or not and whether the arguments are const or not.
Comment #1 by code — 2014-04-03T01:16:47Z
I think this might be the result of bug 1528. Not sure, but I think the empty template arguments are matched with MATCHexact, just like a plain function declaration. And subsequently converting both function arguments to const is deemed a better match than the template. You can use this instead. bool foo (const C lhs, const C rhs) { foo!(C, C)(cast()lhs, cast()rhs); }
Comment #2 by k.hara.pg — 2014-04-03T01:36:24Z
(In reply to comment #1) > I think this might be the result of bug 1528. Not sure, but I think the empty > template arguments are matched with MATCHexact, just like a plain function > declaration. And subsequently converting both function arguments to const is > deemed a better match than the template. > > You can use this instead. > > bool foo (const C lhs, const C rhs) > { > foo!(C, C)(cast()lhs, cast()rhs); > } Yes, this is correct result caused by fixing issue 1528. Another way is to supply "specialized foo" for const C parameters, like as: bool foo(T:Object, U:Object)(const T lhs, const U rhs) { return foo(cast()lhs, cast()rhs); }