[英]encountered `zig compiler bug: GenericPoison`?
我为基本的可组合迭代器编写了这段代码:
pub fn RangeIterator(comptime NumberType: type) type {
return struct {
const This = @This();
const Item = NumberType;
start: NumberType,
step: NumberType,
len: usize,
_index: usize = 0,
fn next(this: *This) !?Item {
if (this._index >= this.len) {
return null;
}
defer this._index += 1;
return this.start + (this.step * @intCast(NumberType, this._index));
}
};
}
test "range iterator" {
// these tests pass!
var iterator = RangeIterator(u32){.start = 1, .step = 3, .len = 5};
try std.testing.expectEqual(iterator.next(), 1);
try std.testing.expectEqual(iterator.next(), 4);
try std.testing.expectEqual(iterator.next(), 7);
try std.testing.expectEqual(iterator.next(), 10);
try std.testing.expectEqual(iterator.next(), 13);
try std.testing.expectEqual(iterator.next(), null);
}
// based on pattern used for BufferedWriter & bufferedWriter
// https://github.com/ziglang/zig/blob/master/lib/std/io/buffered_writer.zig
pub fn IterWhile(
comptime IteratorType: type,
comptime ItemType: type,
comptime include_last: bool,
) type {
return struct {
const This = @This();
const Item = ItemType;
iterator: IteratorType,
predicate: fn (ItemType) bool,
_is_spent: bool = false,
pub fn next(this: *This) ?ItemType {
if (this._is_spent) {
return null;
}
const result = try this.iterator.next();
if (result == null) {
return null;
}
if (!this.predicate(result)) {
this._is_spent = true;
if (!include_last) return null;
}
return result;
}
};
}
pub fn iterWhile(
iterator: anytype,
predicate: fn (anytype) bool,
comptime include_last: bool,
) IterWhile(
@TypeOf(iterator),
@typeInfo(predicate).Fn.args[0].arg_type,
include_last,
) {
return .{ .iterator = iterator, .predicate = predicate };
}
test "iter while" {
// these tests generate a compiler error :S
var range = RangeIterator(u32){.start = 1, .step = 3, .len = 5};
var iterator = iterWhile(range, TestUtils.isOneDigit, false);
try std.testing.expectEqual(iterator.next(), 1);
try std.testing.expectEqual(iterator.next(), 4);
try std.testing.expectEqual(iterator.next(), 7);
try std.testing.expectEqual(iterator.next(), null);
}
const TestUtils = struct {
fn isOneDigit(value: u32) bool {
return value < 10;
}
};
如果我注释掉第二个测试块"iter while"
,则测试通过。 但是如果我把它们留在里面,我会收到以下错误:
thread 1531026 panic: zig compiler bug: GenericPoison
Unable to dump stack trace: debug info stripped
zsh: abort zig test src/utils/iterator.zig
debug info stripped
-> 为什么会这样? 我不是通过不传递任何发布构建标志在调试模式下运行它吗?虽然错误消息是由于编译器中的错误引起的,但您的代码中存在一些错误,解决后允许代码按预期编译和运行:
fn(u32) bool
不可分配给fn(anytype) bool
。 anytype
是一个特殊值,可以在参数中使用以指定参数应该是通用的,并为传入的每个不同类型制作函数的新副本。更改predicate: fn(anytype) bool
→ predicate: anytype
修复了这个问题在此之后,其余问题都有正确的错误消息(尽管接下来的一些问题不会以颜色显示,并注意存在与其显示相关的 zig 编译器错误: Zig compiler bug: attempted to destroy declaration with an attached error
)
@typeInfo(predicate)
- 这里的 predicate 是fn(u32) bool
类型,所以你需要使用@TypeOf
: @typeInfo(@TypeOf(predicate))
.arg_type
- 这是一个可选的。 null 值表示参数类型设置为anytype
。 使用.arg_type.?
这里。 请注意,在较新版本的 zig 中,它已更改为.Fn.params[0].type.?
predicate: fn(ItemType) bool
- 这导致结构成为仅编译时间。 要使其在运行时可用,请使用函数指针: *const fn(ItemType) bool
和.predicate = &predicate
。 这个错误消息不是很有帮助——它说函数在 comptime 被调用,因为它的返回类型是 comptime-only,但没有解释为什么会这样。
this.predicate(result)
- 这里的 result 是可选的。 由于您在上面测试了 null,因此您可以安全地使用result.?
在这里或者您可以更改代码,因此 result 不再是orelse
的可选项:
const result = (try this.iterator.next()) orelse return null;
现在测试将通过
有关编译器错误的信息:
thread 1531026 panic: zig compiler bug: GenericPoison
Unable to dump stack trace: debug info stripped
zsh: abort zig test src/utils/iterator.zig
zig 编译器错误
此消息表明该错误是 zig 编译器中的错误; 你不应该看到它。 编译器错误可能表明:
在这里,代码应该导致关于fn(u32) bool
not being assignable to fn(anytype) bool
的编译错误,但是编译器某处存在错误导致它说GenericPoison
预期的错误消息:
a.zig:xx:xx: error: expected type 'fn(anytype) bool', found 'fn(u32) bool'
最小复制:
const std = @import("std");
pub fn iterWhile(
predicate: fn (anytype) bool,
) void {
_ = predicate;
}
test "iter while" {
iterWhile(isOneDigit);
}
fn isOneDigit(value: u32) bool {
return value < 10;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.