std.zig.Zir: improve instruction tracking

The main change here is to partition tracked instructions found within a
declaration. It's very unlikely that, for instance, a `struct { ... }`
type declaration was intentionally turned into a reification or an
anonymous initialization, so it makes sense to track things in a few
different arrays.

In particular, this fixes an issue where a `func` instruction could
wrongly be mapped to something else if the types of function parameters
changed. This would cause huge problems further down the pipeline; we
expect that if a `declaration` is tracked, and it previously contained a
`func`/`func_inferred`/`func_fancy`, then this instruction is either
tracked to another `func`/`func_inferred`/`func_fancy` instruction, or
is lost.

Also, this commit takes the opportunity to rename the functions actually
doing this logic. `Zir.findDecls` was a name that might have made sense
at some point, but nowadays, it's definitely not finding declarations,
and it's not *exclusively* finding type declarations. Instead, the point
is to find instructions which we want to track; hence the new name,
`Zir.findTrackable`.

Lastly, a nice side effect of partitioning the output of `findTrackable`
is that `Zir.declIterator` no longer needs to accept input instructions
which aren't type declarations (e.g. `reify`, `func`).
This commit is contained in:
mlugg 2024-12-05 18:03:09 +00:00
parent 7f3211a101
commit 8f849684f4
No known key found for this signature in database
GPG Key ID: 3F5B7DCCBF4AF02E
2 changed files with 253 additions and 201 deletions

View File

