I'm posting this here 'cos I've no idea how to improve it, but it's definitely a problem:
First, let's define a struct that overloads opCast: struct S { T opCast(T)() if (is(T == struct)) { T t; return t; } } The code above is just a stub implementation; the idea is that S would store some kind of key/value pairing, and opCast would automatically assign key/value pairs to struct fields (hence the signature constraint is(T==struct)). The reason opCast is used is to integrate nicely with std.conv: unittest { S s; ... // add some key/value pairs to s struct T { int x, int y; } auto t = to!T(s); } On DMD, this works OK. But if we add a method to T: unittest { S s; ... // add some key/value pairs to s struct T { int x, int y; bool f() { return true; } } auto t = to!T(s); } The existence of T.f() causes T to acquire an implicit context pointer, which is a separate issue, but what I'm trying to get at here is, the resulting error message is completely unhelpful: it just shows about 20 or so lines of errors saying that std.conv.to cannot be instantiated, and that it doesn't match any of a large number of toImpl overloads. But there is no indication whatsoever why that might be so -- after all, opCast *is* defined! -- the signature constraint in toImpl that looks for opCast is written like this: if (is(typeof(S.init.opCast!T()) : T) && ... The problem is, if S.init.opCast!T() fails to compile for *any* reason, the signature constraint declines, but the user is left with no clue as to why! The cause of the problem only becomes clear if you replace to!T(s) with s.opCast!T(), then the compiler will tell you exactly what's wrong with opCast (in this case, that T cannot be instantiated outside of its definition scope). In fact, you can insert a random error into opCast and you wouldn't know any better (as long as it's syntactically correct), since if you never call it directly, only via std.conv.to, then you'll only ever see the opaque wall of template instantiation failures, not the *real* reason for the failure. I don't know how to improve this situation. One thought is to rewrite toImpl's signature constraint to only check for the *existence* of opCast, so that any subsequent compile errors will become visible (even if ugly). But that doesn't work for cases where something else may match the signature constraints of another toImpl overload. But the current state of things is very unhelpful -- you keep getting an error that to!T() can't be instantiated, but all you see is that all the toImpl overloads rejected T. Then if you comment out the "T t;" line in opCast and replace the return with "return T.init", then things mysteriously begin to work again. In fact, adding random changes into opCast will either compile if you're lucky, or complain that to!T() can't be instantiated. No message about any syntax error or other error in opCast is ever given. You could be missing a case in a switch statement, and all you'd learn is that to!T() can't be instantiated -- opCast isn't even mentioned anywhere, so you wouldn't even know to look there in the first place! Clearly, something needs to be improved, but it's unclear *what*, or how. T -- Long, long ago, the ancient Chinese invented a device that lets them see through walls. It was called the "window".