Difference between "can call" and "can compile"

Steven Schveighoffer schveiguy at gmail.com
Mon Sep 7 16:27:46 UTC 2020

On 9/7/20 12:12 PM, Paul Backus wrote:
> On Monday, 7 September 2020 at 14:57:24 UTC, Steven Schveighoffer wrote:
>> I get a compilation error. But it's not in foo, it's in bar. It says:
>> Error: template instance onlineapp.bar!(foo) does not match template 
>> declaration bar(alias x)()
>>   with x = foo(T)(T v)
>>   must satisfy the following constraint:
>>        __traits(compiles, x(1))
>> [...]
>> The problem is, if the intention is for it to pass, but the 
>> implementation is bugged, the error message is useless. If the thing 
>> I'm passing is a type with 200 LOC, and there's an error buried in 
>> there somewhere, the compiler is telling me "somewhere in this, it 
>> doesn't work". And sometimes those function signatures and their 
>> constraints are hairy themselves.
>> My usual steps taken at this point are to extract the constraint 
>> template and actually try to call the functions in the constraints 
>> with that type, and see what fails. This is somewhat annoying, and 
>> sometimes difficult to do based on where the code that implements the 
>> constraint actually is, and where the code actually calling it is (I 
>> may have to duplicate a lot of stuff).
> The tedious-but-reliable way to handle this is to recompile with 
> `-verrors=spec`, search the output for the original error message, and 
> then scroll up until you find what you're looking for in the speculative 
> errors. The only issue is that you have to wade through a lot of useless 
> chaff to find the information you actually care about.
> IMO the best way to make this easier would be to have the compiler 
> provide a "stack trace" of speculative errors for each failed constraint 
> whenever a template fails to instantiate--maybe behind a switch 
> (`-verrors=constraints`) to avoid clogging up the output in the common 
> case.
> This has the advantage of working for *all* indirect errors like this, 
> not just ones involving IFTI. To give a concrete example, 
> `-verrors=constraints` would have helped me a lot with the problems I 
> had to debug in SumType's copy constructors recently [1], whereas 
> __traits(canCall) would have been completely useless.
> [1] https://github.com/pbackus/sumtype/issues/36

Thanks! This is the kind of response I'm looking for.

I'm trying to understand what the issue and the solution was in that 
bug. I'm assuming once the compiler bugs were fixed, then you had to 
figure out why it wasn't compiling?

I wasn't aware of -verrors=spec, but it sounds like it spitting out ALL 
speculative errors, not just when a specific call fails to build? While 
giving a searchable set of data, the situation is only slightly improved.

It is true that if your constraint is the problem, then 
__traits(canCall) or whatever wouldn't help. But I don't see any 
constraint changes in that code.

Perhaps you can elaborate on the specific issue and how you solved it? 
It's unclear to me from the diff and the bug discussion that the 
__traits(canCall) would not help.

I would be OK with your proposal as well, and it actually could be done 
separately from the __traits(canCall) idea. Focusing the aim of the 
speculative errors might be useful in general -- like, give a specific 
instantiation line and parameters to debug, and only have it trace that 
one error, rather than having to search through pages of text.


More information about the Digitalmars-d mailing list