The program below show the problem. If it was by design then design is faulty as the broken error message indicates.
(I have a real-world use case for this and see no reason to forbid it)
enum Command{
Char,
Any,
Fork,
Jump,
End
};
template FlowEvaluator()
{
//if control flow
bool execute(Command cmd)()
if(cmd == Command.Jump || cmd == Command.Fork)
{
return false;
}
}
template MatchEvaluator()
{
//if operation
bool execute(Command cmd)()
if(cmd == Command.Char || cmd == Command.Any || cmd == Command.End)
{
return false;
}
}
struct Machine
{
mixin FlowEvaluator;
mixin MatchEvaluator;
bool exec()
{
return execute!(Command.Any)();
}
}
Fails with:
mixin.d(36): Error: template instance execute!(cast(Command)1) ambiguous template declaration
mixin.Machine.MatchEvaluator!().execute(Command cmd)() if (cmd == Command.Char || cmd == Command.Any || cmd == Command.End)
and
mixin.Machine.FlowEvaluator!().execute(Command cmd)() if (cmd == Command.Jump || cmd == Command.Fork)
mixin.d(36): Error: template instance execute!(cast(Command)1) execute!(cast(Command)1) does not match template declaration execute(Command cmd)() if (cmd == Command.Jump || cmd == Command.Fork)
mixin.d(36): Error: function expected before (), not execute!(cast(Command)1) of type void
The second message hints to me that compiler in fact knows perfectly well which one template does match the instantiation but something prevented it from just picking it.
Tested on 2.061alpha, I think it was there all along.
Marking as major as there is either bogus diagnostic or a broken feature.
Comment #1 by k.hara.pg — 2012-12-28T05:55:08Z
This is a kind of "template overload set", which is not yet supported in current dmd.
Following is an another case which fails to compile based on the same issue.
---
// module a;
template A(T) if (is(T == int)) {}
// module b;
template A(T) if (is(T == double)) {}
// moudle test;
import a, b;
alias A!int X;
---
output:
test.d(5): Error: template instance A!(int) ambiguous template declaration b.A(T) if (is(T == double)) and a.A(T) if (is(T == int))
Comment #2 by maximzms — 2013-01-30T05:49:59Z
http://dlang.org/template-mixin.html
"Alias declarations can be used to overload together functions declared in different mixins"
Unfortunately this doesn't work:
-------------------
mixin template mixA()
{
void foo(string s)() if(s == "a") {}
}
mixin template mixB()
{
void foo(string s)() if(s == "b") {}
}
struct Foo
{
mixin mixA A;
mixin mixB B;
alias A.foo foo;
alias B.foo foo;
}
void main()
{
Foo f;
f.foo!"a"();
}
-------------------
test.d(16): Error: alias test.Foo.foo conflicts with alias test.Foo.foo at test.d(15)
-------------------
It looks like signature constraints are ignored in this case.
Comment #3 by maximzms — 2013-02-04T08:12:40Z
Signature constraints are ignored also for structures:
-------------------
struct A
{
void foo(string s)() if(s == "a") {}
}
struct B
{
void foo(string s)() if(s == "b") {}
}
struct Foo
{
A a;
B b;
alias a.foo foo;
alias b.foo foo;
}
void main()
{
Foo f;
f.foo!"a"();
}
-------------------
test.d(16): Error: alias test.Foo.foo conflicts with alias test.Foo.foo at test.d(15)
-------------------
(In reply to comment #3)
> Signature constraints are ignored also for structures:
[snip]
It is not valid code, because
> struct Foo
> {
> A a;
> B b;
> alias a.foo foo;
> alias b.foo foo;
> }
is just same as:
struct Foo
{
A a;
B b;
alias A.foo foo; // alias doesn't handle context *expression*
alias B.foo foo; // so 'a' and 'b' are simply truncated.
}
Then,
> Foo f;
> f.foo!"a"();
is identical with:
A.foo!"a"();
But A.foo requires a valid 'this' expression, so compilation fails.
Comment #6 by andrej.mitrovich — 2013-02-14T08:20:42Z