Bug 5896 – const overload matching is succumb to template parameter one
Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2011-04-27T01:54:00Z
Last change time
2012-05-12T12:07:00Z
Keywords
patch, rejects-valid
Assigned to
nobody
Creator
k.hara.pg
Comments
Comment #0 by k.hara.pg — 2011-04-27T01:54:51Z
This code doesn't compile when -version=expect.
----
struct X
{
version(expect)
{
T opCast(T)() { return 10; } // 1a
T opCast(T)()const { return 11; } // 1b
}
else
{
T opCast(T:int)() { return 10; } // 2a
T opCast(T:int)()const { return 11; } // 2b
}
}
void main()
{
auto xm = X();
auto xc = const(X)();
assert(cast(int)xm == 10);
assert(cast(int)xc == 11);
}
----
test.d(18): Error: template test.X.opCast(T) opCast(T) matches more than one template declaration, test.d(5):opCast(T) and test.d(6):opCast(T)
----
Template function matching processed by template.c TemplateDeclaration::deduceFunctionTemplateMatch(), and
const overload matching is more priority than template parameter one.
T:int(2a,2b) is more specialized from T(1a,1b), then first priority is MATCHexact and second is MATCHconvert.
Next, currently const overload matching returns MATCHconst or not, but the priority of T(MATCHconvert) is less than MATCHconst, so both 1a and 1b return MATCHconvert, then make ambiguous.
It seems to me that more priority level is need:
Priority name
0 MATCHnomatch
1 MATCHconvertconst ... const conversion + template parameter conversion (new)
2 MATCHconvert ... template parameter conversion
3 MATCHconst ... const conversion
4 MATCHexact ... exact match
Comment #1 by clugdbug — 2011-04-29T08:51:07Z
I don't understand why case 2a,2b works.
It seems to me that case 1 is identical to:
struct X{}
T foo(T)(const(X) _this) { return 10; }
T foo(T)(X _this) { return 11; }
void main(){
auto xm = X();
assert(foo!int(xm)==11);
}
Which fails in exactly the same way.
Comment #2 by k.hara.pg — 2011-04-29T16:53:00Z
(In reply to comment #1)
> I don't understand why case 2a,2b works.
> It seems to me that case 1 is identical to:
>
> struct X{}
>
> T foo(T)(const(X) _this) { return 10; }
>
> T foo(T)(X _this) { return 11; }
>
> void main(){
> auto xm = X();
> assert(foo!int(xm)==11);
> }
>
> Which fails in exactly the same way.
I have just started reading the code around the template, template function matching may have three steps:
1. Tempate parameter vs explicit template arguments.
ex. opCast(T)() vs opCast!X() -> T vs X
2. const overload matching on ethis
void f(T)() vs const void f(T)() -> (mutable) vs const
3. function parameters type matching (and may inference of implict template parameters)
void f(X x) vs void f(const(X) x) -> X vs const(X)
The cause of this issue may be step 1 and 2, and cause of your test case may be 3.
----
Re-explain of my test case. on xm (type is X) lookup...
1a matching:
step1: opCast(T) vs opCast!(int) -> MATCHconvert
step2: through -> MATCHconst
-> afterward result: MATCHconvert
1b matching:
step1: opCast(T) vs opCast!(int) -> MATCHconvert
step2: MATCHconst if can -> !!! MATCHconst is succomb to MATCHconvert
-> afterward result: MATCHconvert
Both result of 1a and 1b are MATCHconvert, so make ambiguous.
2a matching:
step1: opCast(T:int) vs opCast!(int) -> MATCHexact
step2: through
-> afterward result: MATCHexact
2b matching:
step1: opCast(T:int) vs opCast!(int) -> MATCHexact
step2: MATCHconst if can -> MATCHconst
-> afterward result: MATCHconvert
2a is more specialized than 2b, then 2a is selected.
More complicated test from my pull is still broken.
----
struct X5896
{
T opCast(T)(){ return 1; } // L3
const T opCast(T)(){ return 2; } // L4
immutable T opCast(T)(){ return 3; }
shared T opCast(T)(){ return 4; } // L6
const shared T opCast(T)(){ return 5; } // L7
}
void test5896()
{
auto xm = X5896 ();
auto xc = const(X5896) ();
auto xi = immutable(X5896) ();
auto xs = shared(X5896) ();
auto xcs= const(shared(X5896))();
assert(cast(int)xm == 1); // L16
assert(cast(int)xc == 2);
assert(cast(int)xi == 3); // L18
assert(cast(int)xs == 4); // L19
assert(cast(int)xcs== 5);
}
Errors:
----
test.d(16): Error: template test.X5896.opCast matches more than one template declaration, test.d(3):opCast(T) and test.d(4):opCast(T)
test.d(18): Error: template test.X5896.opCast matches more than one template declaration, test.d(4):opCast(T) and test.d(7):opCast(T)
test.d(19): Error: template test.X5896.opCast matches more than one template declaration, test.d(6):opCast(T) and test.d(7):opCast(T)
Comment #6 by github-bugzilla — 2012-05-12T11:35:38Z