Hi everyone … new to zig
I’m exploring the language and I found something curious.
Example function
pub fn func1(a: u32) !void {
_ = a;
}
It returns !void
and this expands to @typeInfo(@typeInfo(@TypeOf(test1.func1)).Fn.return_type.?).ErrorUnion.error_set!void
I wanted to put the expanded form as my return type but it gives an error.
pub fn func1(a: u32) @typeInfo(@typeInfo(@TypeOf(test1.func1)).Fn.return_type.?).ErrorUnion.error_set!void {
_ = a;
}
error: use of undeclared identifier 'test1'
That is the name of the file test1.zig
but why is that in the type?
So, I removed that part.
pub fn func1(a: u32) @typeInfo(@typeInfo(@TypeOf(func1)).Fn.return_type.?).ErrorUnion.error_set!void {
_ = a;
}
And I get a new error
error: dependency loop detected
So, how can I use the expanded form as a return type?
The expression
@typeInfo(@typeInfo(@TypeOf(func1)).Fn.return_type.?).ErrorUnion.error_set
isn’t an expanded form of the error set part of the return type of func1
, it’s just a way to refer to the error set from somewhere else in the program. The compiler is giving you a dependency loop error because you can’t use the return type of func1
inside the definition of the return type of func1
.
Interesting …
How I got to this point was:
const test1 = @import("test1.zig");
comptime {
@compileLog(@TypeOf(@field(test1, "func1")));
}
Compile Log Output:
@as(type, fn(u32) @typeInfo(@typeInfo(@TypeOf(test1.func1)).Fn.return_type.?).ErrorUnion.error_set!void)
If that isn’t the true expansion, why is it returning this making it seem to be so and what should it be? What would work as an expanded form?
It’s because the error set is inferred. The explicit return type would be error{}!void
because it can’t return any errors (or just void
if you don’t want the return type to be an error union).
Error sets are of type type
, so printing (or compileLog
ing) an error set is printing the name of the type. It seems that inferred error sets are distinct types, so you end up printing that verbose type name.
Even though both the inferred error set of foo1
and the explicit error set error{}
are error set types with an empty list of errors, they are distinct types.
pub fn func1(a: u32) !void {
_ = a;
}
test {
@compileLog(error{} == @typeInfo(@typeInfo(@TypeOf(func1)).Fn.return_type.?).ErrorUnion.error_set);
}
Compile Log Output:
@as(bool, false)
1 Like
Thank you for your reply.
I am trying to compare function definitions in comptime. I’m trying to see if one struct has the same declarations in another.
The fact that they are distinct types will make this much harder to do.
Thanks for your help.
A bit annoying and verbose, but one way to print an inferred error set is to access its type info and print out the slice of errors. I definitely learned something looking into this!
pub fn func1(a: u32) !void {
_ = a;
}
test {
const ReturnType = @typeInfo(@TypeOf(func1)).Fn.return_type.?;
const ReturnErrors = @typeInfo(ReturnType).ErrorUnion.error_set;
@compileLog(@typeInfo(ReturnErrors).ErrorSet);
}
Compile Log Output:
@as(?[]const builtin.Type.Error, { })
If you are interested in what is going on with @typeInfo
, you can look at builtin.zig
in the standard library, specifically the Type union
. Of course that is kind of “in the weeds” and not super important to learning/using Zig day to day.
6 Likes