@ -3615,145 +3615,155 @@ pub const DeclIterator = struct {
};
pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
const tags = zir.instructions.items(.tag);
const datas = zir.instructions.items(.data);
switch (tags[@intFromEnum(decl_inst)]) {
// Functions are allowed and yield no iterations.
// This is because they are returned by `findDecls`.
.func, .func_inferred, .func_fancy => return .{
.extra_index = undefined,
.decls_remaining = 0,
.zir = zir,
},
const inst = zir.instructions.get(@intFromEnum(decl_inst));
assert(inst.tag == .extended);
const extended = inst.data.extended;
switch (extended.opcode) {
.struct_decl => {
const small: Inst.StructDecl.Small = @bitCast(extended.small);
var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.StructDecl).@"struct".fields.len);
const captures_len = if (small.has_captures_len) captures_len: {
const captures_len = zir.extra[extra_index];
extra_index += 1;
break :captures_len captures_len;
} else 0;
extra_index += @intFromBool(small.has_fields_len);
const decls_len = if (small.has_decls_len) decls_len: {
const decls_len = zir.extra[extra_index];
extra_index += 1;
break :decls_len decls_len;
} else 0;
.extended => {
const extended = datas[@intFromEnum(decl_inst)].extended;
switch (extended.opcode) {
// Reifications are allowed and yield no iterations.
// This is because they are returned by `findDecls`.
.reify => return .{
.extra_index = undefined,
.decls_remaining = 0,
.zir = zir,
},
.struct_decl => {
const small: Inst.StructDecl.Small = @bitCast(extended.small);
var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.StructDecl).@"struct".fields.len);
const captures_len = if (small.has_captures_len) captures_len: {
const captures_len = zir.extra[extra_index];
extra_index += 1;
break :captures_len captures_len;
} else 0;
extra_index += @intFromBool(small.has_fields_len);
const decls_len = if (small.has_decls_len) decls_len: {
const decls_len = zir.extra[extra_index];
extra_index += 1;
break :decls_len decls_len;
} else 0;
extra_index += captures_len;
extra_index += captures_len;
if (small.has_backing_int) {
const backing_int_body_len = zir.extra[extra_index];
extra_index += 1; // backing_int_body_len
if (backing_int_body_len == 0) {
extra_index += 1; // backing_int_ref
} else {
extra_index += backing_int_body_len; // backing_int_body_inst
}
}
return .{
.extra_index = extra_index,
.decls_remaining = decls_len,
.zir = zir,
};
},
.enum_decl => {
const small: Inst.EnumDecl.Small = @bitCast(extended.small);
var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.EnumDecl).@"struct".fields.len);
extra_index += @intFromBool(small.has_tag_type);
const captures_len = if (small.has_captures_len) captures_len: {
const captures_len = zir.extra[extra_index];
extra_index += 1;
break :captures_len captures_len;
} else 0;
extra_index += @intFromBool(small.has_body_len);
extra_index += @intFromBool(small.has_fields_len);
const decls_len = if (small.has_decls_len) decls_len: {
const decls_len = zir.extra[extra_index];
extra_index += 1;
break :decls_len decls_len;
} else 0;
extra_index += captures_len;
return .{
.extra_index = extra_index,
.decls_remaining = decls_len,
.zir = zir,
};
},
.union_decl => {
const small: Inst.UnionDecl.Small = @bitCast(extended.small);
var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.UnionDecl).@"struct".fields.len);
extra_index += @intFromBool(small.has_tag_type);
const captures_len = if (small.has_captures_len) captures_len: {
const captures_len = zir.extra[extra_index];
extra_index += 1;
break :captures_len captures_len;
} else 0;
extra_index += @intFromBool(small.has_body_len);
extra_index += @intFromBool(small.has_fields_len);
const decls_len = if (small.has_decls_len) decls_len: {
const decls_len = zir.extra[extra_index];
extra_index += 1;
break :decls_len decls_len;
} else 0;
extra_index += captures_len;
return .{
.extra_index = extra_index,
.decls_remaining = decls_len,
.zir = zir,
};
},
.opaque_decl => {
const small: Inst.OpaqueDecl.Small = @bitCast(extended.small);
var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.OpaqueDecl).@"struct".fields.len);
const decls_len = if (small.has_decls_len) decls_len: {
const decls_len = zir.extra[extra_index];
extra_index += 1;
break :decls_len decls_len;
} else 0;
const captures_len = if (small.has_captures_len) captures_len: {
const captures_len = zir.extra[extra_index];
extra_index += 1;
break :captures_len captures_len;
} else 0;
extra_index += captures_len;
return .{
.extra_index = extra_index,
.decls_remaining = decls_len,
.zir = zir,
};
},
else => unreachable,
if (small.has_backing_int) {
const backing_int_body_len = zir.extra[extra_index];
extra_index += 1; // backing_int_body_len
if (backing_int_body_len == 0) {
extra_index += 1; // backing_int_ref
} else {
extra_index += backing_int_body_len; // backing_int_body_inst
}
}
return .{
.extra_index = extra_index,
.decls_remaining = decls_len,
.zir = zir,
};
},
.enum_decl => {
const small: Inst.EnumDecl.Small = @bitCast(extended.small);
var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.EnumDecl).@"struct".fields.len);
extra_index += @intFromBool(small.has_tag_type);
const captures_len = if (small.has_captures_len) captures_len: {
const captures_len = zir.extra[extra_index];
extra_index += 1;
break :captures_len captures_len;
} else 0;
extra_index += @intFromBool(small.has_body_len);
extra_index += @intFromBool(small.has_fields_len);
const decls_len = if (small.has_decls_len) decls_len: {
const decls_len = zir.extra[extra_index];
extra_index += 1;
break :decls_len decls_len;
} else 0;
extra_index += captures_len;
return .{
.extra_index = extra_index,
.decls_remaining = decls_len,
.zir = zir,
};
},
.union_decl => {
const small: Inst.UnionDecl.Small = @bitCast(extended.small);
var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.UnionDecl).@"struct".fields.len);
extra_index += @intFromBool(small.has_tag_type);
const captures_len = if (small.has_captures_len) captures_len: {
const captures_len = zir.extra[extra_index];
extra_index += 1;
break :captures_len captures_len;
} else 0;
extra_index += @intFromBool(small.has_body_len);
extra_index += @intFromBool(small.has_fields_len);
const decls_len = if (small.has_decls_len) decls_len: {
const decls_len = zir.extra[extra_index];
extra_index += 1;
break :decls_len decls_len;
} else 0;
extra_index += captures_len;
return .{
.extra_index = extra_index,
.decls_remaining = decls_len,
.zir = zir,
};
},
.opaque_decl => {
const small: Inst.OpaqueDecl.Small = @bitCast(extended.small);
var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.OpaqueDecl).@"struct".fields.len);
const decls_len = if (small.has_decls_len) decls_len: {
const decls_len = zir.extra[extra_index];
extra_index += 1;
break :decls_len decls_len;
} else 0;
const captures_len = if (small.has_captures_len) captures_len: {
const captures_len = zir.extra[extra_index];
extra_index += 1;
break :captures_len captures_len;
} else 0;
extra_index += captures_len;
return .{
.extra_index = extra_index,
.decls_remaining = decls_len,
.zir = zir,
};
},
else => unreachable,
}
}
/// 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();
/// `DeclContents` contains all "interesting" instructions found within a declaration by `findTrackable`.
/// These instructions are partitioned into a few different sets, since this makes ZIR instruction mapping
/// more effective.
pub const DeclContents = struct {
/// This is a simple optional because ZIR guarantees that a `func`/`func_inferred`/`func_fancy` instruction
/// can only occur once per `declaration`.
func_decl: ?Inst.Index,
explicit_types: std.ArrayListUnmanaged(Inst.Index),
other: std.ArrayListUnmanaged(Inst.Index),
pub const init: DeclContents = .{
.func_decl = null,
.explicit_types = .empty,
.other = .empty,
};
pub fn clear(contents: *DeclContents) void {
contents.func_decl = null;
contents.explicit_types.clearRetainingCapacity();
contents.other.clearRetainingCapacity();
}
pub fn deinit(contents: *DeclContents, gpa: Allocator) void {
contents.explicit_types.deinit(gpa);
contents.other.deinit(gpa);
}
};
/// Find all tracked ZIR instructions, recursively, within a `declaration` instruction. Does not recurse through
/// nested declarations; to find all declarations, call this function recursively on the type declarations discovered
/// in `contents.explicit_types`.
///
/// This populates an `ArrayListUnmanaged` because an iterator would need to allocate memory anyway.
pub fn findTrackable(zir: Zir, gpa: Allocator, contents: *DeclContents, decl_inst: Zir.Inst.Index) !void {
contents.clear();
const declaration, const extra_end = zir.getDeclaration(decl_inst);
const bodies = declaration.getBodies(extra_end, zir);
@ -3762,27 +3772,27 @@ pub fn findDecls(zir: Zir, gpa: Allocator, list: *std.ArrayListUnmanaged(Inst.In
var found_defers: std.AutoHashMapUnmanaged(u32, void) = .empty;
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);
try zir.findTrackableBody(gpa, contents, &found_defers, bodies.value_body);
if (bodies.align_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
if (bodies.linksection_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
if (bodies.addrspace_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
}
/// Like `findDecls`, but only considers the `main_struct_inst` instruction. This may return more than
/// Like `findTrackable`, but only considers the `main_struct_inst` instruction. This may return more than
/// just that instruction because it will also traverse fields.
pub fn findDeclsRoot(zir: Zir, gpa: Allocator, list: *std.ArrayListUnmanaged(Inst.Index)) !void {
list.clearRetainingCapacity();
pub fn findTrackableRoot(zir: Zir, gpa: Allocator, contents: *DeclContents) !void {
contents.clear();
var found_defers: std.AutoHashMapUnmanaged(u32, void) = .empty;
defer found_defers.deinit(gpa);
try zir.findDeclsInner(gpa, list, &found_defers, .main_struct_inst);
try zir.findTrackableInner(gpa, contents, &found_defers, .main_struct_inst);
}
fn findDeclsInner(
fn findTrackableInner(
zir: Zir,
gpa: Allocator,
list: *std.ArrayListUnmanaged(Inst.Index),
contents: *DeclContents,
defers: *std.AutoHashMapUnmanaged(u32, void),
inst: Inst.Index,
) Allocator.Error!void {
@ -4026,7 +4036,7 @@ fn findDeclsInner(
.struct_init,
.struct_init_ref,
.struct_init_anon,
=> return list.append(gpa, inst),
=> return contents.other.append(gpa, inst),
.extended => {
const extended = datas[@intFromEnum(inst)].extended;
@ -4093,15 +4103,15 @@ fn findDeclsInner(
.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);
try zir.findTrackableBody(gpa, contents, defers, body);
},
// Reifications and opaque declarations need tracking, but have no body.
.reify, .opaque_decl => return list.append(gpa, inst),
.reify, .opaque_decl => return contents.other.append(gpa, inst),
// Struct declarations need tracking and have bodies.
.struct_decl => {
try list.append(gpa, inst);
try contents.explicit_types.append(gpa, inst);
const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
const extra = zir.extraData(Zir.Inst.StructDecl, extended.operand);
@ -4130,7 +4140,7 @@ fn findDeclsInner(
} else {
const body = zir.bodySlice(extra_index, backing_int_body_len);
extra_index += backing_int_body_len;
try zir.findDeclsBody(gpa, list, defers, body);
try zir.findTrackableBody(gpa, contents, defers, body);
}
}
extra_index += decls_len;
@ -4186,12 +4196,12 @@ fn findDeclsInner(
// 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);
try zir.findTrackableBody(gpa, contents, defers, merged_bodies);
},
// Union declarations need tracking and have a body.
.union_decl => {
try list.append(gpa, inst);
try contents.explicit_types.append(gpa, inst);
const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand);
@ -4216,12 +4226,12 @@ fn findDeclsInner(
extra_index += captures_len;
extra_index += decls_len;
const body = zir.bodySlice(extra_index, body_len);
try zir.findDeclsBody(gpa, list, defers, body);
try zir.findTrackableBody(gpa, contents, defers, body);
},
// Enum declarations need tracking and have a body.
.enum_decl => {
try list.append(gpa, inst);
try contents.explicit_types.append(gpa, inst);
const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);
const extra = zir.extraData(Zir.Inst.EnumDecl, extended.operand);
@ -4246,7 +4256,7 @@ fn findDeclsInner(
extra_index += captures_len;
extra_index += decls_len;
const body = zir.bodySlice(extra_index, body_len);
try zir.findDeclsBody(gpa, list, defers, body);
try zir.findTrackableBody(gpa, contents, defers, body);
},
}
},
@ -4255,7 +4265,8 @@ fn findDeclsInner(
.func,
.func_inferred,
=> {
try list.append(gpa, inst);
assert(contents.func_decl == null);
contents.func_decl = inst;
const inst_data = datas[@intFromEnum(inst)].pl_node;
const extra = zir.extraData(Inst.Func, inst_data.payload_index);
@ -4266,14 +4277,15 @@ fn findDeclsInner(
else => {
const body = zir.bodySlice(extra_index, extra.data.ret_body_len);
extra_index += body.len;
try zir.findDeclsBody(gpa, list, defers, body);
try zir.findTrackableBody(gpa, contents, defers, body);
},
}
const body = zir.bodySlice(extra_index, extra.data.body_len);
return zir.findDeclsBody(gpa, list, defers, body);
return zir.findTrackableBody(gpa, contents, defers, body);
},
.func_fancy => {
try list.append(gpa, inst);
assert(contents.func_decl == null);
contents.func_decl = inst;
const inst_data = datas[@intFromEnum(inst)].pl_node;
const extra = zir.extraData(Inst.FuncFancy, inst_data.payload_index);
@ -4284,7 +4296,7 @@ fn findDeclsInner(
const body_len = zir.extra[extra_index];
extra_index += 1;
const body = zir.bodySlice(extra_index, body_len);
try zir.findDeclsBody(gpa, list, defers, body);
try zir.findTrackableBody(gpa, contents, defers, body);
extra_index += body.len;
} else if (extra.data.bits.has_align_ref) {
extra_index += 1;
@ -4294,7 +4306,7 @@ fn findDeclsInner(
const body_len = zir.extra[extra_index];
extra_index += 1;
const body = zir.bodySlice(extra_index, body_len);
try zir.findDeclsBody(gpa, list, defers, body);
try zir.findTrackableBody(gpa, contents, defers, body);
extra_index += body.len;
} else if (extra.data.bits.has_addrspace_ref) {
extra_index += 1;
@ -4304,7 +4316,7 @@ fn findDeclsInner(
const body_len = zir.extra[extra_index];
extra_index += 1;
const body = zir.bodySlice(extra_index, body_len);
try zir.findDeclsBody(gpa, list, defers, body);
try zir.findTrackableBody(gpa, contents, defers, body);
extra_index += body.len;
} else if (extra.data.bits.has_section_ref) {
extra_index += 1;
@ -4314,7 +4326,7 @@ fn findDeclsInner(
const body_len = zir.extra[extra_index];
extra_index += 1;
const body = zir.bodySlice(extra_index, body_len);
try zir.findDeclsBody(gpa, list, defers, body);
try zir.findTrackableBody(gpa, contents, defers, body);
extra_index += body.len;
} else if (extra.data.bits.has_cc_ref) {
extra_index += 1;
@ -4324,7 +4336,7 @@ fn findDeclsInner(
const body_len = zir.extra[extra_index];
extra_index += 1;
const body = zir.bodySlice(extra_index, body_len);
try zir.findDeclsBody(gpa, list, defers, body);
try zir.findTrackableBody(gpa, contents, defers, body);
extra_index += body.len;
} else if (extra.data.bits.has_ret_ty_ref) {
extra_index += 1;
@ -4333,7 +4345,7 @@ fn findDeclsInner(
extra_index += @intFromBool(extra.data.bits.has_any_noalias);
const body = zir.bodySlice(extra_index, extra.data.body_len);
return zir.findDeclsBody(gpa, list, defers, body);
return zir.findTrackableBody(gpa, contents, defers, body);
},
// Block instructions, recurse over the bodies.
@ -4348,24 +4360,24 @@ fn findDeclsInner(
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(gpa, list, defers, body);
return zir.findTrackableBody(gpa, contents, 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(gpa, list, defers, then_body);
try zir.findDeclsBody(gpa, list, defers, else_body);
try zir.findTrackableBody(gpa, contents, defers, then_body);
try zir.findTrackableBody(gpa, contents, 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(gpa, list, defers, body);
try zir.findTrackableBody(gpa, contents, defers, body);
},
.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),
.switch_block, .switch_block_ref => return zir.findTrackableSwitch(gpa, contents, defers, inst, .normal),
.switch_block_err_union => return zir.findTrackableSwitch(gpa, contents, defers, inst, .err_union),
.suspend_block => @panic("TODO iterate suspend block"),
@ -4373,7 +4385,7 @@ fn findDeclsInner(
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);
try zir.findTrackableBody(gpa, contents, defers, body);
},
inline .call, .field_call => |tag| {
@ -4389,7 +4401,7 @@ fn findDeclsInner(
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);
try zir.findTrackableBody(gpa, contents, defers, args_body);
}
},
.@"defer" => {
@ -4397,7 +4409,7 @@ fn findDeclsInner(
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);
try zir.findTrackableBody(gpa, contents, defers, body);
}
},
.defer_err_code => {
@ -4406,16 +4418,16 @@ fn findDeclsInner(
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);
try zir.findTrackableBody(gpa, contents, defers, body);
}
},
}
}
fn findDeclsSwitch(
fn findTrackableSwitch(
zir: Zir,
gpa: Allocator,
list: *std.ArrayListUnmanaged(Inst.Index),
contents: *DeclContents,
defers: *std.AutoHashMapUnmanaged(u32, void),
inst: Inst.Index,
/// Distinguishes between `switch_block[_ref]` and `switch_block_err_union`.
@ -4451,7 +4463,7 @@ fn findDeclsSwitch(
const body = zir.bodySlice(extra_index, prong_info.body_len);
extra_index += body.len;
try zir.findDeclsBody(gpa, list, defers, body);
try zir.findTrackableBody(gpa, contents, defers, body);
break :has_special extra.data.bits.has_else;
},
@ -4463,7 +4475,7 @@ fn findDeclsSwitch(
const body = zir.bodySlice(extra_index, prong_info.body_len);
extra_index += body.len;
try zir.findDeclsBody(gpa, list, defers, body);
try zir.findTrackableBody(gpa, contents, defers, body);
}
{
@ -4475,7 +4487,7 @@ fn findDeclsSwitch(
const body = zir.bodySlice(extra_index, prong_info.body_len);
extra_index += body.len;
try zir.findDeclsBody(gpa, list, defers, body);
try zir.findTrackableBody(gpa, contents, defers, body);
}
}
{
@ -4492,20 +4504,20 @@ fn findDeclsSwitch(
const body = zir.bodySlice(extra_index, prong_info.body_len);
extra_index += body.len;
try zir.findDeclsBody(gpa, list, defers, body);
try zir.findTrackableBody(gpa, contents, defers, body);
}
}
}
fn findDeclsBody(
fn findTrackableBody(
zir: Zir,
gpa: Allocator,
list: *std.ArrayListUnmanaged(Inst.Index),
contents: *DeclContents,
defers: *std.AutoHashMapUnmanaged(u32, void),
body: []const Inst.Index,
) Allocator.Error!void {
for (body) |member| {
try zir.findDeclsInner(gpa, list, defers, member);
try zir.findTrackableInner(gpa, contents, defers, member);
}
}

View File

@ -2593,26 +2593,44 @@ pub fn mapOldZirToNew(
defer match_stack.deinit(gpa);
// Used as temporary buffers for namespace declaration instructions
var old_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .empty;
defer old_decls.deinit(gpa);
var new_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .empty;
defer new_decls.deinit(gpa);
var old_contents: Zir.DeclContents = .init;
defer old_contents.deinit(gpa);
var new_contents: Zir.DeclContents = .init;
defer new_contents.deinit(gpa);
// Map the main struct inst (and anything in its fields)
{
try old_zir.findDeclsRoot(gpa, &old_decls);
try new_zir.findDeclsRoot(gpa, &new_decls);
try old_zir.findTrackableRoot(gpa, &old_contents);
try new_zir.findTrackableRoot(gpa, &new_contents);
assert(old_decls.items[0] == .main_struct_inst);
assert(new_decls.items[0] == .main_struct_inst);
assert(old_contents.explicit_types.items[0] == .main_struct_inst);
assert(new_contents.explicit_types.items[0] == .main_struct_inst);
// 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);
for (old_decls.items[0..n], new_decls.items[0..n]) |old_inst, new_inst| {
assert(old_contents.func_decl == null);
assert(new_contents.func_decl == null);
// We don't have any smart way of matching up these instructions, so we correlate them based on source order
// in their respective arrays.
const num_explicit_types = @min(old_contents.explicit_types.items.len, new_contents.explicit_types.items.len);
try match_stack.ensureUnusedCapacity(gpa, @intCast(num_explicit_types));
for (
old_contents.explicit_types.items[0..num_explicit_types],
new_contents.explicit_types.items[0..num_explicit_types],
) |old_inst, new_inst| {
// Here we use `match_stack`, so that we will recursively consider declarations on these types.
match_stack.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst });
}
const num_other = @min(old_contents.other.items.len, new_contents.other.items.len);
try inst_map.ensureUnusedCapacity(gpa, @intCast(num_other));
for (
old_contents.other.items[0..num_other],
new_contents.other.items[0..num_other],
) |old_inst, new_inst| {
// These instructions don't have declarations, so we just modify `inst_map` directly.
inst_map.putAssumeCapacity(old_inst, new_inst);
}
}
while (match_stack.popOrNull()) |match_item| {
@ -2700,17 +2718,39 @@ pub fn mapOldZirToNew(
// Match the `declaration` instruction
try inst_map.put(gpa, old_decl_inst, 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);
// Find trackable instructions within this declaration
try old_zir.findTrackable(gpa, &old_contents, old_decl_inst);
try new_zir.findTrackable(gpa, &new_contents, new_decl_inst);
// 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);
for (old_decls.items[0..n], new_decls.items[0..n]) |old_inst, new_inst| {
// We don't have any smart way of matching up these instructions, so we correlate them based on source order
// in their respective arrays.
const num_explicit_types = @min(old_contents.explicit_types.items.len, new_contents.explicit_types.items.len);
try match_stack.ensureUnusedCapacity(gpa, @intCast(num_explicit_types));
for (
old_contents.explicit_types.items[0..num_explicit_types],
new_contents.explicit_types.items[0..num_explicit_types],
) |old_inst, new_inst| {
// Here we use `match_stack`, so that we will recursively consider declarations on these types.
match_stack.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst });
}
const num_other = @min(old_contents.other.items.len, new_contents.other.items.len);
try inst_map.ensureUnusedCapacity(gpa, @intCast(num_other));
for (
old_contents.other.items[0..num_other],
new_contents.other.items[0..num_other],
) |old_inst, new_inst| {
// These instructions don't have declarations, so we just modify `inst_map` directly.
inst_map.putAssumeCapacity(old_inst, new_inst);
}
if (old_contents.func_decl) |old_func_inst| {
if (new_contents.func_decl) |new_func_inst| {
// There are no declarations on a function either, so again, we just directly add it to `inst_map`.
try inst_map.put(gpa, old_func_inst, new_func_inst);
}
}
}
}
}