std.zig.Zir: fix declaration traversal

The old logic here had bitrotted, largely because there were some
incorrect `else` cases. This is now implemented correctly for all
current ZIR instructions. This prevents instructions being lost in
incremental updates, which is important for updates to be minimal.
This commit is contained in:
mlugg 2024-08-16 17:34:30 +01:00 committed by Jacob Young
parent 84c2ebd6c6
commit 89f02d1c10
2 changed files with 614 additions and 62 deletions

View File

@ -603,7 +603,7 @@ pub const Inst = struct {
/// Uses the `un_node` field.
typeof,
/// Implements `@TypeOf` for one operand.
/// Uses the `pl_node` field.
/// Uses the `pl_node` field. Payload is `Block`.
typeof_builtin,
/// Given a value, look at the type of it, which must be an integer type.
/// Returns the integer type for the RHS of a shift operation.
@ -2727,6 +2727,9 @@ pub const Inst = struct {
field_name_start: NullTerminatedString,
};
/// There is a body of instructions at `extra[body_index..][0..body_len]`.
/// Trailing:
/// 0. operand: Ref // for each `operands_len`
pub const TypeOfPeer = struct {
src_node: i32,
body_len: u32,
@ -2844,6 +2847,40 @@ pub const Inst = struct {
src_line: u32,
};
/// Trailing:
/// 0. multi_cases_len: u32 // if `has_multi_cases`
/// 1. err_capture_inst: u32 // if `any_uses_err_capture`
/// 2. non_err_body {
/// info: ProngInfo,
/// inst: Index // for every `info.body_len`
/// }
/// 3. else_body { // if `has_else`
/// info: ProngInfo,
/// inst: Index // for every `info.body_len`
/// }
/// 4. scalar_cases: { // for every `scalar_cases_len`
/// item: Ref,
/// info: ProngInfo,
/// inst: Index // for every `info.body_len`
/// }
/// 5. multi_cases: { // for every `multi_cases_len`
/// items_len: u32,
/// ranges_len: u32,
/// info: ProngInfo,
/// item: Ref // for every `items_len`
/// ranges: { // for every `ranges_len`
/// item_first: Ref,
/// item_last: Ref,
/// }
/// inst: Index // for every `info.body_len`
/// }
///
/// When analyzing a case body, the switch instruction itself refers to the
/// captured error, or to the success value in `non_err_body`. Whether this
/// is captured by reference or by value depends on whether the `byref` bit
/// is set for the corresponding body. `err_capture_inst` refers to the error
/// capture outside of the `switch`, i.e. `err` in
/// `x catch |err| switch (err) { ... }`.
pub const SwitchBlockErrUnion = struct {
operand: Ref,
bits: Bits,
@ -3153,7 +3190,7 @@ pub const Inst = struct {
/// 1. captures_len: u32 // if has_captures_len
/// 2. body_len: u32, // if has_body_len
/// 3. fields_len: u32, // if has_fields_len
/// 4. decls_len: u37, // if has_decls_len
/// 4. decls_len: u32, // if has_decls_len
/// 5. capture: Capture // for every captures_len
/// 6. decl: Index, // for every decls_len; points to a `declaration` instruction
/// 7. inst: Index // for every body_len
@ -3624,33 +3661,492 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
}
}
/// The iterator would have to allocate memory anyway to iterate. So here we populate
/// an ArrayList as the result.
pub fn findDecls(zir: Zir, list: *std.ArrayList(Inst.Index), decl_inst: Zir.Inst.Index) !void {
/// Find all type declarations, recursively, within a `declaration` instruction. Does not recurse through
/// said type declarations' declarations; to find all declarations, call this function on the declarations
/// of the discovered types recursively.
/// The iterator would have to allocate memory anyway to iterate, so an `ArrayList` is populated as the result.
pub fn findDecls(zir: Zir, gpa: Allocator, list: *std.ArrayListUnmanaged(Inst.Index), decl_inst: Zir.Inst.Index) !void {
list.clearRetainingCapacity();
const declaration, const extra_end = zir.getDeclaration(decl_inst);
const bodies = declaration.getBodies(extra_end, zir);
try zir.findDeclsBody(list, bodies.value_body);
if (bodies.align_body) |b| try zir.findDeclsBody(list, b);
if (bodies.linksection_body) |b| try zir.findDeclsBody(list, b);
if (bodies.addrspace_body) |b| try zir.findDeclsBody(list, b);
// `defer` instructions duplicate the same body arbitrarily many times, but we only want to traverse
// their contents once per defer. So, we store the extra index of the body here to deduplicate.
var found_defers: std.AutoHashMapUnmanaged(u32, void) = .{};
defer found_defers.deinit(gpa);
try zir.findDeclsBody(gpa, list, &found_defers, bodies.value_body);
if (bodies.align_body) |b| try zir.findDeclsBody(gpa, list, &found_defers, b);
if (bodies.linksection_body) |b| try zir.findDeclsBody(gpa, list, &found_defers, b);
if (bodies.addrspace_body) |b| try zir.findDeclsBody(gpa, list, &found_defers, b);
}
fn findDeclsInner(
zir: Zir,
list: *std.ArrayList(Inst.Index),
gpa: Allocator,
list: *std.ArrayListUnmanaged(Inst.Index),
defers: *std.AutoHashMapUnmanaged(u32, void),
inst: Inst.Index,
) Allocator.Error!void {
const tags = zir.instructions.items(.tag);
const datas = zir.instructions.items(.data);
switch (tags[@intFromEnum(inst)]) {
.declaration => unreachable,
// Boring instruction tags first. These have no body and are not declarations or type declarations.
.add,
.addwrap,
.add_sat,
.add_unsafe,
.sub,
.subwrap,
.sub_sat,
.mul,
.mulwrap,
.mul_sat,
.div_exact,
.div_floor,
.div_trunc,
.mod,
.rem,
.mod_rem,
.shl,
.shl_exact,
.shl_sat,
.shr,
.shr_exact,
.param_anytype,
.param_anytype_comptime,
.array_cat,
.array_mul,
.array_type,
.array_type_sentinel,
.vector_type,
.elem_type,
.indexable_ptr_elem_type,
.vector_elem_type,
.indexable_ptr_len,
.anyframe_type,
.as_node,
.as_shift_operand,
.bit_and,
.bitcast,
.bit_not,
.bit_or,
.bool_not,
.bool_br_and,
.bool_br_or,
.@"break",
.break_inline,
.check_comptime_control_flow,
.builtin_call,
.cmp_lt,
.cmp_lte,
.cmp_eq,
.cmp_gte,
.cmp_gt,
.cmp_neq,
.error_set_decl,
.dbg_stmt,
.dbg_var_ptr,
.dbg_var_val,
.decl_ref,
.decl_val,
.load,
.div,
.elem_ptr_node,
.elem_ptr,
.elem_val_node,
.elem_val,
.elem_val_imm,
.ensure_result_used,
.ensure_result_non_error,
.ensure_err_union_payload_void,
.error_union_type,
.error_value,
.@"export",
.export_value,
.field_ptr,
.field_val,
.field_ptr_named,
.field_val_named,
.import,
.int,
.int_big,
.float,
.float128,
.int_type,
.is_non_null,
.is_non_null_ptr,
.is_non_err,
.is_non_err_ptr,
.ret_is_non_err,
.repeat,
.repeat_inline,
.for_len,
.merge_error_sets,
.ref,
.ret_node,
.ret_load,
.ret_implicit,
.ret_err_value,
.ret_err_value_code,
.ret_ptr,
.ret_type,
.ptr_type,
.slice_start,
.slice_end,
.slice_sentinel,
.slice_length,
.store_node,
.store_to_inferred_ptr,
.str,
.negate,
.negate_wrap,
.typeof,
.typeof_log2_int_type,
.@"unreachable",
.xor,
.optional_type,
.optional_payload_safe,
.optional_payload_unsafe,
.optional_payload_safe_ptr,
.optional_payload_unsafe_ptr,
.err_union_payload_unsafe,
.err_union_payload_unsafe_ptr,
.err_union_code,
.err_union_code_ptr,
.enum_literal,
.validate_deref,
.validate_destructure,
.field_type_ref,
.opt_eu_base_ptr_init,
.coerce_ptr_elem_ty,
.validate_ref_ty,
.struct_init_empty,
.struct_init_empty_result,
.struct_init_empty_ref_result,
.struct_init_anon,
.struct_init,
.struct_init_ref,
.validate_struct_init_ty,
.validate_struct_init_result_ty,
.validate_ptr_struct_init,
.struct_init_field_type,
.struct_init_field_ptr,
.array_init_anon,
.array_init,
.array_init_ref,
.validate_array_init_ty,
.validate_array_init_result_ty,
.validate_array_init_ref_ty,
.validate_ptr_array_init,
.array_init_elem_type,
.array_init_elem_ptr,
.union_init,
.type_info,
.size_of,
.bit_size_of,
.int_from_ptr,
.compile_error,
.set_eval_branch_quota,
.int_from_enum,
.align_of,
.int_from_bool,
.embed_file,
.error_name,
.panic,
.trap,
.set_runtime_safety,
.sqrt,
.sin,
.cos,
.tan,
.exp,
.exp2,
.log,
.log2,
.log10,
.abs,
.floor,
.ceil,
.trunc,
.round,
.tag_name,
.type_name,
.frame_type,
.frame_size,
.int_from_float,
.float_from_int,
.ptr_from_int,
.enum_from_int,
.float_cast,
.int_cast,
.ptr_cast,
.truncate,
.has_decl,
.has_field,
.clz,
.ctz,
.pop_count,
.byte_swap,
.bit_reverse,
.bit_offset_of,
.offset_of,
.splat,
.reduce,
.shuffle,
.atomic_load,
.atomic_rmw,
.atomic_store,
.mul_add,
.memcpy,
.memset,
.min,
.max,
.alloc,
.alloc_mut,
.alloc_comptime_mut,
.alloc_inferred,
.alloc_inferred_mut,
.alloc_inferred_comptime,
.alloc_inferred_comptime_mut,
.resolve_inferred_alloc,
.make_ptr_const,
.@"resume",
.@"await",
.save_err_ret_index,
.restore_err_ret_index_unconditional,
.restore_err_ret_index_fn_entry,
=> return,
.extended => {
const extended = datas[@intFromEnum(inst)].extended;
switch (extended.opcode) {
.value_placeholder => unreachable,
// Once again, we start with the boring tags.
.variable,
.this,
.ret_addr,
.builtin_src,
.error_return_trace,
.frame,
.frame_address,
.alloc,
.builtin_extern,
.@"asm",
.asm_expr,
.compile_log,
.min_multi,
.max_multi,
.add_with_overflow,
.sub_with_overflow,
.mul_with_overflow,
.shl_with_overflow,
.c_undef,
.c_include,
.c_define,
.wasm_memory_size,
.wasm_memory_grow,
.prefetch,
.fence,
.set_float_mode,
.set_align_stack,
.set_cold,
.error_cast,
.await_nosuspend,
.breakpoint,
.disable_instrumentation,
.select,
.int_from_error,
.error_from_int,
.builtin_async_call,
.cmpxchg,
.c_va_arg,
.c_va_copy,
.c_va_end,
.c_va_start,
.ptr_cast_full,
.ptr_cast_no_dest,
.work_item_id,
.work_group_size,
.work_group_id,
.in_comptime,
.restore_err_ret_index,
.closure_get,
.field_parent_ptr,
=> return,
// `@TypeOf` has a body.
.typeof_peer => {
const extra = zir.extraData(Zir.Inst.TypeOfPeer, extended.operand);
const body = zir.bodySlice(extra.data.body_index, extra.data.body_len);
try zir.findDeclsBody(gpa, list, defers, body);
},
// Reifications and opaque declarations need tracking, but have no body.
.reify, .opaque_decl => return list.append(gpa, inst),
// Struct declarations need tracking and have bodies.
.struct_decl => {
try list.append(gpa, inst);
const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
const extra = zir.extraData(Zir.Inst.StructDecl, extended.operand);
var extra_index = extra.end;
const captures_len = if (small.has_captures_len) blk: {
const captures_len = zir.extra[extra_index];
extra_index += 1;
break :blk captures_len;
} else 0;
const fields_len = if (small.has_fields_len) blk: {
const fields_len = zir.extra[extra_index];
extra_index += 1;
break :blk fields_len;
} else 0;
const decls_len = if (small.has_decls_len) blk: {
const decls_len = zir.extra[extra_index];
extra_index += 1;
break :blk decls_len;
} else 0;
extra_index += captures_len;
if (small.has_backing_int) {
const backing_int_body_len = zir.extra[extra_index];
extra_index += 1;
if (backing_int_body_len == 0) {
extra_index += 1; // backing_int_ref
} else {
const body = zir.bodySlice(extra_index, backing_int_body_len);
extra_index += backing_int_body_len;
try zir.findDeclsBody(gpa, list, defers, body);
}
}
extra_index += decls_len;
// This ZIR is structured in a slightly awkward way, so we have to split up the iteration.
// `extra_index` iterates `flags` (bags of bits).
// `fields_extra_index` iterates `fields`.
// We accumulate the total length of bodies into `total_bodies_len`. This is sufficient because
// the bodies are packed together in `extra` and we only need to traverse their instructions (we
// don't really care about the structure).
const bits_per_field = 4;
const fields_per_u32 = 32 / bits_per_field;
const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
var cur_bit_bag: u32 = undefined;
var fields_extra_index = extra_index + bit_bags_count;
var total_bodies_len: u32 = 0;
for (0..fields_len) |field_i| {
if (field_i % fields_per_u32 == 0) {
cur_bit_bag = zir.extra[extra_index];
extra_index += 1;
}
const has_align = @as(u1, @truncate(cur_bit_bag)) != 0;
cur_bit_bag >>= 1;
const has_init = @as(u1, @truncate(cur_bit_bag)) != 0;
cur_bit_bag >>= 2; // also skip `is_comptime`; we don't care
const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0;
cur_bit_bag >>= 1;
fields_extra_index += @intFromBool(!small.is_tuple); // field_name
fields_extra_index += 1; // doc_comment
if (has_type_body) {
const field_type_body_len = zir.extra[fields_extra_index];
total_bodies_len += field_type_body_len;
}
fields_extra_index += 1; // field_type or field_type_body_len
if (has_align) {
const align_body_len = zir.extra[fields_extra_index];
fields_extra_index += 1;
total_bodies_len += align_body_len;
}
if (has_init) {
const init_body_len = zir.extra[fields_extra_index];
fields_extra_index += 1;
total_bodies_len += init_body_len;
}
}
// Now, `fields_extra_index` points to `bodies`. Let's treat this as one big body.
const merged_bodies = zir.bodySlice(fields_extra_index, total_bodies_len);
try zir.findDeclsBody(gpa, list, defers, merged_bodies);
},
// Union declarations need tracking and have a body.
.union_decl => {
try list.append(gpa, inst);
const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand);
var extra_index = extra.end;
extra_index += @intFromBool(small.has_tag_type);
const captures_len = if (small.has_captures_len) blk: {
const captures_len = zir.extra[extra_index];
extra_index += 1;
break :blk captures_len;
} else 0;
const body_len = if (small.has_body_len) blk: {
const body_len = zir.extra[extra_index];
extra_index += 1;
break :blk body_len;
} else 0;
extra_index += @intFromBool(small.has_fields_len);
const decls_len = if (small.has_decls_len) blk: {
const decls_len = zir.extra[extra_index];
extra_index += 1;
break :blk decls_len;
} else 0;
extra_index += captures_len;
extra_index += decls_len;
const body = zir.bodySlice(extra_index, body_len);
try zir.findDeclsBody(gpa, list, defers, body);
},
// Enum declarations need tracking and have a body.
.enum_decl => {
try list.append(gpa, inst);
const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);
const extra = zir.extraData(Zir.Inst.EnumDecl, extended.operand);
var extra_index = extra.end;
extra_index += @intFromBool(small.has_tag_type);
const captures_len = if (small.has_captures_len) blk: {
const captures_len = zir.extra[extra_index];
extra_index += 1;
break :blk captures_len;
} else 0;
const body_len = if (small.has_body_len) blk: {
const body_len = zir.extra[extra_index];
extra_index += 1;
break :blk body_len;
} else 0;
extra_index += @intFromBool(small.has_fields_len);
const decls_len = if (small.has_decls_len) blk: {
const decls_len = zir.extra[extra_index];
extra_index += 1;
break :blk decls_len;
} else 0;
extra_index += captures_len;
extra_index += decls_len;
const body = zir.bodySlice(extra_index, body_len);
try zir.findDeclsBody(gpa, list, defers, body);
},
}
},
// Functions instructions are interesting and have a body.
.func,
.func_inferred,
=> {
try list.append(inst);
try list.append(gpa, inst);
const inst_data = datas[@intFromEnum(inst)].pl_node;
const extra = zir.extraData(Inst.Func, inst_data.payload_index);
@ -3661,14 +4157,14 @@ fn findDeclsInner(
else => {
const body = zir.bodySlice(extra_index, extra.data.ret_body_len);
extra_index += body.len;
try zir.findDeclsBody(list, body);
try zir.findDeclsBody(gpa, list, defers, body);
},
}
const body = zir.bodySlice(extra_index, extra.data.body_len);
return zir.findDeclsBody(list, body);
return zir.findDeclsBody(gpa, list, defers, body);
},
.func_fancy => {
try list.append(inst);
try list.append(gpa, inst);
const inst_data = datas[@intFromEnum(inst)].pl_node;
const extra = zir.extraData(Inst.FuncFancy, inst_data.payload_index);
@ -3679,7 +4175,7 @@ fn findDeclsInner(
const body_len = zir.extra[extra_index];
extra_index += 1;
const body = zir.bodySlice(extra_index, body_len);
try zir.findDeclsBody(list, body);
try zir.findDeclsBody(gpa, list, defers, body);
extra_index += body.len;
} else if (extra.data.bits.has_align_ref) {
extra_index += 1;
@ -3689,7 +4185,7 @@ fn findDeclsInner(
const body_len = zir.extra[extra_index];
extra_index += 1;
const body = zir.bodySlice(extra_index, body_len);
try zir.findDeclsBody(list, body);
try zir.findDeclsBody(gpa, list, defers, body);
extra_index += body.len;
} else if (extra.data.bits.has_addrspace_ref) {
extra_index += 1;
@ -3699,7 +4195,7 @@ fn findDeclsInner(
const body_len = zir.extra[extra_index];
extra_index += 1;
const body = zir.bodySlice(extra_index, body_len);
try zir.findDeclsBody(list, body);
try zir.findDeclsBody(gpa, list, defers, body);
extra_index += body.len;
} else if (extra.data.bits.has_section_ref) {
extra_index += 1;
@ -3709,7 +4205,7 @@ fn findDeclsInner(
const body_len = zir.extra[extra_index];
extra_index += 1;
const body = zir.bodySlice(extra_index, body_len);
try zir.findDeclsBody(list, body);
try zir.findDeclsBody(gpa, list, defers, body);
extra_index += body.len;
} else if (extra.data.bits.has_cc_ref) {
extra_index += 1;
@ -3719,7 +4215,7 @@ fn findDeclsInner(
const body_len = zir.extra[extra_index];
extra_index += 1;
const body = zir.bodySlice(extra_index, body_len);
try zir.findDeclsBody(list, body);
try zir.findDeclsBody(gpa, list, defers, body);
extra_index += body.len;
} else if (extra.data.bits.has_ret_ty_ref) {
extra_index += 1;
@ -3728,62 +4224,99 @@ fn findDeclsInner(
extra_index += @intFromBool(extra.data.bits.has_any_noalias);
const body = zir.bodySlice(extra_index, extra.data.body_len);
return zir.findDeclsBody(list, body);
},
.extended => {
const extended = datas[@intFromEnum(inst)].extended;
switch (extended.opcode) {
// Decl instructions are interesting but have no body.
// TODO yes they do have a body actually. recurse over them just like block instructions.
.struct_decl,
.union_decl,
.enum_decl,
.opaque_decl,
.reify,
=> return list.append(inst),
else => return,
}
return zir.findDeclsBody(gpa, list, defers, body);
},
// Block instructions, recurse over the bodies.
.block, .block_comptime, .block_inline => {
.block,
.block_comptime,
.block_inline,
.c_import,
.typeof_builtin,
.loop,
=> {
const inst_data = datas[@intFromEnum(inst)].pl_node;
const extra = zir.extraData(Inst.Block, inst_data.payload_index);
const body = zir.bodySlice(extra.end, extra.data.body_len);
return zir.findDeclsBody(list, body);
return zir.findDeclsBody(gpa, list, defers, body);
},
.condbr, .condbr_inline => {
const inst_data = datas[@intFromEnum(inst)].pl_node;
const extra = zir.extraData(Inst.CondBr, inst_data.payload_index);
const then_body = zir.bodySlice(extra.end, extra.data.then_body_len);
const else_body = zir.bodySlice(extra.end + then_body.len, extra.data.else_body_len);
try zir.findDeclsBody(list, then_body);
try zir.findDeclsBody(list, else_body);
try zir.findDeclsBody(gpa, list, defers, then_body);
try zir.findDeclsBody(gpa, list, defers, else_body);
},
.@"try", .try_ptr => {
const inst_data = datas[@intFromEnum(inst)].pl_node;
const extra = zir.extraData(Inst.Try, inst_data.payload_index);
const body = zir.bodySlice(extra.end, extra.data.body_len);
try zir.findDeclsBody(list, body);
try zir.findDeclsBody(gpa, list, defers, body);
},
.switch_block => return findDeclsSwitch(zir, list, inst),
.switch_block, .switch_block_ref => return zir.findDeclsSwitch(gpa, list, defers, inst, .normal),
.switch_block_err_union => return zir.findDeclsSwitch(gpa, list, defers, inst, .err_union),
.suspend_block => @panic("TODO iterate suspend block"),
else => return, // Regular instruction, not interesting.
.param, .param_comptime => {
const inst_data = datas[@intFromEnum(inst)].pl_tok;
const extra = zir.extraData(Inst.Param, inst_data.payload_index);
const body = zir.bodySlice(extra.end, extra.data.body_len);
try zir.findDeclsBody(gpa, list, defers, body);
},
inline .call, .field_call => |tag| {
const inst_data = datas[@intFromEnum(inst)].pl_node;
const extra = zir.extraData(switch (tag) {
.call => Inst.Call,
.field_call => Inst.FieldCall,
else => unreachable,
}, inst_data.payload_index);
// It's easiest to just combine all the arg bodies into one body, like we do above for `struct_decl`.
const args_len = extra.data.flags.args_len;
if (args_len > 0) {
const first_arg_start_off = args_len;
const final_arg_end_off = zir.extra[extra.end + args_len - 1];
const args_body = zir.bodySlice(extra.end + first_arg_start_off, final_arg_end_off - first_arg_start_off);
try zir.findDeclsBody(gpa, list, defers, args_body);
}
},
.@"defer" => {
const inst_data = datas[@intFromEnum(inst)].@"defer";
const gop = try defers.getOrPut(gpa, inst_data.index);
if (!gop.found_existing) {
const body = zir.bodySlice(inst_data.index, inst_data.len);
try zir.findDeclsBody(gpa, list, defers, body);
}
},
.defer_err_code => {
const inst_data = datas[@intFromEnum(inst)].defer_err_code;
const extra = zir.extraData(Inst.DeferErrCode, inst_data.payload_index).data;
const gop = try defers.getOrPut(gpa, extra.index);
if (!gop.found_existing) {
const body = zir.bodySlice(extra.index, extra.len);
try zir.findDeclsBody(gpa, list, defers, body);
}
},
}
}
fn findDeclsSwitch(
zir: Zir,
list: *std.ArrayList(Inst.Index),
gpa: Allocator,
list: *std.ArrayListUnmanaged(Inst.Index),
defers: *std.AutoHashMapUnmanaged(u32, void),
inst: Inst.Index,
/// Distinguishes between `switch_block[_ref]` and `switch_block_err_union`.
comptime kind: enum { normal, err_union },
) Allocator.Error!void {
const inst_data = zir.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = zir.extraData(Inst.SwitchBlock, inst_data.payload_index);
const extra = zir.extraData(switch (kind) {
.normal => Inst.SwitchBlock,
.err_union => Inst.SwitchBlockErrUnion,
}, inst_data.payload_index);
var extra_index: usize = extra.end;
@ -3793,18 +4326,35 @@ fn findDeclsSwitch(
break :blk multi_cases_len;
} else 0;
if (extra.data.bits.any_has_tag_capture) {
if (switch (kind) {
.normal => extra.data.bits.any_has_tag_capture,
.err_union => extra.data.bits.any_uses_err_capture,
}) {
extra_index += 1;
}
const special_prong = extra.data.bits.specialProng();
if (special_prong != .none) {
const has_special = switch (kind) {
.normal => extra.data.bits.specialProng() != .none,
.err_union => has_special: {
// Handle `non_err_body` first.
const prong_info: Inst.SwitchBlock.ProngInfo = @bitCast(zir.extra[extra_index]);
extra_index += 1;
const body = zir.bodySlice(extra_index, prong_info.body_len);
extra_index += body.len;
try zir.findDeclsBody(gpa, list, defers, body);
break :has_special extra.data.bits.has_else;
},
};
if (has_special) {
const prong_info: Inst.SwitchBlock.ProngInfo = @bitCast(zir.extra[extra_index]);
extra_index += 1;
const body = zir.bodySlice(extra_index, prong_info.body_len);
extra_index += body.len;
try zir.findDeclsBody(list, body);
try zir.findDeclsBody(gpa, list, defers, body);
}
{
@ -3816,7 +4366,7 @@ fn findDeclsSwitch(
const body = zir.bodySlice(extra_index, prong_info.body_len);
extra_index += body.len;
try zir.findDeclsBody(list, body);
try zir.findDeclsBody(gpa, list, defers, body);
}
}
{
@ -3833,18 +4383,20 @@ fn findDeclsSwitch(
const body = zir.bodySlice(extra_index, prong_info.body_len);
extra_index += body.len;
try zir.findDeclsBody(list, body);
try zir.findDeclsBody(gpa, list, defers, body);
}
}
}
fn findDeclsBody(
zir: Zir,
list: *std.ArrayList(Inst.Index),
gpa: Allocator,
list: *std.ArrayListUnmanaged(Inst.Index),
defers: *std.AutoHashMapUnmanaged(u32, void),
body: []const Inst.Index,
) Allocator.Error!void {
for (body) |member| {
try zir.findDeclsInner(list, member);
try zir.findDeclsInner(gpa, list, defers, member);
}
}
@ -4042,7 +4594,7 @@ pub fn getAssociatedSrcHash(zir: Zir, inst: Zir.Inst.Index) ?std.zig.SrcHash {
return null;
}
const extra_index = extra.end +
1 +
extra.data.ret_body_len +
extra.data.body_len +
@typeInfo(Inst.Func.SrcLocs).Struct.fields.len;
return @bitCast([4]u32{

View File

@ -2557,10 +2557,10 @@ pub fn mapOldZirToNew(
});
// Used as temporary buffers for namespace declaration instructions
var old_decls = std.ArrayList(Zir.Inst.Index).init(gpa);
defer old_decls.deinit();
var new_decls = std.ArrayList(Zir.Inst.Index).init(gpa);
defer new_decls.deinit();
var old_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
defer old_decls.deinit(gpa);
var new_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
defer new_decls.deinit(gpa);
while (match_stack.popOrNull()) |match_item| {
// Match the namespace declaration itself
@ -2647,11 +2647,11 @@ pub fn mapOldZirToNew(
// Match the `declaration` instruction
try inst_map.put(gpa, old_decl_inst, new_decl_inst);
// Find namespace declarations within this declaration
try old_zir.findDecls(&old_decls, old_decl_inst);
try new_zir.findDecls(&new_decls, new_decl_inst);
// Find container type declarations within this declaration
try old_zir.findDecls(gpa, &old_decls, old_decl_inst);
try new_zir.findDecls(gpa, &new_decls, new_decl_inst);
// We don't have any smart way of matching up these namespace declarations, so we always
// We don't have any smart way of matching up these type declarations, so we always
// correlate them based on source order.
const n = @min(old_decls.items.len, new_decls.items.len);
try match_stack.ensureUnusedCapacity(gpa, n);