ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
34.84k stars 2.55k forks source link

@errorCast into an inferred error set causes compiler crash #21222

Open NicoElbers opened 2 months ago

NicoElbers commented 2 months ago

Zig Version

0.14.0-dev.1307+849c31a6c

Steps to Reproduce and Observed Behavior

bug.zig:

fn func() !void {
    return;
}

pub fn main() !void {
    const res = func();

    const err = @as(@TypeOf(res), @errorCast(error.Err));
    _ = try err;
}

run zig build-exe bug.zig

observe:

❯ zig build-exe bug.zig
[4]    99609 segmentation fault (core dumped)  zig build-exe bug.zig

full dump of a debug compiler here: https://pastebin.com/9bncrwdm

Expected Behavior

A compiling program, as what would happen if func returned anyerror!void

NicoElbers commented 2 months ago

for additional information, a program where error.Err should be in the inferred error set also crashes:

fn func() !void {
    return error.Err;
}

pub fn main() !void {
    const res = func();

    const err = @as(@TypeOf(res), @errorCast(error.Err));
    _ = try err;
}
nektro commented 2 months ago
debug compiler stack trace ``` thread 104550 panic: reached unreachable code Analyzing bug.zig %9 = ret_type() node_offset:5:1 to :5:7 %10 = dbg_stmt(2, 5) %11 = decl_val("func") token_offset:6:17 to :6:21 %12 = dbg_stmt(2, 21) %13 = call(.auto, %11, []) node_offset:6:17 to :6:23 %14 = dbg_var_val(%13, "res") %15 = save_err_ret_index(%13) %16 = dbg_stmt(4, 5) %17 = block_comptime({ %18 = typeof_builtin({ %19 = break_inline(%18, %13) }) node_offset:8:21 to :8:33 %20 = break(%17, %18) }) node_offset:8:21 to :8:33 %21 = dbg_stmt(4, 35) %22 = error_value("Err") token_offset:8:52 to :8:55 > %23 = extended(error_cast(%17, %22)) node_offset:8:35 to :8:56 %24 = as_node(%17, %23) node_offset:8:35 to :8:56 %25 = dbg_var_val(%24, "err") %26 = save_err_ret_index(%24) %27 = dbg_stmt(5, 9) %28 = try(%24, { %29 = err_union_code(%24) node_offset:9:9 to :9:16 %30 = dbg_stmt(5, 9) %31 = ret_node(%29) node_offset:9:9 to :9:16 }) node_offset:9:9 to :9:16 %32 = ensure_result_non_error(%28) node_offset:9:9 to :9:16 %33 = restore_err_ret_index_unconditional(.none) node_offset:5:1 to :5:7 %34 = ret_implicit(@void_value) token_offset:10:1 to :10:1 For full context, use the command zig ast-check -t bug.zig in /home/nico/personal-projects/zig/compiler/stage3/lib/zig/std/start.zig > %1937 = is_non_err(%1936) in /home/nico/personal-projects/zig/compiler/stage3/lib/zig/std/start.zig > %1939 = block({%1934..%1938}) in /home/nico/personal-projects/zig/compiler/stage3/lib/zig/std/start.zig > %1901 = switch_block(%1897, else => {%1919..%2022}, @void_type => {%1902..%1910}, @noreturn_type, @u8_type => {%1911..%1918}) in /home/nico/personal-projects/zig/compiler/stage3/lib/zig/std/start.zig > %1698 = call(.auto, %1696, []) in /home/nico/personal-projects/zig/compiler/stage3/lib/zig/std/start.zig > %1533 = call(.auto, %1531, [ {%1534}, {%1535}, {%1536}, ]) in /home/nico/personal-projects/zig/compiler/stage3/lib/zig/std/start.zig > %1530 = field_call(nodiscard .auto, %1528, "exit", [ {%1531..%1537}, ]) /home/nico/personal-projects/zig/compiler/src/Type.zig:3003:22: 0xb5e66c5 in errorSetNames (zig) .none => unreachable, // unresolved inferred error set ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:22993:53: 0xb1a95e1 in zirErrorCast (zig) const dest_err_names = dest_ty.errorSetNames(mod); ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:1272:65: 0xacfab8b in analyzeBodyInner (zig) .error_cast => try sema.zirErrorCast( block, extended), ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:915:26: 0xb5fbde1 in analyzeFnBody (zig) sema.analyzeBodyInner(block, body) catch |err| switch (err) { ^ /home/nico/personal-projects/zig/compiler/src/Zcu/PerThread.zig:2176:23: 0xb0b752d in analyzeFnBody (zig) sema.analyzeFnBody(&inner_block, fn_info.body) catch |err| switch (err) { ^ /home/nico/personal-projects/zig/compiler/src/Zcu/PerThread.zig:792:35: 0xacae04d in ensureFuncBodyAnalyzedInner (zig) var air = try pt.analyzeFnBody(func_index); ^ /home/nico/personal-projects/zig/compiler/src/Zcu/PerThread.zig:698:81: 0xa86a713 in ensureFuncBodyAnalyzed (zig) const ies_outdated, const analysis_fail = if (pt.ensureFuncBodyAnalyzedInner(func_index, func_outdated)) |result| ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:35950:38: 0xad2114d in resolveInferredErrorSet (zig) try pt.ensureFuncBodyAnalyzed(func_index); ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:32616:69: 0xb1d6421 in analyzeIsNonErrComptimeOnly (zig) const resolved_ty = try sema.resolveInferredErrorSet(block, src, set_ty); ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:32645:56: 0xb67e8c9 in analyzeIsNonErr (zig) const result = try sema.analyzeIsNonErrComptimeOnly(block, src, operand); ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:19294:32: 0xb12cc22 in zirIsNonErr (zig) return sema.analyzeIsNonErr(block, src, operand); ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:1087:66: 0xacf4729 in analyzeBodyInner (zig) .is_non_err => try sema.zirIsNonErr(block, inst), ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:6016:34: 0xb6a8db8 in resolveBlockBody (zig) if (sema.analyzeBodyInner(child_block, body)) |_| { ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:5993:33: 0xb1d9378 in zirBlock (zig) return sema.resolveBlockBody(parent_block, src, &child_block, body, inst, &label.merges); ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:1593:49: 0xad011f7 in analyzeBodyInner (zig) break :blk try sema.zirBlock(block, inst, tags[@intFromEnum(inst)] == .block_comptime); ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:6016:34: 0xb6a8db8 in resolveBlockBody (zig) if (sema.analyzeBodyInner(child_block, body)) |_| { ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:10972:45: 0xb69f5fd in resolveProngComptime (zig) return sema.resolveBlockBody(spa.parent_block, src, child_block, prong_body, spa.switch_block_inst, merges); ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:13244:36: 0xb69f1e5 in resolveSwitchComptime (zig) return spa.resolveProngComptime( ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:12364:37: 0xb13d8f8 in zirSwitchBlock (zig) return resolveSwitchComptime( ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:1110:69: 0xacf5555 in analyzeBodyInner (zig) .switch_block => try sema.zirSwitchBlock(block, inst, false), ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:915:26: 0xb5fbde1 in analyzeFnBody (zig) sema.analyzeBodyInner(block, body) catch |err| switch (err) { ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:7812:31: 0xb1f2df4 in analyzeCall (zig) sema.analyzeFnBody(&child_block, fn_info.body) catch |err| switch (err) { ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:6986:43: 0xb11d298 in zirCall__anon_408486 (zig) const call_inst = try sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, args_info, call_dbg_node, .call); ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:1045:62: 0xacf2ce9 in analyzeBodyInner (zig) .call => try sema.zirCall(block, inst, .direct), ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:915:26: 0xb5fbde1 in analyzeFnBody (zig) sema.analyzeBodyInner(block, body) catch |err| switch (err) { ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:7812:31: 0xb1f2df4 in analyzeCall (zig) sema.analyzeFnBody(&child_block, fn_info.body) catch |err| switch (err) { ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:6986:43: 0xb11d298 in zirCall__anon_408486 (zig) const call_inst = try sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, args_info, call_dbg_node, .call); ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:1045:62: 0xacf2ce9 in analyzeBodyInner (zig) .call => try sema.zirCall(block, inst, .direct), ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:933:30: 0xa89a2d7 in analyzeInlineBody (zig) if (sema.analyzeBodyInner(block, body)) |_| { ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:959:39: 0xa57ea3e in resolveInlineBody (zig) return (try sema.analyzeInlineBody(block, body, break_target)) orelse .unreachable_value; ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:7278:65: 0xb74acb5 in analyzeArg (zig) const uncoerced_arg = try sema.resolveInlineBody(block, arg_body, zir_call.call_inst); ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:7865:49: 0xb1f430b in analyzeCall (zig) arg_out.* = try args_info.analyzeArg(sema, block, arg_idx, param_ty, func_ty_info, func); ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:6986:43: 0xb11e5d3 in zirCall__anon_408488 (zig) const call_inst = try sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, args_info, call_dbg_node, .call); ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:1046:62: 0xacf2d86 in analyzeBodyInner (zig) .field_call => try sema.zirCall(block, inst, .field), ^ /home/nico/personal-projects/zig/compiler/src/Sema.zig:915:26: 0xb5fbde1 in analyzeFnBody (zig) sema.analyzeBodyInner(block, body) catch |err| switch (err) { ^ /home/nico/personal-projects/zig/compiler/src/Zcu/PerThread.zig:2176:23: 0xb0b752d in analyzeFnBody (zig) sema.analyzeFnBody(&inner_block, fn_info.body) catch |err| switch (err) { ^ /home/nico/personal-projects/zig/compiler/src/Zcu/PerThread.zig:792:35: 0xacae04d in ensureFuncBodyAnalyzedInner (zig) var air = try pt.analyzeFnBody(func_index); ^ /home/nico/personal-projects/zig/compiler/src/Zcu/PerThread.zig:698:81: 0xa86a713 in ensureFuncBodyAnalyzed (zig) const ies_outdated, const analysis_fail = if (pt.ensureFuncBodyAnalyzedInner(func_index, func_outdated)) |result| ^ /home/nico/personal-projects/zig/compiler/src/Compilation.zig:3693:38: 0xa554237 in processOneJob (zig) pt.ensureFuncBodyAnalyzed(func) catch |err| switch (err) { ^ /home/nico/personal-projects/zig/compiler/src/Compilation.zig:3638:30: 0xa2d5d51 in performAllTheWorkInner (zig) try processOneJob(@intFromEnum(Zcu.PerThread.Id.main), comp, job, main_progress_node); ^ /home/nico/personal-projects/zig/compiler/src/Compilation.zig:3508:36: 0xa16d460 in performAllTheWork (zig) try comp.performAllTheWorkInner(main_progress_node); ^ /home/nico/personal-projects/zig/compiler/src/Compilation.zig:2269:31: 0xa168c09 in update (zig) try comp.performAllTheWork(main_progress_node); ^ /home/nico/personal-projects/zig/compiler/src/main.zig:4453:20: 0xa16eb7d in updateModule (zig) try comp.update(prog_node); ^ /home/nico/personal-projects/zig/compiler/src/main.zig:3500:21: 0xa1d7f0a in buildOutputType (zig) updateModule(comp, color, root_prog_node) catch |err| switch (err) { ^ /home/nico/personal-projects/zig/compiler/src/main.zig:258:31: 0xa020046 in mainArgs (zig) return buildOutputType(gpa, arena, args, .{ .build = .Exe }); ^ /home/nico/personal-projects/zig/compiler/src/main.zig:199:20: 0xa01d015 in main (zig) return mainArgs(gpa, arena, args); ^ /nix/store/046rjdgb75qdq31pqjx0hqy9gdg8m8gv-zig-0.14.0-dev.1261+c26206112/lib/std/start.zig:614:37: 0xa01cb3e in main (zig) const result = root.main() catch |err| { ^ ???:?:?: 0x7f825837714d in ??? (libc.so.6) Unwind information for `libc.so.6:0x7f825837714d` was not available, trace may be incomplete [2] 104550 IOT instruction (core dumped) ../../compiler/stage3/bin/zig build-exe bug.zig ```
rohlem commented 2 months ago

Maybe known, but you can work around the current bug by stripping the error set's identity (undocumented - https://github.com/ziglang/zig/issues/20862):

fn func() !void {
    return;
}
fn StripErrorSetIdentity(T: type) type {
    return switch (@typeInfo(T)) {
        else => |tag| @compileError("invalid input type: " ++ @typeName(T) ++ " | " ++ @tagName(tag)),
        .ErrorSet => T || error{},
        .ErrorUnion => |u| StripErrorSetIdentity(u.error_set)!u.payload,
    };
}
pub fn main() !void {
    const res = func();
    const Res = StripErrorSetIdentity(@TypeOf(res));

    const err = @as(Res, @errorCast(error.Err));
    _ = try err;
}