Because this will reference the Writer of a bounded array, which is only valid if the bounded array is full of u8.
zig_install/lib/std/bounded_array.zig:282:13: error: The Writer interface is only defined for BoundedArray(u8, ...) but the given type is BoundedArray(sii.SyncM, ...)
@compileError("The Writer interface is only defined for BoundedArray(u8, ...) " ++
My first inclination is to put
test {
std.testing.refAllDecls(@This());
}
at the bottom of all my files, which, after doing it, has found multiple errors in some of my function declarations…which is nice.
In the meantime, the best thing you can do is try to test your code as much as possible, and for those functions too annoying to test, use _ = foo; on them to at least type check them.
Another idea I just thought of is to allow this syntax:
test foo;
which would be equivalent to:
test {
_ = &foo;
}
This at least looks like a doctest but without the actual work of writing a doctest.
I am using comptime instead of test because I don’t want to count it as an additional test case. (refAllDecls uses builtin.is_test to return immediately if the code is not running under a test runner).
I don’t use refAllDeclsRecursive because I don’t write deeply nested test cases.
const std = @import("std");
// a sub module of this module, that may or may not have test declarations in it.
pub const eni = @import("eni.zig");
/// now imagine about 20 more sub modules...
pub const MyStruct = struct {
a: u8,
b: u8,
};
pub const MyStructArray = std.BoundedArray(MyStruct, 32);
test {
std.testing.refAllDeclsRecursive(@This());
}
when run with zig test the following compile error is emitted:
error: The Writer interface is only defined for BoundedArray(u8, ...) but the given type is BoundedArray(test.MyStruct, ...)
@compileError("The Writer interface is only defined for BoundedArray(u8, ...) " ++
This is because std.testing.refAllDeclsRecursive(@This());
reaches into MyStructArray and does this:
So the leading solution (in use by the standard library)
is to do something like this, which isnt too bad
const std = @import("std");
// a sub module of this module, that may or may not have test declarations in it.
pub const eni = @import("eni.zig");
/// now imagine about 20 more sub modules...
pub const MyStruct = struct {
a: u8,
b: u8,
};
pub const MyStructArray = std.BoundedArray(MyStruct, 32);
test {
_ = @import("eni.zig");
// 20 more of these...
}
or use the non-recursive version and put it at the bottom of all my files
Ahh okay, I didn’t think about refAllDeclsRecursive itself causing the reference.
Yeah we had a topic about this problem of not being able to avoid this error from comptime code that may not know that accessing a decl may trigger a @compileError here:
Some part of me thought that it would be nice if @compileError would just return a compileError-value that encapsulates the error and line information of the error, and then you could use comptime to inspect that error without it actually being thrown as an error. Only when this value gets compiled into the program in some way it would actually be triggered as an error.
Basically it would evaluate to a comptime value which then needs to disappear, but if it is referenced by / compiled into runtime code than it is triggered as error.
The value also could be opaque if the comptime code should not be able to access to much of the error message.
But I don’t understand the compiler enough, to say if that would work.
If the comptime type info was just enough to tell that the value resolves to a compile error, then refAllDecls could avoid referencing such declarations.
But from what Andrew wrote above, the refAllDecls is supposed to become unnecessary anyway, still being able to avoid @compileErrors could be useful for other code…
If you look at the fields of StructField next to the field (singular) of Declaration you’ll see a way out of this problem: add a .type field to Declaration. There are some issues discussing this, as well as having a compile_error type as a comptime equivalent of noreturn.
There are some difficulties with doing it that way without it forcing eager evaluation, but we need some sort of way to introspect declarations without halting the compilation process. It could be @TypeOfDecl(thing, "name"), I don’t mind that at all, as long as it solves the exploding reference problem.
Although the last bit probably isn’t needed because to get the type of a declaration it has be be analyzed.
I don’t actually care whether the function stays or goes, just about having a way to introspect declarations without causing a compile error. It’s a classic use/mention mismatch: we want some kind of way of saying “analyze this, but this function call will not put the type into use in the program, so just tell us if it won’t compile, don’t halt”.