From e323cf1264f390911dcc2efea71d46be1d631d92 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sat, 27 Aug 2022 18:48:01 +0300 Subject: stage2: change how defers are stored in Zir Storing defers this way has the benefits that the defer doesn't get analyzed multiple times in AstGen, it takes up less space, and it makes Sema aware of defers allowing for 'unreachable else prong' error on error sets in generic code. The disadvantage is that it is a bit more complex and errdefers with payloads now emit a placeholder instruction (but those are rare). Sema.zig before: Total ZIR bytes: 3.7794370651245117MiB Instructions: 238996 (2.051319122314453MiB) String Table Bytes: 89.2802734375KiB Extra Data Items: 430144 (1.640869140625MiB) Sema.zig after: Total ZIR bytes: 3.3344192504882812MiB Instructions: 211829 (1.8181428909301758MiB) String Table Bytes: 89.2802734375KiB Extra Data Items: 374611 (1.4290275573730469MiB) --- src/Sema.zig | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) (limited to 'src/Sema.zig') diff --git a/src/Sema.zig b/src/Sema.zig index 15e891ef87..f5e4402ea8 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1461,6 +1461,29 @@ fn analyzeBodyInner( // break break_data.inst; // } //}, + .@"defer" => blk: { + const inst_data = sema.code.instructions.items(.data)[inst].@"defer"; + const defer_body = sema.code.extra[inst_data.index..][0..inst_data.len]; + const break_inst = sema.analyzeBodyInner(block, defer_body) catch |err| switch (err) { + error.ComptimeBreak => sema.comptime_break_inst, + else => |e| return e, + }; + if (break_inst != defer_body[defer_body.len - 1]) break always_noreturn; + break :blk Air.Inst.Ref.void_value; + }, + .defer_err_code => blk: { + const inst_data = sema.code.instructions.items(.data)[inst].defer_err_code; + const extra = sema.code.extraData(Zir.Inst.DeferErrCode, inst_data.payload_index).data; + const defer_body = sema.code.extra[extra.index..][0..extra.len]; + const err_code = try sema.resolveInst(inst_data.err_code); + try sema.inst_map.put(sema.gpa, extra.remapped_err_code, err_code); + const break_inst = sema.analyzeBodyInner(block, defer_body) catch |err| switch (err) { + error.ComptimeBreak => sema.comptime_break_inst, + else => |e| return e, + }; + if (break_inst != defer_body[defer_body.len - 1]) break always_noreturn; + break :blk Air.Inst.Ref.void_value; + }, }; if (sema.typeOf(air_inst).isNoReturn()) break always_noreturn; @@ -9394,11 +9417,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError } if (special_prong == .@"else" and seen_errors.count() == operand_ty.errorSetNames().len) { - - // TODO re-enable if defer implementation is improved - // https://github.com/ziglang/zig/issues/11798 - if (true) break :else_validation; - // In order to enable common patterns for generic code allow simple else bodies // else => unreachable, // else => return, @@ -9415,6 +9433,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError .as_node, .ret_node, .@"unreachable", + .@"defer", + .defer_err_code, + .err_union_code, + .ret_err_value_code, + .is_non_err, + .condbr, => {}, else => break, } else break :else_validation; -- cgit v1.2.3