On 5/13/17 10:41 AM, Stanislav Blinov wrote:
Let's suppose I wrote the following template function:

import std.meta;

enum bool isString(T) = is(T == string);

void foo(Args...)(auto ref Args args)
if (!anySatisfy!(isString, Args)) {
   // ...
}

This one is variadic, but it could as well have been non-variadic. The
important
aspect is that it has a constraint. In this case, the constraint is that
it should
accept any argument types *but* strings.

Now, if I call it with a string argument:

foo(1, "a");

I get the following error:

file(line): Error: template foo cannot deduce function from argument
types !()(int, string), candidates are:
file(line): foo(Args...)(auto ref Args arg) if (!anySatisfy!(isString,
Args))

Ok, so the call does not compile, but the message is rather vague: it
doesn't
tell me which argument(s) failed to satisfy the constraint.
In this simple example it's easy to see where the error is, but if foo()
was
called in a generic way (i.e. arguments come from somewhere else, their
type
determined by inference, etc.), or if the constraint was more complex, it
wouldn't be as easy to spot.

So, to help with this, let me write a checker and modify foo's
signature, thanks
to CTFE:

template types(args...) {
   static if (args.length)
       alias types = AliasSeq!(typeof(args[0]), types!(args[1..$]));
   else
       alias types = AliasSeq!();
}

auto noStringArgs(args...)() {
   import std.format;
   // use types, as otherwise iterating over args may not compile
   foreach(i, T; types!args) {
       static if (is(T == string)) {
           pragma(msg, format!"Argument %d is a string, which is not
supported"
                   (i+1));
           return false;
       }
   }
   return true;
}

void foo(Args...)(auto ref Args args)
if (noStringArgs!args) {
   // ...
}


Now if I call foo() with a string argument, I get this:

foo(1, "a");


Argument 2 is a string, which is not supported
file(line): Error: template foo cannot deduce function from argument
types !()(int, string), candidates are:
file(line): foo(Args...)(auto ref Args arg) if (noStringArgs!args)

I think the compiler should be able to figure this out, and report it. The if constraint is a boolean expression, and so it can be divided into the portions that pass or fail.

What I'd love to see is the constraint colorized to show green segments that evaluate to true, and red segments that evaluate to false. And then recursively show each piece when asked.

I think any time spent making a user-level solution will not scale. The compiler knows the information, can ascertain why it fails, and print a much nicer error message. Plus it makes compile-time much longer to get information that is already available.

Imagine also a constraint like isInputRange!R. This basically attempts to compile a dummy lambda. How would one handle this in user-code?

I think there are several forum threads about diagnosing constraint issues, haven't got the time right now to look for them.

-Steve

Reply via email to