This is actually a problem I’ve just encountered in my code. I think it’s interesting enough to warrant a post here.
The isSupported
function down below checks whether a data type is supported by my program. At the top part of the switch statement you can see the list of supported primitives. Composite types are handled near the bottom. They’re supported provided that they don’t contain (or point to) something unsupported.
fn isSupported(comptime T: type) bool {
return switch (@typeInfo(T)) {
.Type,
.Bool,
.Int,
.ComptimeInt,
.Float,
.ComptimeFloat,
.Void,
.Null,
.Undefined,
.ErrorSet,
.Enum,
.Opaque,
.Vector,
.EnumLiteral,
=> true,
.ErrorUnion => |eu| isSupported(eu.payload),
inline .Array, .Optional, .Pointer => |ar| isSupported(ar.child),
.Struct => |st| inline for (st.fields) |field| {
if (!field.is_comptime and !isSupported(field.type)) {
break false;
}
} else true,
.Union => |un| inline for (un.fields) |field| {
if (!isSupported(field.type)) {
break false;
}
} else true,
else => false,
};
}
This code breaks when it encounters a struct that refers to itself indirectly through a pointer. I ran into the issue with the following example:
pub const File = struct {
name: []const u8,
data: []const u8,
};
pub const Directory = struct {
name: []const u8,
entries: []const DirectoryEntry,
};
pub const DirectoryEntry = union(enum) {
file: File,
dir: Directory,
};
isSupported
would go into a infinite loop and die with an “evaluation exceeded 1000 backwards branches” error.