static assert not printing out along the error diagnostic

jfondren julian.fondren at gmail.com
Wed Jul 14 23:44:18 UTC 2021


On Wednesday, 14 July 2021 at 22:59:38 UTC, someone wrote:
>
> Please, go to the bottom of the unittest block and uncomment 
> one of those lines (DMD version here is DMD64 D Compiler 
> v2.096.1):

so, these lines:

```d
     stringUGC32 lugcSequence3 = stringUGC32(cast(char) 'x');
     stringUGC32 lugcSequence4 = stringUGC32(1);
```

which call stringUGC32, an alias:

```d
alias stringUGC32 = gudtUGC!(stringUTF32);
alias stringUTF32 = dstring; /// same as immutable(dchar)[];
```

which explicitly instantiates gudtUGC with the type dstring,

```d
enum isTypeSupported(type) = is(type == stringUTF08) || is(type 
== stringUTF16)
     || is(type == stringUTF32);
...
public struct gudtUGC(typeStringUTF) {
     static assert(isTypeSupported!(typeStringUTF),
             r"ooops … gudtUGC structure requires 
[string|wstring|dstring] ≠ ["d
             ~ typeStringUTF.stringof ~ r"]"d);
```

which passes the assert.

You're explicitly instantiating the struct with dstring, *not 
getting an assertion error because dstring passes the test*, and 
are then passing the constructor a different type, which gets you 
a type error at that time.

However, even if you avoid that alias and try either implicit or 
explicit instantiation of the template with bad types, the 
template instantiation fails first in random other places, like a 
default param of " " not making sense as a char:

```d
staticif1.d(369): Error: cannot implicitly convert expression `" 
"` of type `string` to `const(char)`
staticif1.d(387): Error: cannot implicitly convert expression `" 
"` of type `string` to `const(char)`
staticif1.d(545): Error: template instance 
`fw.types.UniCode.gudtUGC!char` error instantiating
```

So, yeah, even with no static ifs in the file, you're still not 
getting these static asserts to fail before other parts of the 
template. Conclusion: you shouldn't rely on static asserts 
providing a good UI in the case of an error. They still *work*, 
the struct still wouldn't instantiate with a `char` or the like 
if all the other char-incompatibilities were removed, but for UI 
purposes they're not great because you can't rely on them firing 
according to normal control flow.

You're using aliases though, and not instantiating the struct 
directly. If you make those function templates you can use 
template constraints with them, which does result in a nice UI:

```d
gudtUGC!stringUTF08 thing8(T)(T arg) if (isTypeSupported!T) { 
return gudtUGC!T(arg); }
gudtUGC!stringUTF16 thing16(T)(T arg) if (isTypeSupported!T) { 
return gudtUGC!T(arg); }
gudtUGC!stringUTF32 thing32(T)(T arg) if (isTypeSupported!T) { 
return gudtUGC!T(arg); }

...

     stringUGC32 lugcSequence3 = thing32(cast(char) 'x');
     stringUGC32 lugcSequence4 = thing32(1);
```

(introducing new 'thing' functions as stringUGC32 used is 
elsewhere as a type and not just a function. So you still need 
the aliases.)

Which fails in this manner:

```d
staticif1.d(548): Error: template `fw.types.UniCode.thing32` 
cannot deduce function from argument types `!()(char)`, 
candidates are:
staticif1.d(46):        `thing32(T)(T arg)`
   with `T = char`
   must satisfy the following constraint:
`       isTypeSupported!T`
```

and would fail more verbosely if the three functions had the same 
name, instead of numbered names to follow the stringUGC32 pattern.

`isTypeSupported` isn't great here, but you can pick a more 
precise name. Or in the case of already numbered functions like 
this, you could use more precise tests... or just drop the tests 
entirely and have non-templated functions:

```d
gudtUGC!stringUTF08 thing8(stringUTF08 arg) { return 
typeof(return)(arg); }
gudtUGC!stringUTF16 thing16(stringUTF16 arg) { return 
typeof(return)(arg); }
gudtUGC!stringUTF32 thing32(stringUTF32 arg) { return 
typeof(return)(arg); }
```

which results in normal type errors:

```
staticif2.d(548): Error: function 
`fw.types.UniCode.thing32(dstring arg)` is not callable using 
argument types `(char)`
staticif2.d(548):        cannot pass argument `'x'` of type 
`char` to parameter `dstring arg`
```


More information about the Digitalmars-d-learn mailing list