On Thursday, 1 September 2016 at 18:24:13 UTC, Timon Gehr wrote:
The idea is that there'd only be one such "fallback" template,
so that
you cannot get into a situation such as this. I'm guessing the
ICE is
due to a recursive dependency between the two f templates?
I posted the ICE to show that DMD does not necessarily have a
clear concept of how your code should be interpreted. Note that
you are essentially saying: "If not X then X". It's very easy
to run into behaviour that seems inconsistent once you do
things like this.
Well, I'd argue that's not quite right and the correct
interpretation is "If not the other X then this X", due to the
`!__traits(compiles, .f!T)`, explicitly telling the compiler to
check if the *other* "overloads" compile. I don't actually know
whether template constraints are considered to be at module scope
or in the template scope, though, so maybe I'm completely wrong
on this.
enum isSomething(T)=false;
int f(T)(T t) if(isSomething!T){
return 0;
}
int f(T)(T t) if(!compiles!".f!int") {
return 2;
}
enum compiles(string s) = __traits(compiles,mixin(s));
pragma(msg, compiles!".f!int"); // false
pragma(msg, __traits(compiles,.f!int)); // true
DMD cannot properly process code like this (i.e. code that
contradicts itself, where the same expression in the same
context can be true in one part of the compilation, but false
later). Examples can be constructed where the semantics of the
resulting code depends on the order that modules are passed on
the command line. It's not specified anywhere what should
happen, and it is not immediately clear.
DMD shouldn't accept code like this in the first place. It's
very brittle, the result depends on random compiler
implementation details.
I would argue that this is an entirely different case than my
example, but we are getting into compiler implementation details
that I know nothing about, so I can't actually say whether it is
(or should) be valid code.