Difference between "can call" and "can compile"

Steven Schveighoffer schveiguy at gmail.com
Tue Sep 8 13:57:34 UTC 2020


On 9/8/20 1:03 AM, FeepingCreature wrote:
> On Monday, 7 September 2020 at 16:10:13 UTC, Steven Schveighoffer wrote:
>>
>> This is somewhat different than what I was proposing. However, it's 
>> very closely related.
>>
>> I absolutely need it to be matched with a function call, I don't want 
>> to have to do type acrobatics or check for UFCS, or whatever.
>>
>> However, I think both our needs are satisfied if the feature is 
>> something like checking to see that all symbols are resolved and that 
>> all instantiations are unambiguous. What happens after that should be 
>> considered a normal ungagged error.
>>
>> If I can pull out a non-template analogy, imagine you had code like:
>>
>> int foo()
>> {
>>    blahblah(); // unresolved symbol
>> }
>>
>> int bar()
>> {
>>    return foo();
>> }
>>
>> And instead of the error on the "blahblah" line, you got an error that 
>> foo doesn't exist, and so bar cannot be compiled. This is kind of how 
>> the current template state of affairs is. I want the same benefits for 
>> template code that non-template code has.
>>
> Yesss.
> 
> Okay, so as far as I can see there's two avenues that should give us 
> both what we want. The first, and IMO best one (but W&A won't agree) is 
> a huge breaking language change that errors in templates that have 
> matched the constraints are always reported as errors, even in a gagged 
> context.

No, the result of __traits(compiles) or is(typeof(...)) cannot be 
changed. I would never want that.

What we would need is a new feature that then we can migrate existing 
code to use.

> The second, more limited one that I think also gives you what 
> you want (?) is a pragma *like* __traits(compiles), maybe 
> __traits(instantiates), with the change that instead of gagging 
> everything, it captures only one category of error - "the call couldn't 
> find a matching function or template" - and only from the expression 
> directly passed to it. All other errors are reported as usual.
> 
> Would that do it?

Yes, this is exactly what I'm looking for. I was going to call it 
__traits(canCall) or something, but instantiates makes perfect sense, 
since this only really is important for template instantiation.

In order to facilitate more complex conditions, I would say "the code in 
the expression passes semantic, with all template instantiations in the 
checked expression are matched" as the description.

For actual errors in the code being checked, it should return false just 
like __traits(compiles).

e.g.:

void foo()()
{
   import non.existent.mod;
}

__traits(compiles, foo()); // false
__traits(instantiates, foo()); // true, foo's body isn't checked for 
errors, just that it instantiates.
__traits(compiles, () {import non.existent.mod;} ()); // false
__traits(instantiates, () {import non.existent.mod;} ()); // false, the 
code inside the expression doesn't pass semantic

-Steve


More information about the Digitalmars-d mailing list