mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
Merge pull request #18654 from mlugg/incremental-the-second
InternPool: introduce TrackedInst to prepare for incremental compilation
This commit is contained in:
commit
b96fb858c8
376
src/AstGen.zig
376
src/AstGen.zig
@ -86,6 +86,7 @@ fn setExtra(astgen: *AstGen, index: usize, extra: anytype) void {
|
||||
|
||||
Zir.Inst.Ref,
|
||||
Zir.Inst.Index,
|
||||
Zir.Inst.Declaration.Name,
|
||||
Zir.NullTerminatedString,
|
||||
=> @intFromEnum(@field(extra, field.name)),
|
||||
|
||||
@ -95,6 +96,7 @@ fn setExtra(astgen: *AstGen, index: usize, extra: anytype) void {
|
||||
Zir.Inst.SwitchBlock.Bits,
|
||||
Zir.Inst.SwitchBlockErrUnion.Bits,
|
||||
Zir.Inst.FuncFancy.Bits,
|
||||
Zir.Inst.Declaration.Flags,
|
||||
=> @bitCast(@field(extra, field.name)),
|
||||
|
||||
else => @compileError("bad field type"),
|
||||
@ -132,8 +134,8 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {
|
||||
};
|
||||
defer astgen.deinit(gpa);
|
||||
|
||||
// String table indexes 0, 1, 2 are reserved for special meaning.
|
||||
try astgen.string_bytes.appendSlice(gpa, &[_]u8{ 0, 0, 0 });
|
||||
// String table index 0 is reserved for `NullTerminatedString.empty`.
|
||||
try astgen.string_bytes.append(gpa, 0);
|
||||
|
||||
// We expect at least as many ZIR instructions and extra data items
|
||||
// as AST nodes.
|
||||
@ -355,8 +357,13 @@ const ResultInfo = struct {
|
||||
};
|
||||
};
|
||||
|
||||
/// TODO: modify Sema to remove in favour of `coerced_align_ri`
|
||||
const align_ri: ResultInfo = .{ .rl = .{ .ty = .u29_type } };
|
||||
const coerced_align_ri: ResultInfo = .{ .rl = .{ .coerced_ty = .u29_type } };
|
||||
/// TODO: modify Sema to remove in favour of `coerced_addrspace_ri`
|
||||
const addrspace_ri: ResultInfo = .{ .rl = .{ .ty = .address_space_type } };
|
||||
const coerced_addrspace_ri: ResultInfo = .{ .rl = .{ .coerced_ty = .address_space_type } };
|
||||
const coerced_linksection_ri: ResultInfo = .{ .rl = .{ .coerced_ty = .slice_const_u8_type } };
|
||||
const bool_ri: ResultInfo = .{ .rl = .{ .ty = .bool_type } };
|
||||
const type_ri: ResultInfo = .{ .rl = .{ .ty = .type_type } };
|
||||
const coerced_type_ri: ResultInfo = .{ .rl = .{ .coerced_ty = .type_type } };
|
||||
@ -2592,6 +2599,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
|
||||
.block,
|
||||
.block_comptime,
|
||||
.block_inline,
|
||||
.declaration,
|
||||
.suspend_block,
|
||||
.loop,
|
||||
.bool_br_and,
|
||||
@ -3783,7 +3791,7 @@ fn ptrType(
|
||||
gz.astgen.source_line = source_line;
|
||||
gz.astgen.source_column = source_column;
|
||||
|
||||
addrspace_ref = try expr(gz, scope, .{ .rl = .{ .ty = .address_space_type } }, ptr_info.ast.addrspace_node);
|
||||
addrspace_ref = try expr(gz, scope, addrspace_ri, ptr_info.ast.addrspace_node);
|
||||
trailing_count += 1;
|
||||
}
|
||||
if (ptr_info.ast.align_node != 0) {
|
||||
@ -3899,8 +3907,6 @@ fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.
|
||||
const WipMembers = struct {
|
||||
payload: *ArrayListUnmanaged(u32),
|
||||
payload_top: usize,
|
||||
decls_start: u32,
|
||||
decls_end: u32,
|
||||
field_bits_start: u32,
|
||||
fields_start: u32,
|
||||
fields_end: u32,
|
||||
@ -3908,43 +3914,27 @@ const WipMembers = struct {
|
||||
field_index: u32 = 0,
|
||||
|
||||
const Self = @This();
|
||||
/// struct, union, enum, and opaque decls all use same 4 bits per decl
|
||||
const bits_per_decl = 4;
|
||||
const decls_per_u32 = 32 / bits_per_decl;
|
||||
/// struct, union, enum, and opaque decls all have maximum size of 11 u32 slots
|
||||
/// (4 for src_hash + line + name + value + doc_comment + align + link_section + address_space )
|
||||
const max_decl_size = 11;
|
||||
|
||||
fn init(gpa: Allocator, payload: *ArrayListUnmanaged(u32), decl_count: u32, field_count: u32, comptime bits_per_field: u32, comptime max_field_size: u32) Allocator.Error!Self {
|
||||
const payload_top: u32 = @intCast(payload.items.len);
|
||||
const decls_start = payload_top + (decl_count + decls_per_u32 - 1) / decls_per_u32;
|
||||
const field_bits_start = decls_start + decl_count * max_decl_size;
|
||||
const field_bits_start = payload_top + decl_count;
|
||||
const fields_start = field_bits_start + if (bits_per_field > 0) blk: {
|
||||
const fields_per_u32 = 32 / bits_per_field;
|
||||
break :blk (field_count + fields_per_u32 - 1) / fields_per_u32;
|
||||
} else 0;
|
||||
const payload_end = fields_start + field_count * max_field_size;
|
||||
try payload.resize(gpa, payload_end);
|
||||
return Self{
|
||||
return .{
|
||||
.payload = payload,
|
||||
.payload_top = payload_top,
|
||||
.decls_start = decls_start,
|
||||
.field_bits_start = field_bits_start,
|
||||
.fields_start = fields_start,
|
||||
.decls_end = decls_start,
|
||||
.fields_end = fields_start,
|
||||
};
|
||||
}
|
||||
|
||||
fn nextDecl(self: *Self, is_pub: bool, is_export: bool, has_align: bool, has_section_or_addrspace: bool) void {
|
||||
const index = self.payload_top + self.decl_index / decls_per_u32;
|
||||
assert(index < self.decls_start);
|
||||
const bit_bag: u32 = if (self.decl_index % decls_per_u32 == 0) 0 else self.payload.items[index];
|
||||
self.payload.items[index] = (bit_bag >> bits_per_decl) |
|
||||
(@as(u32, @intFromBool(is_pub)) << 28) |
|
||||
(@as(u32, @intFromBool(is_export)) << 29) |
|
||||
(@as(u32, @intFromBool(has_align)) << 30) |
|
||||
(@as(u32, @intFromBool(has_section_or_addrspace)) << 31);
|
||||
fn nextDecl(self: *Self, decl_inst: Zir.Inst.Index) void {
|
||||
self.payload.items[self.payload_top + self.decl_index] = @intFromEnum(decl_inst);
|
||||
self.decl_index += 1;
|
||||
}
|
||||
|
||||
@ -3962,18 +3952,6 @@ const WipMembers = struct {
|
||||
self.field_index += 1;
|
||||
}
|
||||
|
||||
fn appendToDecl(self: *Self, data: u32) void {
|
||||
assert(self.decls_end < self.field_bits_start);
|
||||
self.payload.items[self.decls_end] = data;
|
||||
self.decls_end += 1;
|
||||
}
|
||||
|
||||
fn appendToDeclSlice(self: *Self, data: []const u32) void {
|
||||
assert(self.decls_end + data.len <= self.field_bits_start);
|
||||
@memcpy(self.payload.items[self.decls_end..][0..data.len], data);
|
||||
self.decls_end += @intCast(data.len);
|
||||
}
|
||||
|
||||
fn appendToField(self: *Self, data: u32) void {
|
||||
assert(self.fields_end < self.payload.items.len);
|
||||
self.payload.items[self.fields_end] = data;
|
||||
@ -3981,11 +3959,6 @@ const WipMembers = struct {
|
||||
}
|
||||
|
||||
fn finishBits(self: *Self, comptime bits_per_field: u32) void {
|
||||
const empty_decl_slots = decls_per_u32 - (self.decl_index % decls_per_u32);
|
||||
if (self.decl_index > 0 and empty_decl_slots < decls_per_u32) {
|
||||
const index = self.payload_top + self.decl_index / decls_per_u32;
|
||||
self.payload.items[index] >>= @intCast(empty_decl_slots * bits_per_decl);
|
||||
}
|
||||
if (bits_per_field > 0) {
|
||||
const fields_per_u32 = 32 / bits_per_field;
|
||||
const empty_field_slots = fields_per_u32 - (self.field_index % fields_per_u32);
|
||||
@ -3997,7 +3970,7 @@ const WipMembers = struct {
|
||||
}
|
||||
|
||||
fn declsSlice(self: *Self) []u32 {
|
||||
return self.payload.items[self.payload_top..self.decls_end];
|
||||
return self.payload.items[self.payload_top..][0..self.decl_index];
|
||||
}
|
||||
|
||||
fn fieldsSlice(self: *Self) []u32 {
|
||||
@ -4023,11 +3996,10 @@ fn fnDecl(
|
||||
|
||||
// missing function name already happened in scanDecls()
|
||||
const fn_name_token = fn_proto.name_token orelse return error.AnalysisFail;
|
||||
const fn_name_str_index = try astgen.identAsString(fn_name_token);
|
||||
|
||||
// We insert this at the beginning so that its instruction index marks the
|
||||
// start of the top level declaration.
|
||||
const block_inst = try gz.makeBlockInst(.block_inline, fn_proto.ast.proto_node);
|
||||
const decl_inst = try gz.makeBlockInst(.declaration, fn_proto.ast.proto_node);
|
||||
astgen.advanceSourceCursorToNode(decl_node);
|
||||
|
||||
var decl_gz: GenZir = .{
|
||||
@ -4072,8 +4044,7 @@ fn fnDecl(
|
||||
|
||||
const doc_comment_index = try astgen.docCommentAsString(fn_proto.firstToken());
|
||||
|
||||
// align, linksection, and addrspace is passed in the func instruction in this case.
|
||||
wip_members.nextDecl(is_pub, is_export, false, false);
|
||||
wip_members.nextDecl(decl_inst);
|
||||
|
||||
var noalias_bits: u32 = 0;
|
||||
var params_scope = &fn_gz.base;
|
||||
@ -4213,7 +4184,7 @@ fn fnDecl(
|
||||
var addrspace_gz = decl_gz.makeSubBlock(params_scope);
|
||||
defer addrspace_gz.unstack();
|
||||
const addrspace_ref: Zir.Inst.Ref = if (fn_proto.ast.addrspace_expr == 0) .none else inst: {
|
||||
const inst = try expr(&decl_gz, params_scope, .{ .rl = .{ .coerced_ty = .address_space_type } }, fn_proto.ast.addrspace_expr);
|
||||
const inst = try expr(&decl_gz, params_scope, addrspace_ri, fn_proto.ast.addrspace_expr);
|
||||
if (addrspace_gz.instructionsSlice().len == 0) {
|
||||
// In this case we will send a len=0 body which can be encoded more efficiently.
|
||||
break :inst inst;
|
||||
@ -4298,7 +4269,7 @@ fn fnDecl(
|
||||
.section_gz = §ion_gz,
|
||||
.addrspace_ref = addrspace_ref,
|
||||
.addrspace_gz = &addrspace_gz,
|
||||
.param_block = block_inst,
|
||||
.param_block = decl_inst,
|
||||
.body_gz = null,
|
||||
.lib_name = lib_name,
|
||||
.is_var_args = is_var_args,
|
||||
@ -4349,7 +4320,7 @@ fn fnDecl(
|
||||
.addrspace_gz = &addrspace_gz,
|
||||
.lbrace_line = lbrace_line,
|
||||
.lbrace_column = lbrace_column,
|
||||
.param_block = block_inst,
|
||||
.param_block = decl_inst,
|
||||
.body_gz = &fn_gz,
|
||||
.lib_name = lib_name,
|
||||
.is_var_args = is_var_args,
|
||||
@ -4363,20 +4334,21 @@ fn fnDecl(
|
||||
|
||||
// We add this at the end so that its instruction index marks the end range
|
||||
// of the top level declaration. addFunc already unstacked fn_gz and ret_gz.
|
||||
_ = try decl_gz.addBreak(.break_inline, block_inst, func_inst);
|
||||
try decl_gz.setBlockBody(block_inst);
|
||||
_ = try decl_gz.addBreak(.break_inline, decl_inst, func_inst);
|
||||
|
||||
{
|
||||
const contents_hash align(@alignOf(u32)) = std.zig.hashSrc(tree.getNodeSource(decl_node));
|
||||
wip_members.appendToDeclSlice(std.mem.bytesAsSlice(u32, &contents_hash));
|
||||
}
|
||||
{
|
||||
const line_delta = decl_gz.decl_line - gz.decl_line;
|
||||
wip_members.appendToDecl(line_delta);
|
||||
}
|
||||
wip_members.appendToDecl(@intFromEnum(fn_name_str_index));
|
||||
wip_members.appendToDecl(@intFromEnum(block_inst));
|
||||
wip_members.appendToDecl(@intFromEnum(doc_comment_index));
|
||||
try setDeclaration(
|
||||
decl_inst,
|
||||
std.zig.hashSrc(tree.getNodeSource(decl_node)),
|
||||
.{ .named = fn_name_token },
|
||||
decl_gz.decl_line - gz.decl_line,
|
||||
is_pub,
|
||||
is_export,
|
||||
doc_comment_index,
|
||||
&decl_gz,
|
||||
// align, linksection, and addrspace are passed in the func instruction in this case.
|
||||
// TODO: move them from the function instruction to the declaration instruction?
|
||||
null,
|
||||
);
|
||||
}
|
||||
|
||||
fn globalVarDecl(
|
||||
@ -4393,10 +4365,9 @@ fn globalVarDecl(
|
||||
const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var;
|
||||
// We do this at the beginning so that the instruction index marks the range start
|
||||
// of the top level declaration.
|
||||
const block_inst = try gz.makeBlockInst(.block_inline, node);
|
||||
const decl_inst = try gz.makeBlockInst(.declaration, node);
|
||||
|
||||
const name_token = var_decl.ast.mut_token + 1;
|
||||
const name_str_index = try astgen.identAsString(name_token);
|
||||
astgen.advanceSourceCursorToNode(node);
|
||||
|
||||
var block_scope: GenZir = .{
|
||||
@ -4420,17 +4391,7 @@ fn globalVarDecl(
|
||||
const maybe_extern_token = var_decl.extern_export_token orelse break :blk false;
|
||||
break :blk token_tags[maybe_extern_token] == .keyword_extern;
|
||||
};
|
||||
const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node == 0) .none else inst: {
|
||||
break :inst try expr(&block_scope, &block_scope.base, align_ri, var_decl.ast.align_node);
|
||||
};
|
||||
const addrspace_inst: Zir.Inst.Ref = if (var_decl.ast.addrspace_node == 0) .none else inst: {
|
||||
break :inst try expr(&block_scope, &block_scope.base, .{ .rl = .{ .ty = .address_space_type } }, var_decl.ast.addrspace_node);
|
||||
};
|
||||
const section_inst: Zir.Inst.Ref = if (var_decl.ast.section_node == 0) .none else inst: {
|
||||
break :inst try comptimeExpr(&block_scope, &block_scope.base, .{ .rl = .{ .ty = .slice_const_u8_type } }, var_decl.ast.section_node);
|
||||
};
|
||||
const has_section_or_addrspace = section_inst != .none or addrspace_inst != .none;
|
||||
wip_members.nextDecl(is_pub, is_export, align_inst != .none, has_section_or_addrspace);
|
||||
wip_members.nextDecl(decl_inst);
|
||||
|
||||
const is_threadlocal = if (var_decl.threadlocal_token) |tok| blk: {
|
||||
if (!is_mutable) {
|
||||
@ -4513,29 +4474,44 @@ fn globalVarDecl(
|
||||
} else {
|
||||
return astgen.failNode(node, "unable to infer variable type", .{});
|
||||
};
|
||||
|
||||
// We do this at the end so that the instruction index marks the end
|
||||
// range of a top level declaration.
|
||||
_ = try block_scope.addBreakWithSrcNode(.break_inline, block_inst, var_inst, node);
|
||||
try block_scope.setBlockBody(block_inst);
|
||||
_ = try block_scope.addBreakWithSrcNode(.break_inline, decl_inst, var_inst, node);
|
||||
|
||||
{
|
||||
const contents_hash align(@alignOf(u32)) = std.zig.hashSrc(tree.getNodeSource(node));
|
||||
wip_members.appendToDeclSlice(std.mem.bytesAsSlice(u32, &contents_hash));
|
||||
var align_gz = block_scope.makeSubBlock(scope);
|
||||
if (var_decl.ast.align_node != 0) {
|
||||
const align_inst = try expr(&align_gz, &align_gz.base, coerced_align_ri, var_decl.ast.align_node);
|
||||
_ = try align_gz.addBreakWithSrcNode(.break_inline, decl_inst, align_inst, node);
|
||||
}
|
||||
{
|
||||
const line_delta = block_scope.decl_line - gz.decl_line;
|
||||
wip_members.appendToDecl(line_delta);
|
||||
|
||||
var linksection_gz = align_gz.makeSubBlock(scope);
|
||||
if (var_decl.ast.section_node != 0) {
|
||||
const linksection_inst = try expr(&linksection_gz, &linksection_gz.base, coerced_linksection_ri, var_decl.ast.section_node);
|
||||
_ = try linksection_gz.addBreakWithSrcNode(.break_inline, decl_inst, linksection_inst, node);
|
||||
}
|
||||
wip_members.appendToDecl(@intFromEnum(name_str_index));
|
||||
wip_members.appendToDecl(@intFromEnum(block_inst));
|
||||
wip_members.appendToDecl(@intFromEnum(doc_comment_index)); // doc_comment wip
|
||||
if (align_inst != .none) {
|
||||
wip_members.appendToDecl(@intFromEnum(align_inst));
|
||||
}
|
||||
if (has_section_or_addrspace) {
|
||||
wip_members.appendToDecl(@intFromEnum(section_inst));
|
||||
wip_members.appendToDecl(@intFromEnum(addrspace_inst));
|
||||
|
||||
var addrspace_gz = linksection_gz.makeSubBlock(scope);
|
||||
if (var_decl.ast.addrspace_node != 0) {
|
||||
const addrspace_inst = try expr(&addrspace_gz, &addrspace_gz.base, coerced_addrspace_ri, var_decl.ast.addrspace_node);
|
||||
_ = try addrspace_gz.addBreakWithSrcNode(.break_inline, decl_inst, addrspace_inst, node);
|
||||
}
|
||||
|
||||
try setDeclaration(
|
||||
decl_inst,
|
||||
std.zig.hashSrc(tree.getNodeSource(node)),
|
||||
.{ .named = name_token },
|
||||
block_scope.decl_line - gz.decl_line,
|
||||
is_pub,
|
||||
is_export,
|
||||
doc_comment_index,
|
||||
&block_scope,
|
||||
.{
|
||||
.align_gz = &align_gz,
|
||||
.linksection_gz = &linksection_gz,
|
||||
.addrspace_gz = &addrspace_gz,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn comptimeDecl(
|
||||
@ -4551,8 +4527,8 @@ fn comptimeDecl(
|
||||
|
||||
// Up top so the ZIR instruction index marks the start range of this
|
||||
// top-level declaration.
|
||||
const block_inst = try gz.makeBlockInst(.block_inline, node);
|
||||
wip_members.nextDecl(false, false, false, false);
|
||||
const decl_inst = try gz.makeBlockInst(.declaration, node);
|
||||
wip_members.nextDecl(decl_inst);
|
||||
astgen.advanceSourceCursorToNode(node);
|
||||
|
||||
var decl_block: GenZir = .{
|
||||
@ -4568,21 +4544,20 @@ fn comptimeDecl(
|
||||
|
||||
const block_result = try expr(&decl_block, &decl_block.base, .{ .rl = .none }, body_node);
|
||||
if (decl_block.isEmpty() or !decl_block.refIsNoReturn(block_result)) {
|
||||
_ = try decl_block.addBreak(.break_inline, block_inst, .void_value);
|
||||
_ = try decl_block.addBreak(.break_inline, decl_inst, .void_value);
|
||||
}
|
||||
try decl_block.setBlockBody(block_inst);
|
||||
|
||||
{
|
||||
const contents_hash align(@alignOf(u32)) = std.zig.hashSrc(tree.getNodeSource(node));
|
||||
wip_members.appendToDeclSlice(std.mem.bytesAsSlice(u32, &contents_hash));
|
||||
}
|
||||
{
|
||||
const line_delta = decl_block.decl_line - gz.decl_line;
|
||||
wip_members.appendToDecl(line_delta);
|
||||
}
|
||||
wip_members.appendToDecl(0);
|
||||
wip_members.appendToDecl(@intFromEnum(block_inst));
|
||||
wip_members.appendToDecl(0); // no doc comments on comptime decls
|
||||
try setDeclaration(
|
||||
decl_inst,
|
||||
std.zig.hashSrc(tree.getNodeSource(node)),
|
||||
.@"comptime",
|
||||
decl_block.decl_line - gz.decl_line,
|
||||
false,
|
||||
false,
|
||||
.empty,
|
||||
&decl_block,
|
||||
null,
|
||||
);
|
||||
}
|
||||
|
||||
fn usingnamespaceDecl(
|
||||
@ -4604,8 +4579,8 @@ fn usingnamespaceDecl(
|
||||
};
|
||||
// Up top so the ZIR instruction index marks the start range of this
|
||||
// top-level declaration.
|
||||
const block_inst = try gz.makeBlockInst(.block_inline, node);
|
||||
wip_members.nextDecl(is_pub, true, false, false);
|
||||
const decl_inst = try gz.makeBlockInst(.declaration, node);
|
||||
wip_members.nextDecl(decl_inst);
|
||||
astgen.advanceSourceCursorToNode(node);
|
||||
|
||||
var decl_block: GenZir = .{
|
||||
@ -4620,20 +4595,19 @@ fn usingnamespaceDecl(
|
||||
defer decl_block.unstack();
|
||||
|
||||
const namespace_inst = try typeExpr(&decl_block, &decl_block.base, type_expr);
|
||||
_ = try decl_block.addBreak(.break_inline, block_inst, namespace_inst);
|
||||
try decl_block.setBlockBody(block_inst);
|
||||
_ = try decl_block.addBreak(.break_inline, decl_inst, namespace_inst);
|
||||
|
||||
{
|
||||
const contents_hash align(@alignOf(u32)) = std.zig.hashSrc(tree.getNodeSource(node));
|
||||
wip_members.appendToDeclSlice(std.mem.bytesAsSlice(u32, &contents_hash));
|
||||
}
|
||||
{
|
||||
const line_delta = decl_block.decl_line - gz.decl_line;
|
||||
wip_members.appendToDecl(line_delta);
|
||||
}
|
||||
wip_members.appendToDecl(0);
|
||||
wip_members.appendToDecl(@intFromEnum(block_inst));
|
||||
wip_members.appendToDecl(0); // no doc comments on usingnamespace decls
|
||||
try setDeclaration(
|
||||
decl_inst,
|
||||
std.zig.hashSrc(tree.getNodeSource(node)),
|
||||
.@"usingnamespace",
|
||||
decl_block.decl_line - gz.decl_line,
|
||||
is_pub,
|
||||
false,
|
||||
.empty,
|
||||
&decl_block,
|
||||
null,
|
||||
);
|
||||
}
|
||||
|
||||
fn testDecl(
|
||||
@ -4649,9 +4623,9 @@ fn testDecl(
|
||||
|
||||
// Up top so the ZIR instruction index marks the start range of this
|
||||
// top-level declaration.
|
||||
const block_inst = try gz.makeBlockInst(.block_inline, node);
|
||||
const decl_inst = try gz.makeBlockInst(.declaration, node);
|
||||
|
||||
wip_members.nextDecl(false, false, false, false);
|
||||
wip_members.nextDecl(decl_inst);
|
||||
astgen.advanceSourceCursorToNode(node);
|
||||
|
||||
var decl_block: GenZir = .{
|
||||
@ -4669,12 +4643,10 @@ fn testDecl(
|
||||
const token_tags = tree.tokens.items(.tag);
|
||||
const test_token = main_tokens[node];
|
||||
const test_name_token = test_token + 1;
|
||||
const test_name_token_tag = token_tags[test_name_token];
|
||||
const is_decltest = test_name_token_tag == .identifier;
|
||||
const test_name: Zir.NullTerminatedString = blk: {
|
||||
if (test_name_token_tag == .string_literal) {
|
||||
break :blk try astgen.testNameString(test_name_token);
|
||||
} else if (test_name_token_tag == .identifier) {
|
||||
const test_name: DeclarationName = switch (token_tags[test_name_token]) {
|
||||
else => .unnamed_test,
|
||||
.string_literal => .{ .named_test = test_name_token },
|
||||
.identifier => blk: {
|
||||
const ident_name_raw = tree.tokenSlice(test_name_token);
|
||||
|
||||
if (mem.eql(u8, ident_name_raw, "_")) return astgen.failTok(test_name_token, "'_' used as an identifier without @\"_\" syntax", .{});
|
||||
@ -4744,10 +4716,8 @@ fn testDecl(
|
||||
return astgen.failTok(test_name_token, "use of undeclared identifier '{s}'", .{ident_name});
|
||||
}
|
||||
|
||||
break :blk name_str_index;
|
||||
}
|
||||
// String table index 1 has a special meaning here of test decl with no name.
|
||||
break :blk .unnamed_test_decl;
|
||||
break :blk .{ .decltest = name_str_index };
|
||||
},
|
||||
};
|
||||
|
||||
var fn_block: GenZir = .{
|
||||
@ -4795,7 +4765,7 @@ fn testDecl(
|
||||
|
||||
.lbrace_line = lbrace_line,
|
||||
.lbrace_column = lbrace_column,
|
||||
.param_block = block_inst,
|
||||
.param_block = decl_inst,
|
||||
.body_gz = &fn_block,
|
||||
.lib_name = .empty,
|
||||
.is_var_args = false,
|
||||
@ -4806,26 +4776,19 @@ fn testDecl(
|
||||
.noalias_bits = 0,
|
||||
});
|
||||
|
||||
_ = try decl_block.addBreak(.break_inline, block_inst, func_inst);
|
||||
try decl_block.setBlockBody(block_inst);
|
||||
_ = try decl_block.addBreak(.break_inline, decl_inst, func_inst);
|
||||
|
||||
{
|
||||
const contents_hash align(@alignOf(u32)) = std.zig.hashSrc(tree.getNodeSource(node));
|
||||
wip_members.appendToDeclSlice(std.mem.bytesAsSlice(u32, &contents_hash));
|
||||
}
|
||||
{
|
||||
const line_delta = decl_block.decl_line - gz.decl_line;
|
||||
wip_members.appendToDecl(line_delta);
|
||||
}
|
||||
if (is_decltest)
|
||||
wip_members.appendToDecl(2) // 2 here means that it is a decltest, look at doc comment for name
|
||||
else
|
||||
wip_members.appendToDecl(@intFromEnum(test_name));
|
||||
wip_members.appendToDecl(@intFromEnum(block_inst));
|
||||
if (is_decltest)
|
||||
wip_members.appendToDecl(@intFromEnum(test_name)) // the doc comment on a decltest represents it's name
|
||||
else
|
||||
wip_members.appendToDecl(0); // no doc comments on test decls
|
||||
try setDeclaration(
|
||||
decl_inst,
|
||||
std.zig.hashSrc(tree.getNodeSource(node)),
|
||||
test_name,
|
||||
decl_block.decl_line - gz.decl_line,
|
||||
false,
|
||||
false,
|
||||
.empty,
|
||||
&decl_block,
|
||||
null,
|
||||
);
|
||||
}
|
||||
|
||||
fn structDeclInner(
|
||||
@ -13524,3 +13487,106 @@ fn lowerAstErrors(astgen: *AstGen) !void {
|
||||
try tree.renderError(parse_err, msg.writer(gpa));
|
||||
try astgen.appendErrorTokNotesOff(parse_err.token, extra_offset, "{s}", .{msg.items}, notes.items);
|
||||
}
|
||||
|
||||
const DeclarationName = union(enum) {
|
||||
named: Ast.TokenIndex,
|
||||
named_test: Ast.TokenIndex,
|
||||
unnamed_test,
|
||||
decltest: Zir.NullTerminatedString,
|
||||
@"comptime",
|
||||
@"usingnamespace",
|
||||
};
|
||||
|
||||
/// Sets all extra data for a `declaration` instruction.
|
||||
/// Unstacks `value_gz`, `align_gz`, `linksection_gz`, and `addrspace_gz`.
|
||||
fn setDeclaration(
|
||||
decl_inst: Zir.Inst.Index,
|
||||
src_hash: std.zig.SrcHash,
|
||||
name: DeclarationName,
|
||||
line_offset: u32,
|
||||
is_pub: bool,
|
||||
is_export: bool,
|
||||
doc_comment: Zir.NullTerminatedString,
|
||||
value_gz: *GenZir,
|
||||
/// May be `null` if all these blocks would be empty.
|
||||
/// If `null`, then `value_gz` must have nothing stacked on it.
|
||||
extra_gzs: ?struct {
|
||||
/// Must be stacked on `value_gz`.
|
||||
align_gz: *GenZir,
|
||||
/// Must be stacked on `align_gz`.
|
||||
linksection_gz: *GenZir,
|
||||
/// Must be stacked on `linksection_gz`, and have nothing stacked on it.
|
||||
addrspace_gz: *GenZir,
|
||||
},
|
||||
) !void {
|
||||
const astgen = value_gz.astgen;
|
||||
const gpa = astgen.gpa;
|
||||
|
||||
const empty_body: []Zir.Inst.Index = &.{};
|
||||
const value_body, const align_body, const linksection_body, const addrspace_body = if (extra_gzs) |e| .{
|
||||
value_gz.instructionsSliceUpto(e.align_gz),
|
||||
e.align_gz.instructionsSliceUpto(e.linksection_gz),
|
||||
e.linksection_gz.instructionsSliceUpto(e.addrspace_gz),
|
||||
e.addrspace_gz.instructionsSlice(),
|
||||
} else .{ value_gz.instructionsSlice(), empty_body, empty_body, empty_body };
|
||||
|
||||
const value_len = astgen.countBodyLenAfterFixups(value_body);
|
||||
const align_len = astgen.countBodyLenAfterFixups(align_body);
|
||||
const linksection_len = astgen.countBodyLenAfterFixups(linksection_body);
|
||||
const addrspace_len = astgen.countBodyLenAfterFixups(addrspace_body);
|
||||
|
||||
const true_doc_comment: Zir.NullTerminatedString = switch (name) {
|
||||
.decltest => |test_name| test_name,
|
||||
else => doc_comment,
|
||||
};
|
||||
|
||||
const src_hash_arr: [4]u32 = @bitCast(src_hash);
|
||||
|
||||
const extra: Zir.Inst.Declaration = .{
|
||||
.src_hash_0 = src_hash_arr[0],
|
||||
.src_hash_1 = src_hash_arr[1],
|
||||
.src_hash_2 = src_hash_arr[2],
|
||||
.src_hash_3 = src_hash_arr[3],
|
||||
.name = switch (name) {
|
||||
.named => |tok| @enumFromInt(@intFromEnum(try astgen.identAsString(tok))),
|
||||
.named_test => |tok| @enumFromInt(@intFromEnum(try astgen.testNameString(tok))),
|
||||
.unnamed_test => .unnamed_test,
|
||||
.decltest => .decltest,
|
||||
.@"comptime" => .@"comptime",
|
||||
.@"usingnamespace" => .@"usingnamespace",
|
||||
},
|
||||
.line_offset = line_offset,
|
||||
.flags = .{
|
||||
.value_body_len = @intCast(value_len),
|
||||
.is_pub = is_pub,
|
||||
.is_export = is_export,
|
||||
.has_doc_comment = true_doc_comment != .empty,
|
||||
.has_align_linksection_addrspace = align_len != 0 or linksection_len != 0 or addrspace_len != 0,
|
||||
},
|
||||
};
|
||||
astgen.instructions.items(.data)[@intFromEnum(decl_inst)].pl_node.payload_index = try astgen.addExtra(extra);
|
||||
if (extra.flags.has_doc_comment) {
|
||||
try astgen.extra.append(gpa, @intFromEnum(true_doc_comment));
|
||||
}
|
||||
if (extra.flags.has_align_linksection_addrspace) {
|
||||
try astgen.extra.appendSlice(gpa, &.{
|
||||
align_len,
|
||||
linksection_len,
|
||||
addrspace_len,
|
||||
});
|
||||
}
|
||||
try astgen.extra.ensureUnusedCapacity(gpa, value_len + align_len + linksection_len + addrspace_len);
|
||||
astgen.appendBodyWithFixups(value_body);
|
||||
if (extra.flags.has_align_linksection_addrspace) {
|
||||
astgen.appendBodyWithFixups(align_body);
|
||||
astgen.appendBodyWithFixups(linksection_body);
|
||||
astgen.appendBodyWithFixups(addrspace_body);
|
||||
}
|
||||
|
||||
if (extra_gzs) |e| {
|
||||
e.addrspace_gz.unstack();
|
||||
e.linksection_gz.unstack();
|
||||
e.align_gz.unstack();
|
||||
}
|
||||
value_gz.unstack();
|
||||
}
|
||||
|
||||
302
src/Autodoc.zig
302
src/Autodoc.zig
@ -2846,22 +2846,14 @@ fn walkInstruction(
|
||||
return res;
|
||||
},
|
||||
.block_inline => {
|
||||
return self.walkRef(
|
||||
const pl_node = data[@intFromEnum(inst)].pl_node;
|
||||
const extra = file.zir.extraData(Zir.Inst.Block, pl_node.payload_index);
|
||||
return self.walkInlineBody(
|
||||
file,
|
||||
parent_scope,
|
||||
try self.srcLocInfo(file, pl_node.src_node, parent_src),
|
||||
parent_src,
|
||||
getBlockInlineBreak(file.zir, inst) orelse {
|
||||
const res = DocData.WalkResult{
|
||||
.typeRef = .{ .type = @intFromEnum(Ref.type_type) },
|
||||
.expr = .{ .comptimeExpr = self.comptime_exprs.items.len },
|
||||
};
|
||||
const pl_node = data[@intFromEnum(inst)].pl_node;
|
||||
const block_inline_expr = try self.getBlockSource(file, parent_src, pl_node.src_node);
|
||||
try self.comptime_exprs.append(self.arena, .{
|
||||
.code = block_inline_expr,
|
||||
});
|
||||
return res;
|
||||
},
|
||||
file.zir.bodySlice(extra.end, extra.data.body_len),
|
||||
need_type,
|
||||
call_ctx,
|
||||
);
|
||||
@ -4084,19 +4076,11 @@ fn analyzeAllDecls(
|
||||
// First loop to discover decl names
|
||||
{
|
||||
var it = original_it;
|
||||
while (it.next()) |d| {
|
||||
const decl_name_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[@intFromEnum(d.sub_index) + 5]);
|
||||
switch (decl_name_index) {
|
||||
.empty,
|
||||
.unnamed_test_decl,
|
||||
.decltest,
|
||||
=> continue,
|
||||
_ => if (file.zir.nullTerminatedString(decl_name_index).len == 0) {
|
||||
continue;
|
||||
},
|
||||
}
|
||||
|
||||
try scope.insertDeclRef(self.arena, decl_name_index, .Pending);
|
||||
while (it.next()) |zir_index| {
|
||||
const declaration, _ = file.zir.getDeclaration(zir_index);
|
||||
if (declaration.name.isNamedTest(file.zir)) continue;
|
||||
const decl_name = declaration.name.toString(file.zir) orelse continue;
|
||||
try scope.insertDeclRef(self.arena, decl_name, .Pending);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4104,147 +4088,114 @@ fn analyzeAllDecls(
|
||||
{
|
||||
var it = original_it;
|
||||
var decl_indexes_slot = first_decl_indexes_slot;
|
||||
while (it.next()) |d| : (decl_indexes_slot += 1) {
|
||||
const decl_name_index = file.zir.extra[@intFromEnum(d.sub_index) + 5];
|
||||
switch (decl_name_index) {
|
||||
0 => {
|
||||
const is_exported = @as(u1, @truncate(d.flags >> 1));
|
||||
switch (is_exported) {
|
||||
0 => continue, // comptime decl
|
||||
1 => {
|
||||
try self.analyzeUsingnamespaceDecl(
|
||||
file,
|
||||
scope,
|
||||
parent_src,
|
||||
decl_indexes,
|
||||
priv_decl_indexes,
|
||||
d,
|
||||
call_ctx,
|
||||
);
|
||||
},
|
||||
}
|
||||
},
|
||||
else => continue,
|
||||
}
|
||||
while (it.next()) |zir_index| : (decl_indexes_slot += 1) {
|
||||
const pl_node = file.zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
|
||||
const extra = file.zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
|
||||
if (extra.data.name != .@"usingnamespace") continue;
|
||||
try self.analyzeUsingnamespaceDecl(
|
||||
file,
|
||||
scope,
|
||||
try self.srcLocInfo(file, pl_node.src_node, parent_src),
|
||||
decl_indexes,
|
||||
priv_decl_indexes,
|
||||
extra.data,
|
||||
@intCast(extra.end),
|
||||
call_ctx,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Third loop to analyze all remaining decls
|
||||
var it = original_it;
|
||||
while (it.next()) |d| {
|
||||
const decl_name_index = file.zir.extra[@intFromEnum(d.sub_index) + 5];
|
||||
switch (decl_name_index) {
|
||||
0, 1 => continue, // skip over usingnamespace decls
|
||||
2 => continue, // skip decltests
|
||||
|
||||
else => if (file.zir.string_bytes[decl_name_index] == 0) {
|
||||
continue;
|
||||
},
|
||||
{
|
||||
var it = original_it;
|
||||
while (it.next()) |zir_index| {
|
||||
const pl_node = file.zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
|
||||
const extra = file.zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
|
||||
switch (extra.data.name) {
|
||||
.@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue,
|
||||
_ => if (extra.data.name.isNamedTest(file.zir)) continue,
|
||||
}
|
||||
try self.analyzeDecl(
|
||||
file,
|
||||
scope,
|
||||
try self.srcLocInfo(file, pl_node.src_node, parent_src),
|
||||
decl_indexes,
|
||||
priv_decl_indexes,
|
||||
zir_index,
|
||||
extra.data,
|
||||
@intCast(extra.end),
|
||||
call_ctx,
|
||||
);
|
||||
}
|
||||
|
||||
try self.analyzeDecl(
|
||||
file,
|
||||
scope,
|
||||
parent_src,
|
||||
decl_indexes,
|
||||
priv_decl_indexes,
|
||||
d,
|
||||
call_ctx,
|
||||
);
|
||||
}
|
||||
|
||||
// Fourth loop to analyze decltests
|
||||
it = original_it;
|
||||
while (it.next()) |d| {
|
||||
const decl_name_index = file.zir.extra[@intFromEnum(d.sub_index) + 5];
|
||||
switch (decl_name_index) {
|
||||
0, 1 => continue, // skip over usingnamespace decls
|
||||
2 => {},
|
||||
else => continue, // skip tests and normal decls
|
||||
}
|
||||
|
||||
var it = original_it;
|
||||
while (it.next()) |zir_index| {
|
||||
const pl_node = file.zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
|
||||
const extra = file.zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
|
||||
if (extra.data.name != .decltest) continue;
|
||||
try self.analyzeDecltest(
|
||||
file,
|
||||
scope,
|
||||
parent_src,
|
||||
d,
|
||||
try self.srcLocInfo(file, pl_node.src_node, parent_src),
|
||||
extra.data,
|
||||
@intCast(extra.end),
|
||||
);
|
||||
}
|
||||
|
||||
return it.extra_index;
|
||||
}
|
||||
|
||||
fn walkInlineBody(
|
||||
autodoc: *Autodoc,
|
||||
file: *File,
|
||||
scope: *Scope,
|
||||
block_src: SrcLocInfo,
|
||||
parent_src: SrcLocInfo,
|
||||
body: []const Zir.Inst.Index,
|
||||
need_type: bool,
|
||||
call_ctx: ?*const CallContext,
|
||||
) AutodocErrors!DocData.WalkResult {
|
||||
const tags = file.zir.instructions.items(.tag);
|
||||
const break_inst = switch (tags[@intFromEnum(body[body.len - 1])]) {
|
||||
.condbr_inline => {
|
||||
// Unresolvable.
|
||||
const res: DocData.WalkResult = .{
|
||||
.typeRef = .{ .type = @intFromEnum(Ref.type_type) },
|
||||
.expr = .{ .comptimeExpr = autodoc.comptime_exprs.items.len },
|
||||
};
|
||||
const source = (try file.getTree(autodoc.zcu.gpa)).getNodeSource(block_src.src_node);
|
||||
try autodoc.comptime_exprs.append(autodoc.arena, .{
|
||||
.code = source,
|
||||
});
|
||||
return res;
|
||||
},
|
||||
.break_inline => body[body.len - 1],
|
||||
else => unreachable,
|
||||
};
|
||||
const break_data = file.zir.instructions.items(.data)[@intFromEnum(break_inst)].@"break";
|
||||
return autodoc.walkRef(file, scope, parent_src, break_data.operand, need_type, call_ctx);
|
||||
}
|
||||
|
||||
// Asserts the given decl is public
|
||||
fn analyzeDecl(
|
||||
self: *Autodoc,
|
||||
file: *File,
|
||||
scope: *Scope,
|
||||
parent_src: SrcLocInfo,
|
||||
decl_src: SrcLocInfo,
|
||||
decl_indexes: *std.ArrayListUnmanaged(usize),
|
||||
priv_decl_indexes: *std.ArrayListUnmanaged(usize),
|
||||
d: Zir.DeclIterator.Item,
|
||||
decl_inst: Zir.Inst.Index,
|
||||
declaration: Zir.Inst.Declaration,
|
||||
extra_index: u32,
|
||||
call_ctx: ?*const CallContext,
|
||||
) AutodocErrors!void {
|
||||
const data = file.zir.instructions.items(.data);
|
||||
const is_pub = @as(u1, @truncate(d.flags >> 0)) != 0;
|
||||
// const is_exported = @truncate(u1, d.flags >> 1) != 0;
|
||||
const has_align = @as(u1, @truncate(d.flags >> 2)) != 0;
|
||||
const has_section_or_addrspace = @as(u1, @truncate(d.flags >> 3)) != 0;
|
||||
const bodies = declaration.getBodies(extra_index, file.zir);
|
||||
const name = file.zir.nullTerminatedString(declaration.name.toString(file.zir).?);
|
||||
|
||||
var extra_index = @intFromEnum(d.sub_index);
|
||||
// const hash_u32s = file.zir.extra[extra_index..][0..4];
|
||||
|
||||
extra_index += 4;
|
||||
// const line = file.zir.extra[extra_index];
|
||||
|
||||
extra_index += 1;
|
||||
const decl_name_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[extra_index]);
|
||||
|
||||
extra_index += 1;
|
||||
const value_index: Zir.Inst.Index = @enumFromInt(file.zir.extra[extra_index]);
|
||||
|
||||
extra_index += 1;
|
||||
const doc_comment_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[extra_index]);
|
||||
|
||||
extra_index += 1;
|
||||
const align_inst: Zir.Inst.Ref = if (!has_align) .none else inst: {
|
||||
const inst: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
break :inst inst;
|
||||
};
|
||||
_ = align_inst;
|
||||
|
||||
const section_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: {
|
||||
const inst: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
break :inst inst;
|
||||
};
|
||||
_ = section_inst;
|
||||
|
||||
const addrspace_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: {
|
||||
const inst: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
break :inst inst;
|
||||
};
|
||||
_ = addrspace_inst;
|
||||
|
||||
// This is known to work because decl values are always block_inlines
|
||||
const value_pl_node = data[@intFromEnum(value_index)].pl_node;
|
||||
const decl_src = try self.srcLocInfo(file, value_pl_node.src_node, parent_src);
|
||||
|
||||
const name: []const u8 = switch (decl_name_index) {
|
||||
.empty, .unnamed_test_decl, .decltest => unreachable,
|
||||
_ => blk: {
|
||||
if (decl_name_index == .empty) {
|
||||
// test decl
|
||||
unreachable;
|
||||
}
|
||||
break :blk file.zir.nullTerminatedString(decl_name_index);
|
||||
},
|
||||
};
|
||||
|
||||
const doc_comment: ?[]const u8 = if (doc_comment_index != .empty)
|
||||
file.zir.nullTerminatedString(doc_comment_index)
|
||||
const doc_comment: ?[]const u8 = if (declaration.flags.has_doc_comment)
|
||||
file.zir.nullTerminatedString(@enumFromInt(file.zir.extra[extra_index]))
|
||||
else
|
||||
null;
|
||||
|
||||
@ -4261,16 +4212,22 @@ fn analyzeDecl(
|
||||
break :idx idx;
|
||||
};
|
||||
|
||||
const walk_result = try self.walkInstruction(
|
||||
const walk_result = try self.walkInlineBody(
|
||||
file,
|
||||
scope,
|
||||
decl_src,
|
||||
value_index,
|
||||
decl_src,
|
||||
bodies.value_body,
|
||||
true,
|
||||
call_ctx,
|
||||
);
|
||||
|
||||
const kind: []const u8 = if (try self.declIsVar(file, value_pl_node.src_node, parent_src)) "var" else "const";
|
||||
const tree = try file.getTree(self.zcu.gpa);
|
||||
const kind_token = tree.nodes.items(.main_token)[decl_src.src_node];
|
||||
const kind: []const u8 = switch (tree.tokens.items(.tag)[kind_token]) {
|
||||
.keyword_var => "var",
|
||||
else => "const",
|
||||
};
|
||||
|
||||
const decls_slot_index = self.decls.items.len;
|
||||
try self.decls.append(self.arena, .{
|
||||
@ -4281,13 +4238,13 @@ fn analyzeDecl(
|
||||
.parent_container = scope.enclosing_type,
|
||||
});
|
||||
|
||||
if (is_pub) {
|
||||
if (declaration.flags.is_pub) {
|
||||
try decl_indexes.append(self.arena, decls_slot_index);
|
||||
} else {
|
||||
try priv_decl_indexes.append(self.arena, decls_slot_index);
|
||||
}
|
||||
|
||||
const decl_status_ptr = scope.resolveDeclName(decl_name_index, file, .none);
|
||||
const decl_status_ptr = scope.resolveDeclName(declaration.name.toString(file.zir).?, file, .none);
|
||||
std.debug.assert(decl_status_ptr.* == .Pending);
|
||||
decl_status_ptr.* = .{ .Analyzed = decls_slot_index };
|
||||
|
||||
@ -4296,7 +4253,7 @@ fn analyzeDecl(
|
||||
for (paths.items) |resume_info| {
|
||||
try self.tryResolveRefPath(
|
||||
resume_info.file,
|
||||
value_index,
|
||||
decl_inst,
|
||||
resume_info.ref_path,
|
||||
);
|
||||
}
|
||||
@ -4312,24 +4269,17 @@ fn analyzeUsingnamespaceDecl(
|
||||
self: *Autodoc,
|
||||
file: *File,
|
||||
scope: *Scope,
|
||||
parent_src: SrcLocInfo,
|
||||
decl_src: SrcLocInfo,
|
||||
decl_indexes: *std.ArrayListUnmanaged(usize),
|
||||
priv_decl_indexes: *std.ArrayListUnmanaged(usize),
|
||||
d: Zir.DeclIterator.Item,
|
||||
declaration: Zir.Inst.Declaration,
|
||||
extra_index: u32,
|
||||
call_ctx: ?*const CallContext,
|
||||
) AutodocErrors!void {
|
||||
const data = file.zir.instructions.items(.data);
|
||||
const bodies = declaration.getBodies(extra_index, file.zir);
|
||||
|
||||
const is_pub = @as(u1, @truncate(d.flags)) != 0;
|
||||
const value_index: Zir.Inst.Index = @enumFromInt(file.zir.extra[@intFromEnum(d.sub_index) + 6]);
|
||||
const doc_comment_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[@intFromEnum(d.sub_index) + 7]);
|
||||
|
||||
// This is known to work because decl values are always block_inlines
|
||||
const value_pl_node = data[@intFromEnum(value_index)].pl_node;
|
||||
const decl_src = try self.srcLocInfo(file, value_pl_node.src_node, parent_src);
|
||||
|
||||
const doc_comment: ?[]const u8 = if (doc_comment_index != .empty)
|
||||
file.zir.nullTerminatedString(doc_comment_index)
|
||||
const doc_comment: ?[]const u8 = if (declaration.flags.has_doc_comment)
|
||||
file.zir.nullTerminatedString(@enumFromInt(file.zir.extra[extra_index]))
|
||||
else
|
||||
null;
|
||||
|
||||
@ -4346,11 +4296,12 @@ fn analyzeUsingnamespaceDecl(
|
||||
break :idx idx;
|
||||
};
|
||||
|
||||
const walk_result = try self.walkInstruction(
|
||||
const walk_result = try self.walkInlineBody(
|
||||
file,
|
||||
scope,
|
||||
decl_src,
|
||||
value_index,
|
||||
decl_src,
|
||||
bodies.value_body,
|
||||
true,
|
||||
call_ctx,
|
||||
);
|
||||
@ -4365,7 +4316,7 @@ fn analyzeUsingnamespaceDecl(
|
||||
.parent_container = scope.enclosing_type,
|
||||
});
|
||||
|
||||
if (is_pub) {
|
||||
if (declaration.flags.is_pub) {
|
||||
try decl_indexes.append(self.arena, decl_slot_index);
|
||||
} else {
|
||||
try priv_decl_indexes.append(self.arena, decl_slot_index);
|
||||
@ -4376,18 +4327,14 @@ fn analyzeDecltest(
|
||||
self: *Autodoc,
|
||||
file: *File,
|
||||
scope: *Scope,
|
||||
parent_src: SrcLocInfo,
|
||||
d: Zir.DeclIterator.Item,
|
||||
decl_src: SrcLocInfo,
|
||||
declaration: Zir.Inst.Declaration,
|
||||
extra_index: u32,
|
||||
) AutodocErrors!void {
|
||||
const data = file.zir.instructions.items(.data);
|
||||
std.debug.assert(declaration.flags.has_doc_comment);
|
||||
const decl_name_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[extra_index]);
|
||||
|
||||
const value_index = file.zir.extra[@intFromEnum(d.sub_index) + 6];
|
||||
const decl_name_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[@intFromEnum(d.sub_index) + 7]);
|
||||
|
||||
const value_pl_node = data[value_index].pl_node;
|
||||
const decl_src = try self.srcLocInfo(file, value_pl_node.src_node, parent_src);
|
||||
|
||||
const test_source_code = try self.getBlockSource(file, parent_src, value_pl_node.src_node);
|
||||
const test_source_code = (try file.getTree(self.zcu.gpa)).getNodeSource(decl_src.src_node);
|
||||
|
||||
const decl_name: ?[]const u8 = if (decl_name_index != .empty)
|
||||
file.zir.nullTerminatedString(decl_name_index)
|
||||
@ -5830,17 +5777,6 @@ fn walkRef(
|
||||
}
|
||||
}
|
||||
|
||||
fn getBlockInlineBreak(zir: Zir, inst: Zir.Inst.Index) ?Zir.Inst.Ref {
|
||||
const tags = zir.instructions.items(.tag);
|
||||
const data = zir.instructions.items(.data);
|
||||
const pl_node = data[@intFromEnum(inst)].pl_node;
|
||||
const extra = zir.extraData(Zir.Inst.Block, pl_node.payload_index);
|
||||
const break_index = zir.extra[extra.end..][extra.data.body_len - 1];
|
||||
if (tags[break_index] == .condbr_inline) return null;
|
||||
std.debug.assert(tags[break_index] == .break_inline);
|
||||
return data[break_index].@"break".operand;
|
||||
}
|
||||
|
||||
fn printWithContext(
|
||||
file: *File,
|
||||
inst: Zir.Inst.Index,
|
||||
|
||||
@ -2802,6 +2802,7 @@ const Header = extern struct {
|
||||
extra_len: u32,
|
||||
limbs_len: u32,
|
||||
string_bytes_len: u32,
|
||||
tracked_insts_len: u32,
|
||||
},
|
||||
};
|
||||
|
||||
@ -2809,7 +2810,7 @@ const Header = extern struct {
|
||||
/// saved, such as the target and most CLI flags. A cache hit will only occur
|
||||
/// when subsequent compiler invocations use the same set of flags.
|
||||
pub fn saveState(comp: *Compilation) !void {
|
||||
var bufs_list: [6]std.os.iovec_const = undefined;
|
||||
var bufs_list: [7]std.os.iovec_const = undefined;
|
||||
var bufs_len: usize = 0;
|
||||
|
||||
const lf = comp.bin_file orelse return;
|
||||
@ -2822,6 +2823,7 @@ pub fn saveState(comp: *Compilation) !void {
|
||||
.extra_len = @intCast(ip.extra.items.len),
|
||||
.limbs_len = @intCast(ip.limbs.items.len),
|
||||
.string_bytes_len = @intCast(ip.string_bytes.items.len),
|
||||
.tracked_insts_len = @intCast(ip.tracked_insts.count()),
|
||||
},
|
||||
};
|
||||
addBuf(&bufs_list, &bufs_len, mem.asBytes(&header));
|
||||
@ -2830,6 +2832,7 @@ pub fn saveState(comp: *Compilation) !void {
|
||||
addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.items.items(.data)));
|
||||
addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.items.items(.tag)));
|
||||
addBuf(&bufs_list, &bufs_len, ip.string_bytes.items);
|
||||
addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.tracked_insts.keys()));
|
||||
|
||||
// TODO: compilation errors
|
||||
// TODO: files
|
||||
|
||||
@ -54,6 +54,34 @@ string_table: std.HashMapUnmanaged(
|
||||
std.hash_map.default_max_load_percentage,
|
||||
) = .{},
|
||||
|
||||
/// An index into `tracked_insts` gives a reference to a single ZIR instruction which
|
||||
/// persists across incremental updates.
|
||||
tracked_insts: std.AutoArrayHashMapUnmanaged(TrackedInst, void) = .{},
|
||||
|
||||
pub const TrackedInst = extern struct {
|
||||
path_digest: Cache.BinDigest,
|
||||
inst: Zir.Inst.Index,
|
||||
comptime {
|
||||
// The fields should be tightly packed. See also serialiation logic in `Compilation.saveState`.
|
||||
assert(@sizeOf(@This()) == Cache.bin_digest_len + @sizeOf(Zir.Inst.Index));
|
||||
}
|
||||
pub const Index = enum(u32) {
|
||||
_,
|
||||
pub fn resolve(i: TrackedInst.Index, ip: *const InternPool) Zir.Inst.Index {
|
||||
return ip.tracked_insts.keys()[@intFromEnum(i)].inst;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
pub fn trackZir(ip: *InternPool, gpa: Allocator, file: *Module.File, inst: Zir.Inst.Index) Allocator.Error!TrackedInst.Index {
|
||||
const key: TrackedInst = .{
|
||||
.path_digest = file.path_digest,
|
||||
.inst = inst,
|
||||
};
|
||||
const gop = try ip.tracked_insts.getOrPut(gpa, key);
|
||||
return @enumFromInt(gop.index);
|
||||
}
|
||||
|
||||
const FieldMap = std.ArrayHashMapUnmanaged(void, void, std.array_hash_map.AutoContext(void), false);
|
||||
|
||||
const builtin = @import("builtin");
|
||||
@ -62,11 +90,13 @@ const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
const BigIntConst = std.math.big.int.Const;
|
||||
const BigIntMutable = std.math.big.int.Mutable;
|
||||
const Cache = std.Build.Cache;
|
||||
const Limb = std.math.big.Limb;
|
||||
const Hash = std.hash.Wyhash;
|
||||
|
||||
const InternPool = @This();
|
||||
const Module = @import("Module.zig");
|
||||
const Zcu = Module;
|
||||
const Zir = @import("Zir.zig");
|
||||
|
||||
const KeyAdapter = struct {
|
||||
@ -409,7 +439,7 @@ pub const Key = union(enum) {
|
||||
/// `none` when the struct has no declarations.
|
||||
namespace: OptionalNamespaceIndex,
|
||||
/// Index of the struct_decl ZIR instruction.
|
||||
zir_index: Zir.Inst.Index,
|
||||
zir_index: TrackedInst.Index,
|
||||
layout: std.builtin.Type.ContainerLayout,
|
||||
field_names: NullTerminatedString.Slice,
|
||||
field_types: Index.Slice,
|
||||
@ -653,7 +683,7 @@ pub const Key = union(enum) {
|
||||
}
|
||||
|
||||
/// Asserts the struct is not packed.
|
||||
pub fn setZirIndex(s: @This(), ip: *InternPool, new_zir_index: Zir.Inst.Index) void {
|
||||
pub fn setZirIndex(s: @This(), ip: *InternPool, new_zir_index: TrackedInst.Index) void {
|
||||
assert(s.layout != .Packed);
|
||||
const field_index = std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?;
|
||||
ip.extra.items[s.extra_index + field_index] = @intFromEnum(new_zir_index);
|
||||
@ -769,7 +799,7 @@ pub const Key = union(enum) {
|
||||
flags: Tag.TypeUnion.Flags,
|
||||
/// The enum that provides the list of field names and values.
|
||||
enum_tag_ty: Index,
|
||||
zir_index: Zir.Inst.Index,
|
||||
zir_index: TrackedInst.Index,
|
||||
|
||||
/// The returned pointer expires with any addition to the `InternPool`.
|
||||
pub fn flagsPtr(self: @This(), ip: *const InternPool) *Tag.TypeUnion.Flags {
|
||||
@ -1056,7 +1086,7 @@ pub const Key = union(enum) {
|
||||
/// the body. We store this rather than the body directly so that when ZIR
|
||||
/// is regenerated on update(), we can map this to the new corresponding
|
||||
/// ZIR instruction.
|
||||
zir_body_inst: Zir.Inst.Index,
|
||||
zir_body_inst: TrackedInst.Index,
|
||||
/// Relative to owner Decl.
|
||||
lbrace_line: u32,
|
||||
/// Relative to owner Decl.
|
||||
@ -1082,7 +1112,7 @@ pub const Key = union(enum) {
|
||||
}
|
||||
|
||||
/// Returns a pointer that becomes invalid after any additions to the `InternPool`.
|
||||
pub fn zirBodyInst(func: *const Func, ip: *const InternPool) *Zir.Inst.Index {
|
||||
pub fn zirBodyInst(func: *const Func, ip: *const InternPool) *TrackedInst.Index {
|
||||
return @ptrCast(&ip.extra.items[func.zir_body_inst_extra_index]);
|
||||
}
|
||||
|
||||
@ -1860,7 +1890,7 @@ pub const UnionType = struct {
|
||||
/// If this slice has length 0 it means all elements are `none`.
|
||||
field_aligns: Alignment.Slice,
|
||||
/// Index of the union_decl ZIR instruction.
|
||||
zir_index: Zir.Inst.Index,
|
||||
zir_index: TrackedInst.Index,
|
||||
/// Index into extra array of the `flags` field.
|
||||
flags_index: u32,
|
||||
/// Copied from `enum_tag_ty`.
|
||||
@ -1954,10 +1984,10 @@ pub const UnionType = struct {
|
||||
}
|
||||
|
||||
/// This does not mutate the field of UnionType.
|
||||
pub fn setZirIndex(self: @This(), ip: *InternPool, new_zir_index: Zir.Inst.Index) void {
|
||||
pub fn setZirIndex(self: @This(), ip: *InternPool, new_zir_index: TrackedInst.Index) void {
|
||||
const flags_field_index = std.meta.fieldIndex(Tag.TypeUnion, "flags").?;
|
||||
const zir_index_field_index = std.meta.fieldIndex(Tag.TypeUnion, "zir_index").?;
|
||||
const ptr: *Zir.Inst.Index =
|
||||
const ptr: *TrackedInst.Index =
|
||||
@ptrCast(&ip.extra.items[self.flags_index - flags_field_index + zir_index_field_index]);
|
||||
ptr.* = new_zir_index;
|
||||
}
|
||||
@ -2976,7 +3006,7 @@ pub const Tag = enum(u8) {
|
||||
analysis: FuncAnalysis,
|
||||
owner_decl: DeclIndex,
|
||||
ty: Index,
|
||||
zir_body_inst: Zir.Inst.Index,
|
||||
zir_body_inst: TrackedInst.Index,
|
||||
lbrace_line: u32,
|
||||
rbrace_line: u32,
|
||||
lbrace_column: u32,
|
||||
@ -3050,7 +3080,7 @@ pub const Tag = enum(u8) {
|
||||
namespace: NamespaceIndex,
|
||||
/// The enum that provides the list of field names and values.
|
||||
tag_ty: Index,
|
||||
zir_index: Zir.Inst.Index,
|
||||
zir_index: TrackedInst.Index,
|
||||
|
||||
pub const Flags = packed struct(u32) {
|
||||
runtime_tag: UnionType.RuntimeTag,
|
||||
@ -3072,7 +3102,7 @@ pub const Tag = enum(u8) {
|
||||
/// 2. init: Index for each fields_len // if tag is type_struct_packed_inits
|
||||
pub const TypeStructPacked = struct {
|
||||
decl: DeclIndex,
|
||||
zir_index: Zir.Inst.Index,
|
||||
zir_index: TrackedInst.Index,
|
||||
fields_len: u32,
|
||||
namespace: OptionalNamespaceIndex,
|
||||
backing_int_ty: Index,
|
||||
@ -3119,7 +3149,7 @@ pub const Tag = enum(u8) {
|
||||
/// 7. field_offset: u32 // for each field in declared order, undef until layout_resolved
|
||||
pub const TypeStruct = struct {
|
||||
decl: DeclIndex,
|
||||
zir_index: Zir.Inst.Index,
|
||||
zir_index: TrackedInst.Index,
|
||||
fields_len: u32,
|
||||
flags: Flags,
|
||||
size: u32,
|
||||
@ -3708,6 +3738,8 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
|
||||
|
||||
ip.string_table.deinit(gpa);
|
||||
|
||||
ip.tracked_insts.deinit(gpa);
|
||||
|
||||
ip.* = undefined;
|
||||
}
|
||||
|
||||
@ -5358,7 +5390,7 @@ pub const UnionTypeInit = struct {
|
||||
flags: Tag.TypeUnion.Flags,
|
||||
decl: DeclIndex,
|
||||
namespace: NamespaceIndex,
|
||||
zir_index: Zir.Inst.Index,
|
||||
zir_index: TrackedInst.Index,
|
||||
fields_len: u32,
|
||||
enum_tag_ty: Index,
|
||||
/// May have length 0 which leaves the values unset until later.
|
||||
@ -5430,7 +5462,7 @@ pub const StructTypeInit = struct {
|
||||
decl: DeclIndex,
|
||||
namespace: OptionalNamespaceIndex,
|
||||
layout: std.builtin.Type.ContainerLayout,
|
||||
zir_index: Zir.Inst.Index,
|
||||
zir_index: TrackedInst.Index,
|
||||
fields_len: u32,
|
||||
known_non_opv: bool,
|
||||
requires_comptime: RequiresComptime,
|
||||
@ -5704,7 +5736,7 @@ pub fn getExternFunc(ip: *InternPool, gpa: Allocator, key: Key.ExternFunc) Alloc
|
||||
pub const GetFuncDeclKey = struct {
|
||||
owner_decl: DeclIndex,
|
||||
ty: Index,
|
||||
zir_body_inst: Zir.Inst.Index,
|
||||
zir_body_inst: TrackedInst.Index,
|
||||
lbrace_line: u32,
|
||||
rbrace_line: u32,
|
||||
lbrace_column: u32,
|
||||
@ -5773,7 +5805,7 @@ pub const GetFuncDeclIesKey = struct {
|
||||
is_var_args: bool,
|
||||
is_generic: bool,
|
||||
is_noinline: bool,
|
||||
zir_body_inst: Zir.Inst.Index,
|
||||
zir_body_inst: TrackedInst.Index,
|
||||
lbrace_line: u32,
|
||||
rbrace_line: u32,
|
||||
lbrace_column: u32,
|
||||
@ -6186,8 +6218,6 @@ fn finishFuncInstance(
|
||||
.generation = generation,
|
||||
.is_pub = fn_owner_decl.is_pub,
|
||||
.is_exported = fn_owner_decl.is_exported,
|
||||
.has_linksection_or_addrspace = fn_owner_decl.has_linksection_or_addrspace,
|
||||
.has_align = fn_owner_decl.has_align,
|
||||
.alive = true,
|
||||
.kind = .anon,
|
||||
});
|
||||
@ -6537,7 +6567,7 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {
|
||||
NullTerminatedString,
|
||||
OptionalNullTerminatedString,
|
||||
Tag.TypePointer.VectorIndex,
|
||||
Zir.Inst.Index,
|
||||
TrackedInst.Index,
|
||||
=> @intFromEnum(@field(extra, field.name)),
|
||||
|
||||
u32,
|
||||
@ -6613,7 +6643,7 @@ fn extraDataTrail(ip: *const InternPool, comptime T: type, index: usize) struct
|
||||
NullTerminatedString,
|
||||
OptionalNullTerminatedString,
|
||||
Tag.TypePointer.VectorIndex,
|
||||
Zir.Inst.Index,
|
||||
TrackedInst.Index,
|
||||
=> @enumFromInt(int32),
|
||||
|
||||
u32,
|
||||
@ -8319,7 +8349,7 @@ pub fn funcHasInferredErrorSet(ip: *const InternPool, i: Index) bool {
|
||||
return funcAnalysis(ip, i).inferred_error_set;
|
||||
}
|
||||
|
||||
pub fn funcZirBodyInst(ip: *const InternPool, i: Index) Zir.Inst.Index {
|
||||
pub fn funcZirBodyInst(ip: *const InternPool, i: Index) TrackedInst.Index {
|
||||
assert(i != .none);
|
||||
const item = ip.items.get(@intFromEnum(i));
|
||||
const zir_body_inst_field_index = std.meta.fieldIndex(Tag.FuncDecl, "zir_body_inst").?;
|
||||
|
||||
586
src/Module.zig
586
src/Module.zig
@ -386,11 +386,9 @@ pub const Decl = struct {
|
||||
/// do not need to be loaded into memory in order to compute debug line numbers.
|
||||
/// This value is absolute.
|
||||
src_line: u32,
|
||||
/// Index to ZIR `extra` array to the entry in the parent's decl structure
|
||||
/// (the part that says "for every decls_len"). The first item at this index is
|
||||
/// the contents hash, followed by line, name, etc.
|
||||
/// For anonymous decls and also the root Decl for a File, this is `none`.
|
||||
zir_decl_index: Zir.OptionalExtraIndex,
|
||||
/// Index of the ZIR `declaration` instruction from which this `Decl` was created.
|
||||
/// For the root `Decl` of a `File` and legacy anonymous decls, this is `.none`.
|
||||
zir_decl_index: Zir.Inst.OptionalIndex,
|
||||
|
||||
/// Represents the "shallow" analysis status. For example, for decls that are functions,
|
||||
/// the function type is analyzed with this set to `in_progress`, however, the semantic
|
||||
@ -442,10 +440,6 @@ pub const Decl = struct {
|
||||
is_pub: bool,
|
||||
/// Whether the corresponding AST decl has a `export` keyword.
|
||||
is_exported: bool,
|
||||
/// Whether the ZIR code provides an align instruction.
|
||||
has_align: bool,
|
||||
/// Whether the ZIR code provides a linksection and address space instruction.
|
||||
has_linksection_or_addrspace: bool,
|
||||
/// Flag used by garbage collection to mark and sweep.
|
||||
/// Decls which correspond to an AST node always have this field set to `true`.
|
||||
/// Anonymous Decls are initialized with this field set to `false` and then it
|
||||
@ -471,81 +465,19 @@ pub const Decl = struct {
|
||||
const Index = InternPool.DeclIndex;
|
||||
const OptionalIndex = InternPool.OptionalDeclIndex;
|
||||
|
||||
pub const DepsTable = std.AutoArrayHashMapUnmanaged(Decl.Index, DepType);
|
||||
|
||||
/// Later types take priority; e.g. if a dependent decl has both `normal`
|
||||
/// and `function_body` dependencies on another decl, it will be marked as
|
||||
/// having a `function_body` dependency.
|
||||
pub const DepType = enum {
|
||||
/// The dependent references or uses the dependency's value, so must be
|
||||
/// updated whenever it is changed. However, if the dependency is a
|
||||
/// function and its type is unchanged, the dependent does not need to
|
||||
/// be updated.
|
||||
normal,
|
||||
/// The dependent performs an inline or comptime call to the dependency,
|
||||
/// or is a generic instantiation of it. It must therefore be updated
|
||||
/// whenever the dependency is updated, even if the function type
|
||||
/// remained the same.
|
||||
function_body,
|
||||
};
|
||||
|
||||
/// This name is relative to the containing namespace of the decl.
|
||||
/// The memory is owned by the containing File ZIR.
|
||||
pub fn getName(decl: Decl, mod: *Module) ?[:0]const u8 {
|
||||
const zir = decl.getFileScope(mod).zir;
|
||||
return decl.getNameZir(zir);
|
||||
/// Asserts that `zir_decl_index` is not `.none`.
|
||||
fn getDeclaration(decl: Decl, zir: Zir) Zir.Inst.Declaration {
|
||||
const zir_index = decl.zir_decl_index.unwrap().?;
|
||||
const pl_node = zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
|
||||
return zir.extraData(Zir.Inst.Declaration, pl_node.payload_index).data;
|
||||
}
|
||||
|
||||
pub fn getNameZir(decl: Decl, zir: Zir) ?[:0]const u8 {
|
||||
assert(decl.zir_decl_index != .none);
|
||||
const name_index = zir.extra[@intFromEnum(decl.zir_decl_index) + 5];
|
||||
if (name_index <= 1) return null;
|
||||
return zir.nullTerminatedString(name_index);
|
||||
}
|
||||
|
||||
pub fn contentsHash(decl: Decl, mod: *Module) std.zig.SrcHash {
|
||||
const zir = decl.getFileScope(mod).zir;
|
||||
return decl.contentsHashZir(zir);
|
||||
}
|
||||
|
||||
pub fn contentsHashZir(decl: Decl, zir: Zir) std.zig.SrcHash {
|
||||
assert(decl.zir_decl_index != .none);
|
||||
const hash_u32s = zir.extra[@intFromEnum(decl.zir_decl_index)..][0..4];
|
||||
const contents_hash = @as(std.zig.SrcHash, @bitCast(hash_u32s.*));
|
||||
return contents_hash;
|
||||
}
|
||||
|
||||
pub fn zirBlockIndex(decl: *const Decl, mod: *Module) Zir.Inst.Index {
|
||||
assert(decl.zir_decl_index != .none);
|
||||
const zir = decl.getFileScope(mod).zir;
|
||||
return @enumFromInt(zir.extra[@intFromEnum(decl.zir_decl_index) + 6]);
|
||||
}
|
||||
|
||||
pub fn zirAlignRef(decl: Decl, mod: *Module) Zir.Inst.Ref {
|
||||
if (!decl.has_align) return .none;
|
||||
assert(decl.zir_decl_index != .none);
|
||||
const zir = decl.getFileScope(mod).zir;
|
||||
return @enumFromInt(zir.extra[@intFromEnum(decl.zir_decl_index) + 8]);
|
||||
}
|
||||
|
||||
pub fn zirLinksectionRef(decl: Decl, mod: *Module) Zir.Inst.Ref {
|
||||
if (!decl.has_linksection_or_addrspace) return .none;
|
||||
assert(decl.zir_decl_index != .none);
|
||||
const zir = decl.getFileScope(mod).zir;
|
||||
const extra_index = @intFromEnum(decl.zir_decl_index) + 8 + @intFromBool(decl.has_align);
|
||||
return @enumFromInt(zir.extra[extra_index]);
|
||||
}
|
||||
|
||||
pub fn zirAddrspaceRef(decl: Decl, mod: *Module) Zir.Inst.Ref {
|
||||
if (!decl.has_linksection_or_addrspace) return .none;
|
||||
assert(decl.zir_decl_index != .none);
|
||||
const zir = decl.getFileScope(mod).zir;
|
||||
const extra_index = @intFromEnum(decl.zir_decl_index) + 8 + @intFromBool(decl.has_align) + 1;
|
||||
return @enumFromInt(zir.extra[extra_index]);
|
||||
}
|
||||
|
||||
pub fn relativeToLine(decl: Decl, offset: u32) u32 {
|
||||
return decl.src_line + offset;
|
||||
pub fn zirBodies(decl: Decl, zcu: *Zcu) Zir.Inst.Declaration.Bodies {
|
||||
const zir = decl.getFileScope(zcu).zir;
|
||||
const zir_index = decl.zir_decl_index.unwrap().?;
|
||||
const pl_node = zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
|
||||
const extra = zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
|
||||
return extra.data.getBodies(@intCast(extra.end), zir);
|
||||
}
|
||||
|
||||
pub fn relativeToNodeIndex(decl: Decl, offset: i32) Ast.Node.Index {
|
||||
@ -902,6 +834,9 @@ pub const File = struct {
|
||||
multi_pkg: bool = false,
|
||||
/// List of references to this file, used for multi-package errors.
|
||||
references: std.ArrayListUnmanaged(Reference) = .{},
|
||||
/// The hash of the path to this file, used to store `InternPool.TrackedInst`.
|
||||
/// undefined until `zir_loaded == true`.
|
||||
path_digest: Cache.BinDigest = undefined,
|
||||
|
||||
/// Used by change detection algorithm, after astgen, contains the
|
||||
/// set of decls that existed in the previous ZIR but not in the new one.
|
||||
@ -2662,7 +2597,7 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
|
||||
const stat = try source_file.stat();
|
||||
|
||||
const want_local_cache = file.mod == mod.main_mod;
|
||||
const digest = hash: {
|
||||
const bin_digest = hash: {
|
||||
var path_hash: Cache.HashHelper = .{};
|
||||
path_hash.addBytes(build_options.version);
|
||||
path_hash.add(builtin.zig_backend);
|
||||
@ -2671,7 +2606,19 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
|
||||
path_hash.addBytes(file.mod.root.sub_path);
|
||||
}
|
||||
path_hash.addBytes(file.sub_file_path);
|
||||
break :hash path_hash.final();
|
||||
var bin: Cache.BinDigest = undefined;
|
||||
path_hash.hasher.final(&bin);
|
||||
break :hash bin;
|
||||
};
|
||||
file.path_digest = bin_digest;
|
||||
const hex_digest = hex: {
|
||||
var hex: Cache.HexDigest = undefined;
|
||||
_ = std.fmt.bufPrint(
|
||||
&hex,
|
||||
"{s}",
|
||||
.{std.fmt.fmtSliceHexLower(&bin_digest)},
|
||||
) catch unreachable;
|
||||
break :hex hex;
|
||||
};
|
||||
const cache_directory = if (want_local_cache) mod.local_zir_cache else mod.global_zir_cache;
|
||||
const zir_dir = cache_directory.handle;
|
||||
@ -2681,7 +2628,7 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
|
||||
.never_loaded, .retryable_failure => lock: {
|
||||
// First, load the cached ZIR code, if any.
|
||||
log.debug("AstGen checking cache: {s} (local={}, digest={s})", .{
|
||||
file.sub_file_path, want_local_cache, &digest,
|
||||
file.sub_file_path, want_local_cache, &hex_digest,
|
||||
});
|
||||
|
||||
break :lock .shared;
|
||||
@ -2708,7 +2655,7 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
|
||||
// version. Likewise if we're working on AstGen and another process asks for
|
||||
// the cached file, they'll get it.
|
||||
const cache_file = while (true) {
|
||||
break zir_dir.createFile(&digest, .{
|
||||
break zir_dir.createFile(&hex_digest, .{
|
||||
.read = true,
|
||||
.truncate = false,
|
||||
.lock = lock,
|
||||
@ -2894,7 +2841,7 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
|
||||
};
|
||||
cache_file.writevAll(&iovecs) catch |err| {
|
||||
log.warn("unable to write cached ZIR code for {}{s} to {}{s}: {s}", .{
|
||||
file.mod.root, file.sub_file_path, cache_directory, &digest, @errorName(err),
|
||||
file.mod.root, file.sub_file_path, cache_directory, &hex_digest, @errorName(err),
|
||||
});
|
||||
};
|
||||
|
||||
@ -3003,93 +2950,22 @@ fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_file: std.fs.File)
|
||||
return zir;
|
||||
}
|
||||
|
||||
/// Patch ups:
|
||||
/// * Struct.zir_index
|
||||
/// * Decl.zir_index
|
||||
/// * Fn.zir_body_inst
|
||||
/// * Decl.zir_decl_index
|
||||
fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void {
|
||||
const gpa = mod.gpa;
|
||||
const new_zir = file.zir;
|
||||
fn updateZirRefs(zcu: *Module, file: *File, old_zir: Zir) !void {
|
||||
const gpa = zcu.gpa;
|
||||
|
||||
// The root decl will be null if the previous ZIR had AST errors.
|
||||
const root_decl = file.root_decl.unwrap() orelse return;
|
||||
|
||||
// Maps from old ZIR to new ZIR, struct_decl, enum_decl, etc. Any instruction which
|
||||
// creates a namespace, gets mapped from old to new here.
|
||||
var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{};
|
||||
defer inst_map.deinit(gpa);
|
||||
// Maps from old ZIR to new ZIR, the extra data index for the sub-decl item.
|
||||
// e.g. the thing that Decl.zir_decl_index points to.
|
||||
var extra_map: std.AutoHashMapUnmanaged(Zir.ExtraIndex, Zir.ExtraIndex) = .{};
|
||||
defer extra_map.deinit(gpa);
|
||||
|
||||
try mapOldZirToNew(gpa, old_zir, new_zir, &inst_map, &extra_map);
|
||||
try mapOldZirToNew(gpa, old_zir, file.zir, &inst_map);
|
||||
|
||||
// Walk the Decl graph, updating ZIR indexes, strings, and populating
|
||||
// the deleted and outdated lists.
|
||||
|
||||
var decl_stack: ArrayListUnmanaged(Decl.Index) = .{};
|
||||
defer decl_stack.deinit(gpa);
|
||||
|
||||
try decl_stack.append(gpa, root_decl);
|
||||
|
||||
file.deleted_decls.clearRetainingCapacity();
|
||||
file.outdated_decls.clearRetainingCapacity();
|
||||
|
||||
// The root decl is always outdated; otherwise we would not have had
|
||||
// to re-generate ZIR for the File.
|
||||
try file.outdated_decls.append(gpa, root_decl);
|
||||
|
||||
const ip = &mod.intern_pool;
|
||||
|
||||
while (decl_stack.popOrNull()) |decl_index| {
|
||||
const decl = mod.declPtr(decl_index);
|
||||
// Anonymous decls and the root decl have this set to 0. We still need
|
||||
// to walk them but we do not need to modify this value.
|
||||
// Anonymous decls should not be marked outdated. They will be re-generated
|
||||
// if their owner decl is marked outdated.
|
||||
if (decl.zir_decl_index.unwrap()) |old_zir_decl_index| {
|
||||
const new_zir_decl_index = extra_map.get(old_zir_decl_index) orelse {
|
||||
try file.deleted_decls.append(gpa, decl_index);
|
||||
continue;
|
||||
};
|
||||
const old_hash = decl.contentsHashZir(old_zir);
|
||||
decl.zir_decl_index = new_zir_decl_index.toOptional();
|
||||
const new_hash = decl.contentsHashZir(new_zir);
|
||||
if (!std.zig.srcHashEql(old_hash, new_hash)) {
|
||||
try file.outdated_decls.append(gpa, decl_index);
|
||||
}
|
||||
}
|
||||
|
||||
if (!decl.owns_tv) continue;
|
||||
|
||||
if (decl.getOwnedStruct(mod)) |struct_type| {
|
||||
struct_type.setZirIndex(ip, inst_map.get(struct_type.zir_index) orelse {
|
||||
try file.deleted_decls.append(gpa, decl_index);
|
||||
continue;
|
||||
});
|
||||
}
|
||||
|
||||
if (decl.getOwnedUnion(mod)) |union_type| {
|
||||
union_type.setZirIndex(ip, inst_map.get(union_type.zir_index) orelse {
|
||||
try file.deleted_decls.append(gpa, decl_index);
|
||||
continue;
|
||||
});
|
||||
}
|
||||
|
||||
if (decl.getOwnedFunction(mod)) |func| {
|
||||
func.zirBodyInst(ip).* = inst_map.get(func.zir_body_inst) orelse {
|
||||
try file.deleted_decls.append(gpa, decl_index);
|
||||
continue;
|
||||
};
|
||||
}
|
||||
|
||||
if (decl.getOwnedInnerNamespace(mod)) |namespace| {
|
||||
for (namespace.decls.keys()) |sub_decl| {
|
||||
try decl_stack.append(gpa, sub_decl);
|
||||
}
|
||||
}
|
||||
// TODO: this should be done after all AstGen workers complete, to avoid
|
||||
// iterating over this full set for every updated file.
|
||||
for (zcu.intern_pool.tracked_insts.keys()) |*ti| {
|
||||
if (!std.mem.eql(u8, &ti.path_digest, &file.path_digest)) continue;
|
||||
ti.inst = inst_map.get(ti.inst) orelse {
|
||||
// TODO: invalidate this `TrackedInst` via the dependency mechanism
|
||||
continue;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -3098,9 +2974,9 @@ pub fn mapOldZirToNew(
|
||||
old_zir: Zir,
|
||||
new_zir: Zir,
|
||||
inst_map: *std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index),
|
||||
extra_map: *std.AutoHashMapUnmanaged(Zir.ExtraIndex, Zir.ExtraIndex),
|
||||
) Allocator.Error!void {
|
||||
// Contain ZIR indexes of declaration instructions.
|
||||
// Contain ZIR indexes of namespace declaration instructions, e.g. struct_decl, union_decl, etc.
|
||||
// Not `declaration`, as this does not create a namespace.
|
||||
const MatchedZirDecl = struct {
|
||||
old_inst: Zir.Inst.Index,
|
||||
new_inst: Zir.Inst.Index,
|
||||
@ -3108,47 +2984,113 @@ pub fn mapOldZirToNew(
|
||||
var match_stack: ArrayListUnmanaged(MatchedZirDecl) = .{};
|
||||
defer match_stack.deinit(gpa);
|
||||
|
||||
// Main struct inst is always the same
|
||||
// Main struct inst is always matched
|
||||
try match_stack.append(gpa, .{
|
||||
.old_inst = .main_struct_inst,
|
||||
.new_inst = .main_struct_inst,
|
||||
});
|
||||
|
||||
// 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();
|
||||
|
||||
while (match_stack.popOrNull()) |match_item| {
|
||||
// Match the namespace declaration itself
|
||||
try inst_map.put(gpa, match_item.old_inst, match_item.new_inst);
|
||||
|
||||
// Maps name to extra index of decl sub item.
|
||||
var decl_map: std.StringHashMapUnmanaged(Zir.ExtraIndex) = .{};
|
||||
defer decl_map.deinit(gpa);
|
||||
// Maps decl name to `declaration` instruction.
|
||||
var named_decls: std.StringHashMapUnmanaged(Zir.Inst.Index) = .{};
|
||||
defer named_decls.deinit(gpa);
|
||||
// Maps test name to `declaration` instruction.
|
||||
var named_tests: std.StringHashMapUnmanaged(Zir.Inst.Index) = .{};
|
||||
defer named_tests.deinit(gpa);
|
||||
// All unnamed tests, in order, for a best-effort match.
|
||||
var unnamed_tests: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
|
||||
defer unnamed_tests.deinit(gpa);
|
||||
// All comptime declarations, in order, for a best-effort match.
|
||||
var comptime_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
|
||||
defer comptime_decls.deinit(gpa);
|
||||
// All usingnamespace declarations, in order, for a best-effort match.
|
||||
var usingnamespace_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
|
||||
defer usingnamespace_decls.deinit(gpa);
|
||||
|
||||
{
|
||||
var old_decl_it = old_zir.declIterator(match_item.old_inst);
|
||||
while (old_decl_it.next()) |old_decl| {
|
||||
try decl_map.put(gpa, old_decl.name, old_decl.sub_index);
|
||||
while (old_decl_it.next()) |old_decl_inst| {
|
||||
const old_decl, _ = old_zir.getDeclaration(old_decl_inst);
|
||||
switch (old_decl.name) {
|
||||
.@"comptime" => try comptime_decls.append(gpa, old_decl_inst),
|
||||
.@"usingnamespace" => try usingnamespace_decls.append(gpa, old_decl_inst),
|
||||
.unnamed_test, .decltest => try unnamed_tests.append(gpa, old_decl_inst),
|
||||
_ => {
|
||||
const name_nts = old_decl.name.toString(old_zir).?;
|
||||
const name = old_zir.nullTerminatedString(name_nts);
|
||||
if (old_decl.name.isNamedTest(old_zir)) {
|
||||
try named_tests.put(gpa, name, old_decl_inst);
|
||||
} else {
|
||||
try named_decls.put(gpa, name, old_decl_inst);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var new_decl_it = new_zir.declIterator(match_item.new_inst);
|
||||
while (new_decl_it.next()) |new_decl| {
|
||||
const old_extra_index = decl_map.get(new_decl.name) orelse continue;
|
||||
const new_extra_index = new_decl.sub_index;
|
||||
try extra_map.put(gpa, old_extra_index, new_extra_index);
|
||||
var unnamed_test_idx: u32 = 0;
|
||||
var comptime_decl_idx: u32 = 0;
|
||||
var usingnamespace_decl_idx: u32 = 0;
|
||||
|
||||
try old_zir.findDecls(&old_decls, old_extra_index);
|
||||
try new_zir.findDecls(&new_decls, new_extra_index);
|
||||
var i: usize = 0;
|
||||
while (true) : (i += 1) {
|
||||
if (i >= old_decls.items.len) break;
|
||||
if (i >= new_decls.items.len) break;
|
||||
try match_stack.append(gpa, .{
|
||||
.old_inst = old_decls.items[i],
|
||||
.new_inst = new_decls.items[i],
|
||||
});
|
||||
var new_decl_it = new_zir.declIterator(match_item.new_inst);
|
||||
while (new_decl_it.next()) |new_decl_inst| {
|
||||
const new_decl, _ = new_zir.getDeclaration(new_decl_inst);
|
||||
// Attempt to match this to a declaration in the old ZIR:
|
||||
// * For named declarations (`const`/`var`/`fn`), we match based on name.
|
||||
// * For named tests (`test "foo"`), we also match based on name.
|
||||
// * For unnamed tests and decltests, we match based on order.
|
||||
// * For comptime blocks, we match based on order.
|
||||
// * For usingnamespace decls, we match based on order.
|
||||
// If we cannot match this declaration, we can't match anything nested inside of it either, so we just `continue`.
|
||||
const old_decl_inst = switch (new_decl.name) {
|
||||
.@"comptime" => inst: {
|
||||
if (comptime_decl_idx == comptime_decls.items.len) continue;
|
||||
defer comptime_decl_idx += 1;
|
||||
break :inst comptime_decls.items[comptime_decl_idx];
|
||||
},
|
||||
.@"usingnamespace" => inst: {
|
||||
if (usingnamespace_decl_idx == usingnamespace_decls.items.len) continue;
|
||||
defer usingnamespace_decl_idx += 1;
|
||||
break :inst usingnamespace_decls.items[usingnamespace_decl_idx];
|
||||
},
|
||||
.unnamed_test, .decltest => inst: {
|
||||
if (unnamed_test_idx == unnamed_tests.items.len) continue;
|
||||
defer unnamed_test_idx += 1;
|
||||
break :inst unnamed_tests.items[unnamed_test_idx];
|
||||
},
|
||||
_ => inst: {
|
||||
const name_nts = new_decl.name.toString(old_zir).?;
|
||||
const name = new_zir.nullTerminatedString(name_nts);
|
||||
if (new_decl.name.isNamedTest(new_zir)) {
|
||||
break :inst named_tests.get(name) orelse continue;
|
||||
} else {
|
||||
break :inst named_decls.get(name) orelse continue;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// 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);
|
||||
|
||||
// We don't have any smart way of matching up these namespace 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| {
|
||||
match_stack.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3457,8 +3399,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
|
||||
new_decl.src_line = 0;
|
||||
new_decl.is_pub = true;
|
||||
new_decl.is_exported = false;
|
||||
new_decl.has_align = false;
|
||||
new_decl.has_linksection_or_addrspace = false;
|
||||
new_decl.ty = Type.type;
|
||||
new_decl.alignment = .none;
|
||||
new_decl.@"linksection" = .none;
|
||||
@ -3502,7 +3442,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
|
||||
const struct_ty = sema.getStructType(
|
||||
new_decl_index,
|
||||
new_namespace_index,
|
||||
.main_struct_inst,
|
||||
try mod.intern_pool.trackZir(gpa, file, .main_struct_inst),
|
||||
) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
};
|
||||
@ -3561,7 +3501,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
|
||||
|
||||
const gpa = mod.gpa;
|
||||
const zir = decl.getFileScope(mod).zir;
|
||||
const zir_datas = zir.instructions.items(.data);
|
||||
|
||||
const builtin_type_target_index: InternPool.Index = blk: {
|
||||
const std_mod = mod.std_mod;
|
||||
@ -3639,11 +3578,9 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
|
||||
};
|
||||
defer block_scope.instructions.deinit(gpa);
|
||||
|
||||
const zir_block_index = decl.zirBlockIndex(mod);
|
||||
const inst_data = zir_datas[@intFromEnum(zir_block_index)].pl_node;
|
||||
const extra = zir.extraData(Zir.Inst.Block, inst_data.payload_index);
|
||||
const body = zir.extra[extra.end..][0..extra.data.body_len];
|
||||
const result_ref = (try sema.analyzeBodyBreak(&block_scope, @ptrCast(body))).?.operand;
|
||||
const decl_bodies = decl.zirBodies(mod);
|
||||
|
||||
const result_ref = (try sema.analyzeBodyBreak(&block_scope, decl_bodies.value_body)).?.operand;
|
||||
// We'll do some other bits with the Sema. Clear the type target index just
|
||||
// in case they analyze any type.
|
||||
sema.builtin_type_target_index = .none;
|
||||
@ -3760,13 +3697,13 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
|
||||
decl.ty = decl_tv.ty;
|
||||
decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod)));
|
||||
decl.alignment = blk: {
|
||||
const align_ref = decl.zirAlignRef(mod);
|
||||
if (align_ref == .none) break :blk .none;
|
||||
const align_body = decl_bodies.align_body orelse break :blk .none;
|
||||
const align_ref = (try sema.analyzeBodyBreak(&block_scope, align_body)).?.operand;
|
||||
break :blk try sema.resolveAlign(&block_scope, align_src, align_ref);
|
||||
};
|
||||
decl.@"linksection" = blk: {
|
||||
const linksection_ref = decl.zirLinksectionRef(mod);
|
||||
if (linksection_ref == .none) break :blk .none;
|
||||
const linksection_body = decl_bodies.linksection_body orelse break :blk .none;
|
||||
const linksection_ref = (try sema.analyzeBodyBreak(&block_scope, linksection_body)).?.operand;
|
||||
const bytes = try sema.resolveConstString(&block_scope, section_src, linksection_ref, .{
|
||||
.needed_comptime_reason = "linksection must be comptime-known",
|
||||
});
|
||||
@ -3786,15 +3723,15 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
|
||||
};
|
||||
|
||||
const target = sema.mod.getTarget();
|
||||
break :blk switch (decl.zirAddrspaceRef(mod)) {
|
||||
.none => switch (addrspace_ctx) {
|
||||
.function => target_util.defaultAddressSpace(target, .function),
|
||||
.variable => target_util.defaultAddressSpace(target, .global_mutable),
|
||||
.constant => target_util.defaultAddressSpace(target, .global_constant),
|
||||
else => unreachable,
|
||||
},
|
||||
else => |addrspace_ref| try sema.analyzeAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx),
|
||||
|
||||
const addrspace_body = decl_bodies.addrspace_body orelse break :blk switch (addrspace_ctx) {
|
||||
.function => target_util.defaultAddressSpace(target, .function),
|
||||
.variable => target_util.defaultAddressSpace(target, .global_mutable),
|
||||
.constant => target_util.defaultAddressSpace(target, .global_constant),
|
||||
else => unreachable,
|
||||
};
|
||||
const addrspace_ref = (try sema.analyzeBodyBreak(&block_scope, addrspace_body)).?.operand;
|
||||
break :blk try sema.analyzeAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx);
|
||||
};
|
||||
decl.has_tv = true;
|
||||
decl.analysis = .complete;
|
||||
@ -4133,52 +4070,32 @@ fn newEmbedFile(
|
||||
}
|
||||
|
||||
pub fn scanNamespace(
|
||||
mod: *Module,
|
||||
zcu: *Zcu,
|
||||
namespace_index: Namespace.Index,
|
||||
extra_start: usize,
|
||||
decls_len: u32,
|
||||
decls: []const Zir.Inst.Index,
|
||||
parent_decl: *Decl,
|
||||
) Allocator.Error!usize {
|
||||
) Allocator.Error!void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const gpa = mod.gpa;
|
||||
const namespace = mod.namespacePtr(namespace_index);
|
||||
const zir = namespace.file_scope.zir;
|
||||
const gpa = zcu.gpa;
|
||||
const namespace = zcu.namespacePtr(namespace_index);
|
||||
|
||||
try mod.comp.work_queue.ensureUnusedCapacity(decls_len);
|
||||
try namespace.decls.ensureTotalCapacity(gpa, decls_len);
|
||||
try zcu.comp.work_queue.ensureUnusedCapacity(decls.len);
|
||||
try namespace.decls.ensureTotalCapacity(gpa, decls.len);
|
||||
|
||||
const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable;
|
||||
var extra_index = extra_start + bit_bags_count;
|
||||
var bit_bag_index: usize = extra_start;
|
||||
var cur_bit_bag: u32 = undefined;
|
||||
var decl_i: u32 = 0;
|
||||
var scan_decl_iter: ScanDeclIter = .{
|
||||
.module = mod,
|
||||
.zcu = zcu,
|
||||
.namespace_index = namespace_index,
|
||||
.parent_decl = parent_decl,
|
||||
};
|
||||
while (decl_i < decls_len) : (decl_i += 1) {
|
||||
if (decl_i % 8 == 0) {
|
||||
cur_bit_bag = zir.extra[bit_bag_index];
|
||||
bit_bag_index += 1;
|
||||
}
|
||||
const flags = @as(u4, @truncate(cur_bit_bag));
|
||||
cur_bit_bag >>= 4;
|
||||
|
||||
const decl_sub_index = extra_index;
|
||||
extra_index += 8; // src_hash(4) + line(1) + name(1) + value(1) + doc_comment(1)
|
||||
extra_index += @as(u1, @truncate(flags >> 2)); // Align
|
||||
extra_index += @as(u2, @as(u1, @truncate(flags >> 3))) * 2; // Link section or address space, consists of 2 Refs
|
||||
|
||||
try scanDecl(&scan_decl_iter, decl_sub_index, flags);
|
||||
for (decls) |decl_inst| {
|
||||
try scanDecl(&scan_decl_iter, decl_inst);
|
||||
}
|
||||
return extra_index;
|
||||
}
|
||||
|
||||
const ScanDeclIter = struct {
|
||||
module: *Module,
|
||||
zcu: *Zcu,
|
||||
namespace_index: Namespace.Index,
|
||||
parent_decl: *Decl,
|
||||
usingnamespace_index: usize = 0,
|
||||
@ -4186,119 +4103,112 @@ const ScanDeclIter = struct {
|
||||
unnamed_test_index: usize = 0,
|
||||
};
|
||||
|
||||
fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Error!void {
|
||||
fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const mod = iter.module;
|
||||
const zcu = iter.zcu;
|
||||
const namespace_index = iter.namespace_index;
|
||||
const namespace = mod.namespacePtr(namespace_index);
|
||||
const gpa = mod.gpa;
|
||||
const namespace = zcu.namespacePtr(namespace_index);
|
||||
const gpa = zcu.gpa;
|
||||
const zir = namespace.file_scope.zir;
|
||||
const ip = &mod.intern_pool;
|
||||
const ip = &zcu.intern_pool;
|
||||
|
||||
// zig fmt: off
|
||||
const is_pub = (flags & 0b0001) != 0;
|
||||
const export_bit = (flags & 0b0010) != 0;
|
||||
const has_align = (flags & 0b0100) != 0;
|
||||
const has_linksection_or_addrspace = (flags & 0b1000) != 0;
|
||||
// zig fmt: on
|
||||
const pl_node = zir.instructions.items(.data)[@intFromEnum(decl_inst)].pl_node;
|
||||
const extra = zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
|
||||
const declaration = extra.data;
|
||||
|
||||
const line_off = zir.extra[decl_sub_index + 4];
|
||||
const line = iter.parent_decl.relativeToLine(line_off);
|
||||
const decl_name_index: Zir.NullTerminatedString = @enumFromInt(zir.extra[decl_sub_index + 5]);
|
||||
const decl_doccomment_index = zir.extra[decl_sub_index + 7];
|
||||
const decl_zir_index = zir.extra[decl_sub_index + 6];
|
||||
const decl_block_inst_data = zir.instructions.items(.data)[decl_zir_index].pl_node;
|
||||
const decl_node = iter.parent_decl.relativeToNodeIndex(decl_block_inst_data.src_node);
|
||||
const line = iter.parent_decl.src_line + declaration.line_offset;
|
||||
const decl_node = iter.parent_decl.relativeToNodeIndex(pl_node.src_node);
|
||||
|
||||
// Every Decl needs a name.
|
||||
var is_named_test = false;
|
||||
var kind: Decl.Kind = .named;
|
||||
const decl_name: InternPool.NullTerminatedString = switch (decl_name_index) {
|
||||
.empty => name: {
|
||||
if (export_bit) {
|
||||
const i = iter.usingnamespace_index;
|
||||
iter.usingnamespace_index += 1;
|
||||
kind = .@"usingnamespace";
|
||||
break :name try ip.getOrPutStringFmt(gpa, "usingnamespace_{d}", .{i});
|
||||
} else {
|
||||
const i = iter.comptime_index;
|
||||
iter.comptime_index += 1;
|
||||
kind = .@"comptime";
|
||||
break :name try ip.getOrPutStringFmt(gpa, "comptime_{d}", .{i});
|
||||
}
|
||||
const decl_name: InternPool.NullTerminatedString, const kind: Decl.Kind, const is_named_test: bool = switch (declaration.name) {
|
||||
.@"comptime" => info: {
|
||||
const i = iter.comptime_index;
|
||||
iter.comptime_index += 1;
|
||||
break :info .{
|
||||
try ip.getOrPutStringFmt(gpa, "comptime_{d}", .{i}),
|
||||
.@"comptime",
|
||||
false,
|
||||
};
|
||||
},
|
||||
.unnamed_test_decl => name: {
|
||||
.@"usingnamespace" => info: {
|
||||
const i = iter.usingnamespace_index;
|
||||
iter.usingnamespace_index += 1;
|
||||
break :info .{
|
||||
try ip.getOrPutStringFmt(gpa, "usingnamespace_{d}", .{i}),
|
||||
.@"usingnamespace",
|
||||
false,
|
||||
};
|
||||
},
|
||||
.unnamed_test => info: {
|
||||
const i = iter.unnamed_test_index;
|
||||
iter.unnamed_test_index += 1;
|
||||
kind = .@"test";
|
||||
break :name try ip.getOrPutStringFmt(gpa, "test_{d}", .{i});
|
||||
break :info .{
|
||||
try ip.getOrPutStringFmt(gpa, "test_{d}", .{i}),
|
||||
.@"test",
|
||||
false,
|
||||
};
|
||||
},
|
||||
.decltest => name: {
|
||||
is_named_test = true;
|
||||
const test_name = zir.nullTerminatedString(@enumFromInt(decl_doccomment_index));
|
||||
kind = .@"test";
|
||||
break :name try ip.getOrPutStringFmt(gpa, "decltest.{s}", .{test_name});
|
||||
.decltest => info: {
|
||||
assert(declaration.flags.has_doc_comment);
|
||||
const name = zir.nullTerminatedString(@enumFromInt(zir.extra[extra.end]));
|
||||
break :info .{
|
||||
try ip.getOrPutStringFmt(gpa, "decltest.{s}", .{name}),
|
||||
.@"test",
|
||||
true,
|
||||
};
|
||||
},
|
||||
_ => name: {
|
||||
const raw_name = zir.nullTerminatedString(decl_name_index);
|
||||
if (raw_name.len == 0) {
|
||||
is_named_test = true;
|
||||
const test_name = zir.nullTerminatedString(@enumFromInt(@intFromEnum(decl_name_index) + 1));
|
||||
kind = .@"test";
|
||||
break :name try ip.getOrPutStringFmt(gpa, "test.{s}", .{test_name});
|
||||
} else {
|
||||
break :name try ip.getOrPutString(gpa, raw_name);
|
||||
}
|
||||
_ => if (declaration.name.isNamedTest(zir)) .{
|
||||
try ip.getOrPutStringFmt(gpa, "test.{s}", .{zir.nullTerminatedString(declaration.name.toString(zir).?)}),
|
||||
.@"test",
|
||||
true,
|
||||
} else .{
|
||||
try ip.getOrPutString(gpa, zir.nullTerminatedString(declaration.name.toString(zir).?)),
|
||||
.named,
|
||||
false,
|
||||
},
|
||||
};
|
||||
|
||||
const is_exported = export_bit and decl_name_index != .empty;
|
||||
if (kind == .@"usingnamespace") try namespace.usingnamespace_set.ensureUnusedCapacity(gpa, 1);
|
||||
|
||||
// We create a Decl for it regardless of analysis status.
|
||||
const gop = try namespace.decls.getOrPutContextAdapted(
|
||||
gpa,
|
||||
decl_name,
|
||||
DeclAdapter{ .mod = mod },
|
||||
Namespace.DeclContext{ .module = mod },
|
||||
DeclAdapter{ .mod = zcu },
|
||||
Namespace.DeclContext{ .module = zcu },
|
||||
);
|
||||
const comp = mod.comp;
|
||||
const comp = zcu.comp;
|
||||
if (!gop.found_existing) {
|
||||
const new_decl_index = try mod.allocateNewDecl(namespace_index, decl_node, iter.parent_decl.src_scope);
|
||||
const new_decl = mod.declPtr(new_decl_index);
|
||||
const new_decl_index = try zcu.allocateNewDecl(namespace_index, decl_node, iter.parent_decl.src_scope);
|
||||
const new_decl = zcu.declPtr(new_decl_index);
|
||||
new_decl.kind = kind;
|
||||
new_decl.name = decl_name;
|
||||
if (kind == .@"usingnamespace") {
|
||||
namespace.usingnamespace_set.putAssumeCapacity(new_decl_index, is_pub);
|
||||
namespace.usingnamespace_set.putAssumeCapacity(new_decl_index, declaration.flags.is_pub);
|
||||
}
|
||||
new_decl.src_line = line;
|
||||
gop.key_ptr.* = new_decl_index;
|
||||
// Exported decls, comptime decls, usingnamespace decls, and
|
||||
// test decls if in test mode, get analyzed.
|
||||
const decl_mod = namespace.file_scope.mod;
|
||||
const want_analysis = is_exported or switch (decl_name_index) {
|
||||
.empty => true, // comptime or usingnamespace decl
|
||||
.unnamed_test_decl => blk: {
|
||||
// test decl with no name. Skip the part where we check against
|
||||
// the test name filter.
|
||||
if (!comp.config.is_test) break :blk false;
|
||||
if (decl_mod != mod.main_mod) break :blk false;
|
||||
try mod.test_functions.put(gpa, new_decl_index, {});
|
||||
break :blk true;
|
||||
},
|
||||
else => blk: {
|
||||
if (!is_named_test) break :blk false;
|
||||
if (!comp.config.is_test) break :blk false;
|
||||
if (decl_mod != mod.main_mod) break :blk false;
|
||||
if (comp.test_filter) |test_filter| {
|
||||
if (mem.indexOf(u8, ip.stringToSlice(decl_name), test_filter) == null) {
|
||||
break :blk false;
|
||||
const want_analysis = declaration.flags.is_export or switch (kind) {
|
||||
.anon => unreachable,
|
||||
.@"comptime", .@"usingnamespace" => true,
|
||||
.named => false,
|
||||
.@"test" => a: {
|
||||
if (!comp.config.is_test) break :a false;
|
||||
if (decl_mod != zcu.main_mod) break :a false;
|
||||
if (is_named_test) {
|
||||
if (comp.test_filter) |test_filter| {
|
||||
if (mem.indexOf(u8, ip.stringToSlice(decl_name), test_filter) == null) {
|
||||
break :a false;
|
||||
}
|
||||
}
|
||||
}
|
||||
try mod.test_functions.put(gpa, new_decl_index, {});
|
||||
break :blk true;
|
||||
try zcu.test_functions.put(gpa, new_decl_index, {});
|
||||
break :a true;
|
||||
},
|
||||
};
|
||||
if (want_analysis) {
|
||||
@ -4307,46 +4217,42 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err
|
||||
});
|
||||
comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl_index });
|
||||
}
|
||||
new_decl.is_pub = is_pub;
|
||||
new_decl.is_exported = is_exported;
|
||||
new_decl.has_align = has_align;
|
||||
new_decl.has_linksection_or_addrspace = has_linksection_or_addrspace;
|
||||
new_decl.zir_decl_index = @enumFromInt(decl_sub_index);
|
||||
new_decl.is_pub = declaration.flags.is_pub;
|
||||
new_decl.is_exported = declaration.flags.is_export;
|
||||
new_decl.zir_decl_index = decl_inst.toOptional();
|
||||
new_decl.alive = true; // This Decl corresponds to an AST node and therefore always alive.
|
||||
return;
|
||||
}
|
||||
const decl_index = gop.key_ptr.*;
|
||||
const decl = mod.declPtr(decl_index);
|
||||
const decl = zcu.declPtr(decl_index);
|
||||
if (kind == .@"test") {
|
||||
const src_loc = SrcLoc{
|
||||
.file_scope = decl.getFileScope(mod),
|
||||
.file_scope = decl.getFileScope(zcu),
|
||||
.parent_decl_node = decl.src_node,
|
||||
.lazy = .{ .token_offset = 1 },
|
||||
};
|
||||
const msg = try ErrorMsg.create(gpa, src_loc, "duplicate test name: {}", .{
|
||||
decl_name.fmt(&mod.intern_pool),
|
||||
decl_name.fmt(ip),
|
||||
});
|
||||
errdefer msg.destroy(gpa);
|
||||
try mod.failed_decls.putNoClobber(gpa, decl_index, msg);
|
||||
try zcu.failed_decls.putNoClobber(gpa, decl_index, msg);
|
||||
const other_src_loc = SrcLoc{
|
||||
.file_scope = namespace.file_scope,
|
||||
.parent_decl_node = decl_node,
|
||||
.lazy = .{ .token_offset = 1 },
|
||||
};
|
||||
try mod.errNoteNonLazy(other_src_loc, msg, "other test here", .{});
|
||||
try zcu.errNoteNonLazy(other_src_loc, msg, "other test here", .{});
|
||||
}
|
||||
// Update the AST node of the decl; even if its contents are unchanged, it may
|
||||
// have been re-ordered.
|
||||
decl.src_node = decl_node;
|
||||
decl.src_line = line;
|
||||
|
||||
decl.is_pub = is_pub;
|
||||
decl.is_exported = is_exported;
|
||||
decl.is_pub = declaration.flags.is_pub;
|
||||
decl.is_exported = declaration.flags.is_export;
|
||||
decl.kind = kind;
|
||||
decl.has_align = has_align;
|
||||
decl.has_linksection_or_addrspace = has_linksection_or_addrspace;
|
||||
decl.zir_decl_index = @enumFromInt(decl_sub_index);
|
||||
if (decl.getOwnedFunction(mod) != null) {
|
||||
decl.zir_decl_index = decl_inst.toOptional();
|
||||
if (decl.getOwnedFunction(zcu) != null) {
|
||||
// TODO Look into detecting when this would be unnecessary by storing enough state
|
||||
// in `Decl` to notice that the line number did not change.
|
||||
comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index });
|
||||
@ -4514,7 +4420,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
|
||||
};
|
||||
defer inner_block.instructions.deinit(gpa);
|
||||
|
||||
const fn_info = sema.code.getFnInfo(func.zirBodyInst(ip).*);
|
||||
const fn_info = sema.code.getFnInfo(func.zirBodyInst(ip).resolve(ip));
|
||||
|
||||
// Here we are performing "runtime semantic analysis" for a function body, which means
|
||||
// we must map the parameter ZIR instructions to `arg` AIR instructions.
|
||||
@ -4730,8 +4636,6 @@ pub fn allocateNewDecl(
|
||||
.generation = 0,
|
||||
.is_pub = false,
|
||||
.is_exported = false,
|
||||
.has_linksection_or_addrspace = false,
|
||||
.has_align = false,
|
||||
.alive = false,
|
||||
.kind = .anon,
|
||||
});
|
||||
@ -6169,7 +6073,7 @@ pub fn getParamName(mod: *Module, func_index: InternPool.Index, index: u32) [:0]
|
||||
const tags = file.zir.instructions.items(.tag);
|
||||
const data = file.zir.instructions.items(.data);
|
||||
|
||||
const param_body = file.zir.getParamBody(func.zir_body_inst);
|
||||
const param_body = file.zir.getParamBody(func.zir_body_inst.resolve(&mod.intern_pool));
|
||||
const param = param_body[index];
|
||||
|
||||
return switch (tags[@intFromEnum(param)]) {
|
||||
|
||||
70
src/Sema.zig
70
src/Sema.zig
@ -1224,6 +1224,10 @@ fn analyzeBodyInner(
|
||||
.trap => break sema.zirTrap(block, inst),
|
||||
// zig fmt: on
|
||||
|
||||
// This instruction never exists in an analyzed body. It exists only in the declaration
|
||||
// list for a container type.
|
||||
.declaration => unreachable,
|
||||
|
||||
.extended => ext: {
|
||||
const extended = datas[@intFromEnum(inst)].extended;
|
||||
break :ext switch (extended.opcode) {
|
||||
@ -2704,11 +2708,12 @@ pub fn getStructType(
|
||||
sema: *Sema,
|
||||
decl: InternPool.DeclIndex,
|
||||
namespace: InternPool.NamespaceIndex,
|
||||
zir_index: Zir.Inst.Index,
|
||||
tracked_inst: InternPool.TrackedInst.Index,
|
||||
) !InternPool.Index {
|
||||
const mod = sema.mod;
|
||||
const gpa = sema.gpa;
|
||||
const ip = &mod.intern_pool;
|
||||
const zir_index = tracked_inst.resolve(ip);
|
||||
const extended = sema.code.instructions.items(.data)[@intFromEnum(zir_index)].extended;
|
||||
assert(extended.opcode == .struct_decl);
|
||||
const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
|
||||
@ -2736,12 +2741,14 @@ pub fn getStructType(
|
||||
}
|
||||
}
|
||||
|
||||
extra_index = try mod.scanNamespace(namespace, extra_index, decls_len, mod.declPtr(decl));
|
||||
const decls = sema.code.bodySlice(extra_index, decls_len);
|
||||
try mod.scanNamespace(namespace, decls, mod.declPtr(decl));
|
||||
extra_index += decls_len;
|
||||
|
||||
const ty = try ip.getStructType(gpa, .{
|
||||
.decl = decl,
|
||||
.namespace = namespace.toOptional(),
|
||||
.zir_index = zir_index,
|
||||
.zir_index = tracked_inst,
|
||||
.layout = small.layout,
|
||||
.known_non_opv = small.known_non_opv,
|
||||
.is_tuple = small.is_tuple,
|
||||
@ -2791,7 +2798,8 @@ fn zirStructDecl(
|
||||
errdefer mod.destroyNamespace(new_namespace_index);
|
||||
|
||||
const struct_ty = ty: {
|
||||
const ty = try sema.getStructType(new_decl_index, new_namespace_index, inst);
|
||||
const tracked_inst = try ip.trackZir(mod.gpa, block.getFileScope(mod), inst);
|
||||
const ty = try sema.getStructType(new_decl_index, new_namespace_index, tracked_inst);
|
||||
if (sema.builtin_type_target_index != .none) {
|
||||
ip.resolveBuiltinType(sema.builtin_type_target_index, ty);
|
||||
break :ty sema.builtin_type_target_index;
|
||||
@ -2850,7 +2858,7 @@ fn createAnonymousDeclTypeNamed(
|
||||
return new_decl_index;
|
||||
},
|
||||
.func => {
|
||||
const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index));
|
||||
const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip));
|
||||
const zir_tags = sema.code.instructions.items(.tag);
|
||||
|
||||
var buf = std.ArrayList(u8).init(gpa);
|
||||
@ -2973,7 +2981,9 @@ fn zirEnumDecl(
|
||||
const new_namespace = mod.namespacePtr(new_namespace_index);
|
||||
errdefer if (!done) mod.destroyNamespace(new_namespace_index);
|
||||
|
||||
extra_index = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl);
|
||||
const decls = sema.code.bodySlice(extra_index, decls_len);
|
||||
try mod.scanNamespace(new_namespace_index, decls, new_decl);
|
||||
extra_index += decls_len;
|
||||
|
||||
const body = sema.code.bodySlice(extra_index, body_len);
|
||||
extra_index += body.len;
|
||||
@ -3244,7 +3254,7 @@ fn zirUnionDecl(
|
||||
},
|
||||
.decl = new_decl_index,
|
||||
.namespace = new_namespace_index,
|
||||
.zir_index = inst,
|
||||
.zir_index = try mod.intern_pool.trackZir(gpa, block.getFileScope(mod), inst),
|
||||
.fields_len = fields_len,
|
||||
.enum_tag_ty = .none,
|
||||
.field_types = &.{},
|
||||
@ -3263,7 +3273,8 @@ fn zirUnionDecl(
|
||||
new_decl.val = Value.fromInterned(union_ty);
|
||||
new_namespace.ty = Type.fromInterned(union_ty);
|
||||
|
||||
_ = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl);
|
||||
const decls = sema.code.bodySlice(extra_index, decls_len);
|
||||
try mod.scanNamespace(new_namespace_index, decls, new_decl);
|
||||
|
||||
const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
|
||||
try mod.finalizeAnonDecl(new_decl_index);
|
||||
@ -3326,7 +3337,8 @@ fn zirOpaqueDecl(
|
||||
new_decl.val = Value.fromInterned(opaque_ty);
|
||||
new_namespace.ty = Type.fromInterned(opaque_ty);
|
||||
|
||||
extra_index = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl);
|
||||
const decls = sema.code.bodySlice(extra_index, decls_len);
|
||||
try mod.scanNamespace(new_namespace_index, decls, new_decl);
|
||||
|
||||
const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
|
||||
try mod.finalizeAnonDecl(new_decl_index);
|
||||
@ -7436,7 +7448,7 @@ fn analyzeCall(
|
||||
// the AIR instructions of the callsite. The callee could be a generic function
|
||||
// which means its parameter type expressions must be resolved in order and used
|
||||
// to successively coerce the arguments.
|
||||
const fn_info = ics.callee().code.getFnInfo(module_fn.zir_body_inst);
|
||||
const fn_info = ics.callee().code.getFnInfo(module_fn.zir_body_inst.resolve(ip));
|
||||
try ics.callee().inst_map.ensureSpaceForInstructions(gpa, fn_info.param_body);
|
||||
|
||||
var arg_i: u32 = 0;
|
||||
@ -7484,7 +7496,7 @@ fn analyzeCall(
|
||||
// each of the parameters, resolving the return type and providing it to the child
|
||||
// `Sema` so that it can be used for the `ret_ptr` instruction.
|
||||
const ret_ty_inst = if (fn_info.ret_ty_body.len != 0)
|
||||
try sema.resolveBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst)
|
||||
try sema.resolveBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst.resolve(ip))
|
||||
else
|
||||
try sema.resolveInst(fn_info.ret_ty_ref);
|
||||
const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
|
||||
@ -7875,7 +7887,7 @@ fn instantiateGenericCall(
|
||||
const namespace_index = fn_owner_decl.src_namespace;
|
||||
const namespace = mod.namespacePtr(namespace_index);
|
||||
const fn_zir = namespace.file_scope.zir;
|
||||
const fn_info = fn_zir.getFnInfo(generic_owner_func.zir_body_inst);
|
||||
const fn_info = fn_zir.getFnInfo(generic_owner_func.zir_body_inst.resolve(ip));
|
||||
|
||||
const comptime_args = try sema.arena.alloc(InternPool.Index, args_info.count());
|
||||
@memset(comptime_args, .none);
|
||||
@ -9457,7 +9469,7 @@ fn funcCommon(
|
||||
.is_generic = final_is_generic,
|
||||
.is_noinline = is_noinline,
|
||||
|
||||
.zir_body_inst = func_inst,
|
||||
.zir_body_inst = try ip.trackZir(gpa, block.getFileScope(mod), func_inst),
|
||||
.lbrace_line = src_locs.lbrace_line,
|
||||
.rbrace_line = src_locs.rbrace_line,
|
||||
.lbrace_column = @as(u16, @truncate(src_locs.columns)),
|
||||
@ -9535,7 +9547,7 @@ fn funcCommon(
|
||||
.ty = func_ty,
|
||||
.cc = cc,
|
||||
.is_noinline = is_noinline,
|
||||
.zir_body_inst = func_inst,
|
||||
.zir_body_inst = try ip.trackZir(gpa, block.getFileScope(mod), func_inst),
|
||||
.lbrace_line = src_locs.lbrace_line,
|
||||
.rbrace_line = src_locs.rbrace_line,
|
||||
.lbrace_column = @as(u16, @truncate(src_locs.columns)),
|
||||
@ -21552,7 +21564,7 @@ fn zirReify(
|
||||
.namespace = new_namespace_index,
|
||||
.enum_tag_ty = enum_tag_ty,
|
||||
.fields_len = fields_len,
|
||||
.zir_index = inst,
|
||||
.zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst), // TODO: should reified types be handled differently?
|
||||
.flags = .{
|
||||
.layout = layout,
|
||||
.status = .have_field_types,
|
||||
@ -21720,7 +21732,7 @@ fn reifyStruct(
|
||||
const ty = try ip.getStructType(gpa, .{
|
||||
.decl = new_decl_index,
|
||||
.namespace = .none,
|
||||
.zir_index = inst,
|
||||
.zir_index = try mod.intern_pool.trackZir(gpa, block.getFileScope(mod), inst), // TODO: should reified types be handled differently?
|
||||
.layout = layout,
|
||||
.known_non_opv = false,
|
||||
.fields_len = fields_len,
|
||||
@ -35592,7 +35604,8 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) Comp
|
||||
break :blk accumulator;
|
||||
};
|
||||
|
||||
const extended = zir.instructions.items(.data)[@intFromEnum(struct_type.zir_index)].extended;
|
||||
const zir_index = struct_type.zir_index.resolve(ip);
|
||||
const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
|
||||
assert(extended.opcode == .struct_decl);
|
||||
const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
|
||||
|
||||
@ -35612,7 +35625,7 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) Comp
|
||||
break :blk try sema.resolveType(&block, backing_int_src, backing_int_ref);
|
||||
} else {
|
||||
const body = zir.bodySlice(extra_index, backing_int_body_len);
|
||||
const ty_ref = try sema.resolveBody(&block, body, struct_type.zir_index);
|
||||
const ty_ref = try sema.resolveBody(&block, body, zir_index);
|
||||
break :blk try sema.analyzeAsType(&block, backing_int_src, ty_ref);
|
||||
}
|
||||
};
|
||||
@ -36340,9 +36353,7 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {
|
||||
}
|
||||
|
||||
// Skip over decls.
|
||||
var decls_it = zir.declIteratorInner(extra_index, decls_len);
|
||||
while (decls_it.next()) |_| {}
|
||||
extra_index = decls_it.extra_index;
|
||||
extra_index += decls_len;
|
||||
|
||||
return .{ fields_len, small, extra_index };
|
||||
}
|
||||
@ -36358,7 +36369,7 @@ fn semaStructFields(
|
||||
const decl = mod.declPtr(decl_index);
|
||||
const namespace_index = struct_type.namespace.unwrap() orelse decl.src_namespace;
|
||||
const zir = mod.namespacePtr(namespace_index).file_scope.zir;
|
||||
const zir_index = struct_type.zir_index;
|
||||
const zir_index = struct_type.zir_index.resolve(ip);
|
||||
|
||||
const fields_len, const small, var extra_index = structZirInfo(zir, zir_index);
|
||||
|
||||
@ -36629,7 +36640,7 @@ fn semaStructFieldInits(
|
||||
const decl = mod.declPtr(decl_index);
|
||||
const namespace_index = struct_type.namespace.unwrap() orelse decl.src_namespace;
|
||||
const zir = mod.namespacePtr(namespace_index).file_scope.zir;
|
||||
const zir_index = struct_type.zir_index;
|
||||
const zir_index = struct_type.zir_index.resolve(ip);
|
||||
const fields_len, const small, var extra_index = structZirInfo(zir, zir_index);
|
||||
|
||||
var comptime_mutable_decls = std.ArrayList(InternPool.DeclIndex).init(gpa);
|
||||
@ -36778,7 +36789,8 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
|
||||
const ip = &mod.intern_pool;
|
||||
const decl_index = union_type.decl;
|
||||
const zir = mod.namespacePtr(union_type.namespace).file_scope.zir;
|
||||
const extended = zir.instructions.items(.data)[@intFromEnum(union_type.zir_index)].extended;
|
||||
const zir_index = union_type.zir_index.resolve(ip);
|
||||
const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
|
||||
assert(extended.opcode == .union_decl);
|
||||
const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
|
||||
var extra_index: usize = extended.operand;
|
||||
@ -36811,9 +36823,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
|
||||
} else 0;
|
||||
|
||||
// Skip over decls.
|
||||
var decls_it = zir.declIteratorInner(extra_index, decls_len);
|
||||
while (decls_it.next()) |_| {}
|
||||
extra_index = decls_it.extra_index;
|
||||
extra_index += decls_len;
|
||||
|
||||
const body = zir.bodySlice(extra_index, body_len);
|
||||
extra_index += body.len;
|
||||
@ -37810,10 +37820,12 @@ pub fn analyzeAddressSpace(
|
||||
ctx: AddressSpaceContext,
|
||||
) !std.builtin.AddressSpace {
|
||||
const mod = sema.mod;
|
||||
const addrspace_tv = try sema.resolveInstConst(block, src, zir_ref, .{
|
||||
const air_ref = try sema.resolveInst(zir_ref);
|
||||
const coerced = try sema.coerce(block, Type.fromInterned(.address_space_type), air_ref, src);
|
||||
const addrspace_val = try sema.resolveConstDefinedValue(block, src, coerced, .{
|
||||
.needed_comptime_reason = "address space must be comptime-known",
|
||||
});
|
||||
const address_space = mod.toEnum(std.builtin.AddressSpace, addrspace_tv.val);
|
||||
const address_space = mod.toEnum(std.builtin.AddressSpace, addrspace_val);
|
||||
const target = sema.mod.getTarget();
|
||||
const arch = target.cpu.arch;
|
||||
|
||||
|
||||
400
src/Zir.zig
400
src/Zir.zig
@ -30,7 +30,7 @@ instructions: std.MultiArrayList(Inst).Slice,
|
||||
/// is referencing the data here whether they want to store both index and length,
|
||||
/// thus allowing null bytes, or store only index, and use null-termination. The
|
||||
/// `string_bytes` array is agnostic to either usage.
|
||||
/// Indexes 0 and 1 are reserved for special cases.
|
||||
/// Index 0 is reserved for special cases.
|
||||
string_bytes: []u8,
|
||||
/// The meaning of this data is determined by `Inst.Tag` value.
|
||||
/// The first few indexes are reserved. See `ExtraIndex` for the values.
|
||||
@ -60,21 +60,6 @@ pub const ExtraIndex = enum(u32) {
|
||||
imports,
|
||||
|
||||
_,
|
||||
|
||||
pub fn toOptional(i: ExtraIndex) OptionalExtraIndex {
|
||||
return @enumFromInt(@intFromEnum(i));
|
||||
}
|
||||
};
|
||||
|
||||
pub const OptionalExtraIndex = enum(u32) {
|
||||
compile_errors,
|
||||
imports,
|
||||
none = std.math.maxInt(u32),
|
||||
_,
|
||||
|
||||
pub fn unwrap(oi: OptionalExtraIndex) ?ExtraIndex {
|
||||
return if (oi == .none) null else @enumFromInt(@intFromEnum(oi));
|
||||
}
|
||||
};
|
||||
|
||||
fn ExtraData(comptime T: type) type {
|
||||
@ -93,6 +78,7 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) ExtraData(T) {
|
||||
|
||||
Inst.Ref,
|
||||
Inst.Index,
|
||||
Inst.Declaration.Name,
|
||||
NullTerminatedString,
|
||||
=> @enumFromInt(code.extra[i]),
|
||||
|
||||
@ -102,6 +88,7 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) ExtraData(T) {
|
||||
Inst.SwitchBlock.Bits,
|
||||
Inst.SwitchBlockErrUnion.Bits,
|
||||
Inst.FuncFancy.Bits,
|
||||
Inst.Declaration.Flags,
|
||||
=> @bitCast(code.extra[i]),
|
||||
|
||||
else => @compileError("bad field type"),
|
||||
@ -116,8 +103,6 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) ExtraData(T) {
|
||||
|
||||
pub const NullTerminatedString = enum(u32) {
|
||||
empty = 0,
|
||||
unnamed_test_decl = 1,
|
||||
decltest = 2,
|
||||
_,
|
||||
};
|
||||
|
||||
@ -304,6 +289,12 @@ pub const Inst = struct {
|
||||
/// a noreturn instruction.
|
||||
/// Uses the `pl_node` union field. Payload is `Block`.
|
||||
block_inline,
|
||||
/// This instruction may only ever appear in the list of declarations for a
|
||||
/// namespace type, e.g. within a `struct_decl` instruction. It represents a
|
||||
/// single source declaration (`const`/`var`/`fn`), containing the name,
|
||||
/// attributes, type, and value of the declaration.
|
||||
/// Uses the `pl_node` union field. Payload is `Declaration`.
|
||||
declaration,
|
||||
/// Implements `suspend {...}`.
|
||||
/// Uses the `pl_node` union field. Payload is `Block`.
|
||||
suspend_block,
|
||||
@ -1092,6 +1083,7 @@ pub const Inst = struct {
|
||||
.block,
|
||||
.block_comptime,
|
||||
.block_inline,
|
||||
.declaration,
|
||||
.suspend_block,
|
||||
.loop,
|
||||
.bool_br_and,
|
||||
@ -1405,6 +1397,7 @@ pub const Inst = struct {
|
||||
.block,
|
||||
.block_comptime,
|
||||
.block_inline,
|
||||
.declaration,
|
||||
.suspend_block,
|
||||
.loop,
|
||||
.bool_br_and,
|
||||
@ -1639,6 +1632,7 @@ pub const Inst = struct {
|
||||
.block = .pl_node,
|
||||
.block_comptime = .pl_node,
|
||||
.block_inline = .pl_node,
|
||||
.declaration = .pl_node,
|
||||
.suspend_block = .pl_node,
|
||||
.bool_not = .un_node,
|
||||
.bool_br_and = .bool_br,
|
||||
@ -2508,6 +2502,7 @@ pub const Inst = struct {
|
||||
/// If this is 1 it means return_type is a simple Ref
|
||||
ret_body_len: u32,
|
||||
/// Points to the block that contains the param instructions for this function.
|
||||
/// If this is a `declaration`, it refers to the declaration's value body.
|
||||
param_block: Index,
|
||||
body_len: u32,
|
||||
|
||||
@ -2565,6 +2560,7 @@ pub const Inst = struct {
|
||||
/// 18. src_locs: Func.SrcLocs // if body_len != 0
|
||||
pub const FuncFancy = struct {
|
||||
/// Points to the block that contains the param instructions for this function.
|
||||
/// If this is a `declaration`, it refers to the declaration's value body.
|
||||
param_block: Index,
|
||||
body_len: u32,
|
||||
bits: Bits,
|
||||
@ -2632,6 +2628,116 @@ pub const Inst = struct {
|
||||
body_len: u32,
|
||||
};
|
||||
|
||||
/// Trailing:
|
||||
/// 0. doc_comment: u32 // if `has_doc_comment`; null-terminated string index
|
||||
/// 1. align_body_len: u32 // if `has_align_linksection_addrspace`; 0 means no `align`
|
||||
/// 2. linksection_body_len: u32 // if `has_align_linksection_addrspace`; 0 means no `linksection`
|
||||
/// 3. addrspace_body_len: u32 // if `has_align_linksection_addrspace`; 0 means no `addrspace`
|
||||
/// 4. value_body_inst: Zir.Inst.Index
|
||||
/// - for each `value_body_len`
|
||||
/// - body to be exited via `break_inline` to this `declaration` instruction
|
||||
/// 5. align_body_inst: Zir.Inst.Index
|
||||
/// - for each `align_body_len`
|
||||
/// - body to be exited via `break_inline` to this `declaration` instruction
|
||||
/// 6. linksection_body_inst: Zir.Inst.Index
|
||||
/// - for each `linksection_body_len`
|
||||
/// - body to be exited via `break_inline` to this `declaration` instruction
|
||||
/// 7. addrspace_body_inst: Zir.Inst.Index
|
||||
/// - for each `addrspace_body_len`
|
||||
/// - body to be exited via `break_inline` to this `declaration` instruction
|
||||
pub const Declaration = struct {
|
||||
// These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.
|
||||
src_hash_0: u32,
|
||||
src_hash_1: u32,
|
||||
src_hash_2: u32,
|
||||
src_hash_3: u32,
|
||||
/// The name of this `Decl`. Also indicates whether it is a test, comptime block, etc.
|
||||
name: Name,
|
||||
/// This Decl's line number relative to that of its parent.
|
||||
/// TODO: column must be encoded similarly to respect non-formatted code!
|
||||
line_offset: u32,
|
||||
flags: Flags,
|
||||
|
||||
pub const Flags = packed struct(u32) {
|
||||
value_body_len: u28,
|
||||
is_pub: bool,
|
||||
is_export: bool,
|
||||
has_doc_comment: bool,
|
||||
has_align_linksection_addrspace: bool,
|
||||
};
|
||||
|
||||
pub const Name = enum(u32) {
|
||||
@"comptime" = std.math.maxInt(u32),
|
||||
@"usingnamespace" = std.math.maxInt(u32) - 1,
|
||||
unnamed_test = std.math.maxInt(u32) - 2,
|
||||
/// In this case, `has_doc_comment` will be true, and the doc
|
||||
/// comment body is the identifier name.
|
||||
decltest = std.math.maxInt(u32) - 3,
|
||||
/// Other values are `NullTerminatedString` values, i.e. index into
|
||||
/// `string_bytes`. If the byte referenced is 0, the decl is a named
|
||||
/// test, and the actual name begins at the following byte.
|
||||
_,
|
||||
|
||||
pub fn isNamedTest(name: Name, zir: Zir) bool {
|
||||
return switch (name) {
|
||||
.@"comptime", .@"usingnamespace", .unnamed_test, .decltest => false,
|
||||
_ => zir.string_bytes[@intFromEnum(name)] == 0,
|
||||
};
|
||||
}
|
||||
pub fn toString(name: Name, zir: Zir) ?NullTerminatedString {
|
||||
switch (name) {
|
||||
.@"comptime", .@"usingnamespace", .unnamed_test, .decltest => return null,
|
||||
_ => {},
|
||||
}
|
||||
const idx: u32 = @intFromEnum(name);
|
||||
if (zir.string_bytes[idx] == 0) {
|
||||
// Named test
|
||||
return @enumFromInt(idx + 1);
|
||||
}
|
||||
return @enumFromInt(idx);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Bodies = struct {
|
||||
value_body: []const Index,
|
||||
align_body: ?[]const Index,
|
||||
linksection_body: ?[]const Index,
|
||||
addrspace_body: ?[]const Index,
|
||||
};
|
||||
|
||||
pub fn getBodies(declaration: Declaration, extra_end: u32, zir: Zir) Bodies {
|
||||
var extra_index: u32 = extra_end;
|
||||
extra_index += @intFromBool(declaration.flags.has_doc_comment);
|
||||
const value_body_len = declaration.flags.value_body_len;
|
||||
const align_body_len, const linksection_body_len, const addrspace_body_len = lens: {
|
||||
if (!declaration.flags.has_align_linksection_addrspace) {
|
||||
break :lens .{ 0, 0, 0 };
|
||||
}
|
||||
const lens = zir.extra[extra_index..][0..3].*;
|
||||
extra_index += 3;
|
||||
break :lens lens;
|
||||
};
|
||||
return .{
|
||||
.value_body = b: {
|
||||
defer extra_index += value_body_len;
|
||||
break :b zir.bodySlice(extra_index, value_body_len);
|
||||
},
|
||||
.align_body = if (align_body_len == 0) null else b: {
|
||||
defer extra_index += align_body_len;
|
||||
break :b zir.bodySlice(extra_index, align_body_len);
|
||||
},
|
||||
.linksection_body = if (linksection_body_len == 0) null else b: {
|
||||
defer extra_index += linksection_body_len;
|
||||
break :b zir.bodySlice(extra_index, linksection_body_len);
|
||||
},
|
||||
.addrspace_body = if (addrspace_body_len == 0) null else b: {
|
||||
defer extra_index += addrspace_body_len;
|
||||
break :b zir.bodySlice(extra_index, addrspace_body_len);
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/// Stored inside extra, with trailing arguments according to `args_len`.
|
||||
/// Implicit 0. arg_0_start: u32, // always same as `args_len`
|
||||
/// 1. arg_end: u32, // for each `args_len`
|
||||
@ -2913,37 +3019,14 @@ pub const Inst = struct {
|
||||
/// 3. backing_int_body_len: u32, // if has_backing_int
|
||||
/// 4. backing_int_ref: Ref, // if has_backing_int and backing_int_body_len is 0
|
||||
/// 5. backing_int_body_inst: Inst, // if has_backing_int and backing_int_body_len is > 0
|
||||
/// 6. decl_bits: u32 // for every 8 decls
|
||||
/// - sets of 4 bits:
|
||||
/// 0b000X: whether corresponding decl is pub
|
||||
/// 0b00X0: whether corresponding decl is exported
|
||||
/// 0b0X00: whether corresponding decl has an align expression
|
||||
/// 0bX000: whether corresponding decl has a linksection or an address space expression
|
||||
/// 7. decl: { // for every decls_len
|
||||
/// src_hash: [4]u32, // hash of source bytes
|
||||
/// line: u32, // line number of decl, relative to parent
|
||||
/// name: NullTerminatedString, // null terminated string index
|
||||
/// - 0 means comptime or usingnamespace decl.
|
||||
/// - if name == 0 `is_exported` determines which one: 0=comptime,1=usingnamespace
|
||||
/// - 1 means test decl with no name.
|
||||
/// - 2 means that the test is a decltest, doc_comment gives the name of the identifier
|
||||
/// - if there is a 0 byte at the position `name` indexes, it indicates
|
||||
/// this is a test decl, and the name starts at `name+1`.
|
||||
/// value: Index,
|
||||
/// doc_comment: u32, .empty if no doc comment, if this is a decltest, doc_comment references the decl name in the string table
|
||||
/// align: Ref, // if corresponding bit is set
|
||||
/// link_section_or_address_space: { // if corresponding bit is set.
|
||||
/// link_section: Ref,
|
||||
/// address_space: Ref,
|
||||
/// }
|
||||
/// }
|
||||
/// 8. flags: u32 // for every 8 fields
|
||||
/// 6. decl: Index, // for every decls_len; points to a `declaration` instruction
|
||||
/// 7. flags: u32 // for every 8 fields
|
||||
/// - sets of 4 bits:
|
||||
/// 0b000X: whether corresponding field has an align expression
|
||||
/// 0b00X0: whether corresponding field has a default expression
|
||||
/// 0b0X00: whether corresponding field is comptime
|
||||
/// 0bX000: whether corresponding field has a type expression
|
||||
/// 9. fields: { // for every fields_len
|
||||
/// 8. fields: { // for every fields_len
|
||||
/// field_name: u32, // if !is_tuple
|
||||
/// doc_comment: NullTerminatedString, // .empty if no doc comment
|
||||
/// field_type: Ref, // if corresponding bit is not set. none means anytype.
|
||||
@ -3009,33 +3092,11 @@ pub const Inst = struct {
|
||||
/// 2. body_len: u32, // if has_body_len
|
||||
/// 3. fields_len: u32, // if has_fields_len
|
||||
/// 4. decls_len: u32, // if has_decls_len
|
||||
/// 5. decl_bits: u32 // for every 8 decls
|
||||
/// - sets of 4 bits:
|
||||
/// 0b000X: whether corresponding decl is pub
|
||||
/// 0b00X0: whether corresponding decl is exported
|
||||
/// 0b0X00: whether corresponding decl has an align expression
|
||||
/// 0bX000: whether corresponding decl has a linksection or an address space expression
|
||||
/// 6. decl: { // for every decls_len
|
||||
/// src_hash: [4]u32, // hash of source bytes
|
||||
/// line: u32, // line number of decl, relative to parent
|
||||
/// name: NullTerminatedString, // null terminated string index
|
||||
/// - 0 means comptime or usingnamespace decl.
|
||||
/// - if name == 0 `is_exported` determines which one: 0=comptime,1=usingnamespace
|
||||
/// - 1 means test decl with no name.
|
||||
/// - if there is a 0 byte at the position `name` indexes, it indicates
|
||||
/// this is a test decl, and the name starts at `name+1`.
|
||||
/// value: Index,
|
||||
/// doc_comment: u32, // .empty if no doc_comment
|
||||
/// align: Ref, // if corresponding bit is set
|
||||
/// link_section_or_address_space: { // if corresponding bit is set.
|
||||
/// link_section: Ref,
|
||||
/// address_space: Ref,
|
||||
/// }
|
||||
/// }
|
||||
/// 7. inst: Index // for every body_len
|
||||
/// 8. has_bits: u32 // for every 32 fields
|
||||
/// 5. decl: Index, // for every decls_len; points to a `declaration` instruction
|
||||
/// 6. inst: Index // for every body_len
|
||||
/// 7. has_bits: u32 // for every 32 fields
|
||||
/// - the bit is whether corresponding field has an value expression
|
||||
/// 9. fields: { // for every fields_len
|
||||
/// 8. fields: { // for every fields_len
|
||||
/// field_name: u32,
|
||||
/// doc_comment: u32, // .empty if no doc_comment
|
||||
/// value: Ref, // if corresponding bit is set
|
||||
@ -3059,37 +3120,15 @@ pub const Inst = struct {
|
||||
/// 2. body_len: u32, // if has_body_len
|
||||
/// 3. fields_len: u32, // if has_fields_len
|
||||
/// 4. decls_len: u32, // if has_decls_len
|
||||
/// 5. decl_bits: u32 // for every 8 decls
|
||||
/// - sets of 4 bits:
|
||||
/// 0b000X: whether corresponding decl is pub
|
||||
/// 0b00X0: whether corresponding decl is exported
|
||||
/// 0b0X00: whether corresponding decl has an align expression
|
||||
/// 0bX000: whether corresponding decl has a linksection or an address space expression
|
||||
/// 6. decl: { // for every decls_len
|
||||
/// src_hash: [4]u32, // hash of source bytes
|
||||
/// line: u32, // line number of decl, relative to parent
|
||||
/// name: NullTerminatedString, // null terminated string index
|
||||
/// - 0 means comptime or usingnamespace decl.
|
||||
/// - if name == 0 `is_exported` determines which one: 0=comptime,1=usingnamespace
|
||||
/// - 1 means test decl with no name.
|
||||
/// - if there is a 0 byte at the position `name` indexes, it indicates
|
||||
/// this is a test decl, and the name starts at `name+1`.
|
||||
/// value: Index,
|
||||
/// doc_comment: NullTerminatedString, // .empty if no doc comment
|
||||
/// align: Ref, // if corresponding bit is set
|
||||
/// link_section_or_address_space: { // if corresponding bit is set.
|
||||
/// link_section: Ref,
|
||||
/// address_space: Ref,
|
||||
/// }
|
||||
/// }
|
||||
/// 7. inst: Index // for every body_len
|
||||
/// 8. has_bits: u32 // for every 8 fields
|
||||
/// 5. decl: Index, // for every decls_len; points to a `declaration` instruction
|
||||
/// 6. inst: Index // for every body_len
|
||||
/// 7. has_bits: u32 // for every 8 fields
|
||||
/// - sets of 4 bits:
|
||||
/// 0b000X: whether corresponding field has a type expression
|
||||
/// 0b00X0: whether corresponding field has a align expression
|
||||
/// 0b0X00: whether corresponding field has a tag value expression
|
||||
/// 0bX000: unused
|
||||
/// 9. fields: { // for every fields_len
|
||||
/// 8. fields: { // for every fields_len
|
||||
/// field_name: NullTerminatedString, // null terminated string index
|
||||
/// doc_comment: NullTerminatedString, // .empty if no doc comment
|
||||
/// field_type: Ref, // if corresponding bit is set
|
||||
@ -3121,29 +3160,7 @@ pub const Inst = struct {
|
||||
/// Trailing:
|
||||
/// 0. src_node: i32, // if has_src_node
|
||||
/// 1. decls_len: u32, // if has_decls_len
|
||||
/// 2. decl_bits: u32 // for every 8 decls
|
||||
/// - sets of 4 bits:
|
||||
/// 0b000X: whether corresponding decl is pub
|
||||
/// 0b00X0: whether corresponding decl is exported
|
||||
/// 0b0X00: whether corresponding decl has an align expression
|
||||
/// 0bX000: whether corresponding decl has a linksection or an address space expression
|
||||
/// 3. decl: { // for every decls_len
|
||||
/// src_hash: [4]u32, // hash of source bytes
|
||||
/// line: u32, // line number of decl, relative to parent
|
||||
/// name: NullTerminatedString, // null terminated string index
|
||||
/// - 0 means comptime or usingnamespace decl.
|
||||
/// - if name == 0 `is_exported` determines which one: 0=comptime,1=usingnamespace
|
||||
/// - 1 means test decl with no name.
|
||||
/// - if there is a 0 byte at the position `name` indexes, it indicates
|
||||
/// this is a test decl, and the name starts at `name+1`.
|
||||
/// value: Index,
|
||||
/// doc_comment: NullTerminatedString, // .empty if no doc comment,
|
||||
/// align: Ref, // if corresponding bit is set
|
||||
/// link_section_or_address_space: { // if corresponding bit is set.
|
||||
/// link_section: Ref,
|
||||
/// address_space: Ref,
|
||||
/// }
|
||||
/// }
|
||||
/// 2. decl: Index, // for every decls_len; points to a `declaration` instruction
|
||||
pub const OpaqueDecl = struct {
|
||||
pub const Small = packed struct {
|
||||
has_src_node: bool,
|
||||
@ -3407,44 +3424,17 @@ pub const Inst = struct {
|
||||
pub const SpecialProng = enum { none, @"else", under };
|
||||
|
||||
pub const DeclIterator = struct {
|
||||
extra_index: usize,
|
||||
bit_bag_index: usize,
|
||||
cur_bit_bag: u32,
|
||||
decl_i: u32,
|
||||
decls_len: u32,
|
||||
extra_index: u32,
|
||||
decls_remaining: u32,
|
||||
zir: Zir,
|
||||
|
||||
pub const Item = struct {
|
||||
name: [:0]const u8,
|
||||
sub_index: ExtraIndex,
|
||||
flags: u4,
|
||||
};
|
||||
|
||||
pub fn next(it: *DeclIterator) ?Item {
|
||||
if (it.decl_i >= it.decls_len) return null;
|
||||
|
||||
if (it.decl_i % 8 == 0) {
|
||||
it.cur_bit_bag = it.zir.extra[it.bit_bag_index];
|
||||
it.bit_bag_index += 1;
|
||||
}
|
||||
it.decl_i += 1;
|
||||
|
||||
const flags: u4 = @truncate(it.cur_bit_bag);
|
||||
it.cur_bit_bag >>= 4;
|
||||
|
||||
const sub_index: ExtraIndex = @enumFromInt(it.extra_index);
|
||||
it.extra_index += 5; // src_hash(4) + line(1)
|
||||
const name = it.zir.nullTerminatedString(@enumFromInt(it.zir.extra[it.extra_index]));
|
||||
it.extra_index += 3; // name(1) + value(1) + doc_comment(1)
|
||||
it.extra_index += @as(u1, @truncate(flags >> 2)); // align
|
||||
it.extra_index += @as(u1, @truncate(flags >> 3)); // link_section
|
||||
it.extra_index += @as(u1, @truncate(flags >> 3)); // address_space
|
||||
|
||||
return Item{
|
||||
.sub_index = sub_index,
|
||||
.name = name,
|
||||
.flags = flags,
|
||||
};
|
||||
pub fn next(it: *DeclIterator) ?Inst.Index {
|
||||
if (it.decls_remaining == 0) return null;
|
||||
const decl_inst: Zir.Inst.Index = @enumFromInt(it.zir.extra[it.extra_index]);
|
||||
it.extra_index += 1;
|
||||
it.decls_remaining -= 1;
|
||||
assert(it.zir.instructions.items(.tag)[@intFromEnum(decl_inst)] == .declaration);
|
||||
return decl_inst;
|
||||
}
|
||||
};
|
||||
|
||||
@ -3454,14 +3444,18 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
|
||||
switch (tags[@intFromEnum(decl_inst)]) {
|
||||
// Functions are allowed and yield no iterations.
|
||||
// There is one case matching this in the extended instruction set below.
|
||||
.func, .func_inferred, .func_fancy => return declIteratorInner(zir, 0, 0),
|
||||
.func, .func_inferred, .func_fancy => return .{
|
||||
.extra_index = undefined,
|
||||
.decls_remaining = 0,
|
||||
.zir = zir,
|
||||
},
|
||||
|
||||
.extended => {
|
||||
const extended = datas[@intFromEnum(decl_inst)].extended;
|
||||
switch (extended.opcode) {
|
||||
.struct_decl => {
|
||||
const small: Inst.StructDecl.Small = @bitCast(extended.small);
|
||||
var extra_index: usize = extended.operand;
|
||||
var extra_index: u32 = extended.operand;
|
||||
extra_index += @intFromBool(small.has_src_node);
|
||||
extra_index += @intFromBool(small.has_fields_len);
|
||||
const decls_len = if (small.has_decls_len) decls_len: {
|
||||
@ -3480,11 +3474,15 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
|
||||
}
|
||||
}
|
||||
|
||||
return declIteratorInner(zir, extra_index, decls_len);
|
||||
return .{
|
||||
.extra_index = extra_index,
|
||||
.decls_remaining = decls_len,
|
||||
.zir = zir,
|
||||
};
|
||||
},
|
||||
.enum_decl => {
|
||||
const small: Inst.EnumDecl.Small = @bitCast(extended.small);
|
||||
var extra_index: usize = extended.operand;
|
||||
var extra_index: u32 = extended.operand;
|
||||
extra_index += @intFromBool(small.has_src_node);
|
||||
extra_index += @intFromBool(small.has_tag_type);
|
||||
extra_index += @intFromBool(small.has_body_len);
|
||||
@ -3495,11 +3493,15 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
|
||||
break :decls_len decls_len;
|
||||
} else 0;
|
||||
|
||||
return declIteratorInner(zir, extra_index, decls_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: usize = extended.operand;
|
||||
var extra_index: u32 = extended.operand;
|
||||
extra_index += @intFromBool(small.has_src_node);
|
||||
extra_index += @intFromBool(small.has_tag_type);
|
||||
extra_index += @intFromBool(small.has_body_len);
|
||||
@ -3510,11 +3512,15 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
|
||||
break :decls_len decls_len;
|
||||
} else 0;
|
||||
|
||||
return declIteratorInner(zir, extra_index, decls_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: usize = extended.operand;
|
||||
var extra_index: u32 = extended.operand;
|
||||
extra_index += @intFromBool(small.has_src_node);
|
||||
const decls_len = if (small.has_decls_len) decls_len: {
|
||||
const decls_len = zir.extra[extra_index];
|
||||
@ -3522,7 +3528,11 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
|
||||
break :decls_len decls_len;
|
||||
} else 0;
|
||||
|
||||
return declIteratorInner(zir, extra_index, decls_len);
|
||||
return .{
|
||||
.extra_index = extra_index,
|
||||
.decls_remaining = decls_len,
|
||||
.zir = zir,
|
||||
};
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
@ -3531,25 +3541,17 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn declIteratorInner(zir: Zir, extra_index: usize, decls_len: u32) DeclIterator {
|
||||
const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable;
|
||||
return .{
|
||||
.zir = zir,
|
||||
.extra_index = extra_index + bit_bags_count,
|
||||
.bit_bag_index = extra_index,
|
||||
.cur_bit_bag = undefined,
|
||||
.decl_i = 0,
|
||||
.decls_len = decls_len,
|
||||
};
|
||||
}
|
||||
|
||||
/// 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_sub_index: ExtraIndex) !void {
|
||||
const block_inst: Zir.Inst.Index = @enumFromInt(zir.extra[@intFromEnum(decl_sub_index) + 6]);
|
||||
pub fn findDecls(zir: Zir, list: *std.ArrayList(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);
|
||||
|
||||
return zir.findDeclsInner(list, block_inst);
|
||||
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);
|
||||
}
|
||||
|
||||
fn findDeclsInner(
|
||||
@ -3791,8 +3793,17 @@ pub fn getParamBody(zir: Zir, fn_inst: Inst.Index) []const Zir.Inst.Index {
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
const param_block = zir.extraData(Inst.Block, datas[@intFromEnum(param_block_index)].pl_node.payload_index);
|
||||
return zir.bodySlice(param_block.end, param_block.data.body_len);
|
||||
switch (tags[@intFromEnum(param_block_index)]) {
|
||||
.block, .block_comptime, .block_inline => {
|
||||
const param_block = zir.extraData(Inst.Block, datas[@intFromEnum(param_block_index)].pl_node.payload_index);
|
||||
return zir.bodySlice(param_block.end, param_block.data.body_len);
|
||||
},
|
||||
.declaration => {
|
||||
const decl, const extra_end = zir.getDeclaration(param_block_index);
|
||||
return decl.getBodies(extra_end, zir).value_body;
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
|
||||
@ -3888,12 +3899,17 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
switch (tags[@intFromEnum(info.param_block)]) {
|
||||
.block, .block_comptime, .block_inline => {}, // OK
|
||||
else => unreachable, // assertion failure
|
||||
}
|
||||
const param_block = zir.extraData(Inst.Block, datas[@intFromEnum(info.param_block)].pl_node.payload_index);
|
||||
const param_body = zir.bodySlice(param_block.end, param_block.data.body_len);
|
||||
const param_body = switch (tags[@intFromEnum(info.param_block)]) {
|
||||
.block, .block_comptime, .block_inline => param_body: {
|
||||
const param_block = zir.extraData(Inst.Block, datas[@intFromEnum(info.param_block)].pl_node.payload_index);
|
||||
break :param_body zir.bodySlice(param_block.end, param_block.data.body_len);
|
||||
},
|
||||
.declaration => param_body: {
|
||||
const decl, const extra_end = zir.getDeclaration(info.param_block);
|
||||
break :param_body decl.getBodies(extra_end, zir).value_body;
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
var total_params_len: u32 = 0;
|
||||
for (param_body) |inst| {
|
||||
switch (tags[@intFromEnum(inst)]) {
|
||||
@ -3912,3 +3928,13 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
|
||||
.total_params_len = total_params_len,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getDeclaration(zir: Zir, inst: Zir.Inst.Index) struct { Inst.Declaration, u32 } {
|
||||
assert(zir.instructions.items(.tag)[@intFromEnum(inst)] == .declaration);
|
||||
const pl_node = zir.instructions.items(.data)[@intFromEnum(inst)].pl_node;
|
||||
const extra = zir.extraData(Inst.Declaration, pl_node.payload_index);
|
||||
return .{
|
||||
extra.data,
|
||||
@intCast(extra.end),
|
||||
};
|
||||
}
|
||||
|
||||
17
src/main.zig
17
src/main.zig
@ -6855,10 +6855,7 @@ pub fn cmdChangelist(
|
||||
var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{};
|
||||
defer inst_map.deinit(gpa);
|
||||
|
||||
var extra_map: std.AutoHashMapUnmanaged(Zir.ExtraIndex, Zir.ExtraIndex) = .{};
|
||||
defer extra_map.deinit(gpa);
|
||||
|
||||
try Module.mapOldZirToNew(gpa, old_zir, file.zir, &inst_map, &extra_map);
|
||||
try Module.mapOldZirToNew(gpa, old_zir, file.zir, &inst_map);
|
||||
|
||||
var bw = io.bufferedWriter(io.getStdOut().writer());
|
||||
const stdout = bw.writer();
|
||||
@ -6867,16 +6864,8 @@ pub fn cmdChangelist(
|
||||
var it = inst_map.iterator();
|
||||
while (it.next()) |entry| {
|
||||
try stdout.print(" %{d} => %{d}\n", .{
|
||||
entry.key_ptr.*, entry.value_ptr.*,
|
||||
});
|
||||
}
|
||||
}
|
||||
{
|
||||
try stdout.print("Extra mappings:\n", .{});
|
||||
var it = extra_map.iterator();
|
||||
while (it.next()) |entry| {
|
||||
try stdout.print(" {d} => {d}\n", .{
|
||||
entry.key_ptr.*, entry.value_ptr.*,
|
||||
@intFromEnum(entry.key_ptr.*),
|
||||
@intFromEnum(entry.value_ptr.*),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -521,6 +521,8 @@ const Writer = struct {
|
||||
.@"defer" => try self.writeDefer(stream, inst),
|
||||
.defer_err_code => try self.writeDeferErrCode(stream, inst),
|
||||
|
||||
.declaration => try self.writeDeclaration(stream, inst),
|
||||
|
||||
.extended => try self.writeExtended(stream, inst),
|
||||
}
|
||||
}
|
||||
@ -1454,8 +1456,9 @@ const Writer = struct {
|
||||
|
||||
try stream.writeAll("{\n");
|
||||
self.indent += 2;
|
||||
extra_index = try self.writeDecls(stream, decls_len, extra_index);
|
||||
try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
|
||||
self.indent -= 2;
|
||||
extra_index += decls_len;
|
||||
try stream.writeByteNTimes(' ', self.indent);
|
||||
try stream.writeAll("}, ");
|
||||
}
|
||||
@ -1634,8 +1637,9 @@ const Writer = struct {
|
||||
|
||||
try stream.writeAll("{\n");
|
||||
self.indent += 2;
|
||||
extra_index = try self.writeDecls(stream, decls_len, extra_index);
|
||||
try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
|
||||
self.indent -= 2;
|
||||
extra_index += decls_len;
|
||||
try stream.writeByteNTimes(' ', self.indent);
|
||||
try stream.writeAll("}");
|
||||
}
|
||||
@ -1727,124 +1731,6 @@ const Writer = struct {
|
||||
try self.writeSrcNode(stream, src_node);
|
||||
}
|
||||
|
||||
fn writeDecls(self: *Writer, stream: anytype, decls_len: u32, extra_start: usize) !usize {
|
||||
const parent_decl_node = self.parent_decl_node;
|
||||
const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable;
|
||||
var extra_index = extra_start + bit_bags_count;
|
||||
var bit_bag_index: usize = extra_start;
|
||||
var cur_bit_bag: u32 = undefined;
|
||||
var decl_i: u32 = 0;
|
||||
while (decl_i < decls_len) : (decl_i += 1) {
|
||||
if (decl_i % 8 == 0) {
|
||||
cur_bit_bag = self.code.extra[bit_bag_index];
|
||||
bit_bag_index += 1;
|
||||
}
|
||||
const is_pub = @as(u1, @truncate(cur_bit_bag)) != 0;
|
||||
cur_bit_bag >>= 1;
|
||||
const is_exported = @as(u1, @truncate(cur_bit_bag)) != 0;
|
||||
cur_bit_bag >>= 1;
|
||||
const has_align = @as(u1, @truncate(cur_bit_bag)) != 0;
|
||||
cur_bit_bag >>= 1;
|
||||
const has_section_or_addrspace = @as(u1, @truncate(cur_bit_bag)) != 0;
|
||||
cur_bit_bag >>= 1;
|
||||
|
||||
const sub_index = extra_index;
|
||||
|
||||
const hash_u32s = self.code.extra[extra_index..][0..4];
|
||||
extra_index += 4;
|
||||
const line = self.code.extra[extra_index];
|
||||
extra_index += 1;
|
||||
const decl_name_index = self.code.extra[extra_index];
|
||||
extra_index += 1;
|
||||
const decl_index: Zir.Inst.Index = @enumFromInt(self.code.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
const doc_comment_index: Zir.NullTerminatedString = @enumFromInt(self.code.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
|
||||
const align_inst: Zir.Inst.Ref = if (!has_align) .none else inst: {
|
||||
const inst = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
|
||||
extra_index += 1;
|
||||
break :inst inst;
|
||||
};
|
||||
const section_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: {
|
||||
const inst = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
|
||||
extra_index += 1;
|
||||
break :inst inst;
|
||||
};
|
||||
const addrspace_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: {
|
||||
const inst = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
|
||||
extra_index += 1;
|
||||
break :inst inst;
|
||||
};
|
||||
|
||||
const pub_str = if (is_pub) "pub " else "";
|
||||
const hash_bytes: [16]u8 = @bitCast(hash_u32s.*);
|
||||
if (decl_name_index == 0) {
|
||||
try stream.writeByteNTimes(' ', self.indent);
|
||||
const name = if (is_exported) "usingnamespace" else "comptime";
|
||||
try stream.writeAll(pub_str);
|
||||
try stream.writeAll(name);
|
||||
} else if (decl_name_index == 1) {
|
||||
try stream.writeByteNTimes(' ', self.indent);
|
||||
try stream.writeAll("test");
|
||||
} else if (decl_name_index == 2) {
|
||||
try stream.writeByteNTimes(' ', self.indent);
|
||||
try stream.print("[{d}] decltest {s}", .{ sub_index, self.code.nullTerminatedString(doc_comment_index) });
|
||||
} else {
|
||||
const raw_decl_name = self.code.nullTerminatedString(@enumFromInt(decl_name_index));
|
||||
const decl_name = if (raw_decl_name.len == 0)
|
||||
self.code.nullTerminatedString(@enumFromInt(decl_name_index + 1))
|
||||
else
|
||||
raw_decl_name;
|
||||
const test_str = if (raw_decl_name.len == 0) "test \"" else "";
|
||||
const export_str = if (is_exported) "export " else "";
|
||||
|
||||
try self.writeDocComment(stream, doc_comment_index);
|
||||
|
||||
try stream.writeByteNTimes(' ', self.indent);
|
||||
const endquote_if_test: []const u8 = if (raw_decl_name.len == 0) "\"" else "";
|
||||
try stream.print("[{d}] {s}{s}{s}{}{s}", .{
|
||||
sub_index, pub_str, test_str, export_str, std.zig.fmtId(decl_name), endquote_if_test,
|
||||
});
|
||||
if (align_inst != .none) {
|
||||
try stream.writeAll(" align(");
|
||||
try self.writeInstRef(stream, align_inst);
|
||||
try stream.writeAll(")");
|
||||
}
|
||||
if (addrspace_inst != .none) {
|
||||
try stream.writeAll(" addrspace(");
|
||||
try self.writeInstRef(stream, addrspace_inst);
|
||||
try stream.writeAll(")");
|
||||
}
|
||||
if (section_inst != .none) {
|
||||
try stream.writeAll(" linksection(");
|
||||
try self.writeInstRef(stream, section_inst);
|
||||
try stream.writeAll(")");
|
||||
}
|
||||
}
|
||||
|
||||
if (self.recurse_decls) {
|
||||
const tag = self.code.instructions.items(.tag)[@intFromEnum(decl_index)];
|
||||
try stream.print(" line({d}) hash({}): %{d} = {s}(", .{
|
||||
line, std.fmt.fmtSliceHexLower(&hash_bytes), @intFromEnum(decl_index), @tagName(tag),
|
||||
});
|
||||
|
||||
const decl_block_inst_data = self.code.instructions.items(.data)[@intFromEnum(decl_index)].pl_node;
|
||||
const sub_decl_node_off = decl_block_inst_data.src_node;
|
||||
self.parent_decl_node = self.relativeToNodeIndex(sub_decl_node_off);
|
||||
try self.writePlNodeBlockWithoutSrc(stream, decl_index);
|
||||
self.parent_decl_node = parent_decl_node;
|
||||
try self.writeSrc(stream, decl_block_inst_data.src());
|
||||
try stream.writeAll("\n");
|
||||
} else {
|
||||
try stream.print(" line({d}) hash({}): %{d} = ...\n", .{
|
||||
line, std.fmt.fmtSliceHexLower(&hash_bytes), @intFromEnum(decl_index),
|
||||
});
|
||||
}
|
||||
}
|
||||
return extra_index;
|
||||
}
|
||||
|
||||
fn writeEnumDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
|
||||
const small = @as(Zir.Inst.EnumDecl.Small, @bitCast(extended.small));
|
||||
var extra_index: usize = extended.operand;
|
||||
@ -1891,8 +1777,9 @@ const Writer = struct {
|
||||
|
||||
try stream.writeAll("{\n");
|
||||
self.indent += 2;
|
||||
extra_index = try self.writeDecls(stream, decls_len, extra_index);
|
||||
try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
|
||||
self.indent -= 2;
|
||||
extra_index += decls_len;
|
||||
try stream.writeByteNTimes(' ', self.indent);
|
||||
try stream.writeAll("}, ");
|
||||
}
|
||||
@ -1988,7 +1875,7 @@ const Writer = struct {
|
||||
|
||||
try stream.writeAll("{\n");
|
||||
self.indent += 2;
|
||||
_ = try self.writeDecls(stream, decls_len, extra_index);
|
||||
try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
|
||||
self.indent -= 2;
|
||||
try stream.writeByteNTimes(' ', self.indent);
|
||||
try stream.writeAll("})");
|
||||
@ -2762,6 +2649,64 @@ const Writer = struct {
|
||||
try stream.writeByte(')');
|
||||
}
|
||||
|
||||
fn writeDeclaration(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
|
||||
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
|
||||
const extra = self.code.extraData(Zir.Inst.Declaration, inst_data.payload_index);
|
||||
const doc_comment: ?Zir.NullTerminatedString = if (extra.data.flags.has_doc_comment) dc: {
|
||||
break :dc @enumFromInt(self.code.extra[extra.end]);
|
||||
} else null;
|
||||
if (extra.data.flags.is_pub) try stream.writeAll("pub ");
|
||||
if (extra.data.flags.is_export) try stream.writeAll("export ");
|
||||
switch (extra.data.name) {
|
||||
.@"comptime" => try stream.writeAll("comptime"),
|
||||
.@"usingnamespace" => try stream.writeAll("usingnamespace"),
|
||||
.unnamed_test => try stream.writeAll("test"),
|
||||
.decltest => try stream.print("decltest '{s}'", .{self.code.nullTerminatedString(doc_comment.?)}),
|
||||
_ => {
|
||||
const name = extra.data.name.toString(self.code).?;
|
||||
const prefix = if (extra.data.name.isNamedTest(self.code)) "test " else "";
|
||||
try stream.print("{s}'{s}'", .{ prefix, self.code.nullTerminatedString(name) });
|
||||
},
|
||||
}
|
||||
const src_hash_arr: [4]u32 = .{
|
||||
extra.data.src_hash_0,
|
||||
extra.data.src_hash_1,
|
||||
extra.data.src_hash_2,
|
||||
extra.data.src_hash_3,
|
||||
};
|
||||
const src_hash_bytes: [16]u8 = @bitCast(src_hash_arr);
|
||||
try stream.print(" line(+{d}) hash({})", .{ extra.data.line_offset, std.fmt.fmtSliceHexLower(&src_hash_bytes) });
|
||||
|
||||
{
|
||||
const prev_parent_decl_node = self.parent_decl_node;
|
||||
defer self.parent_decl_node = prev_parent_decl_node;
|
||||
self.parent_decl_node = self.relativeToNodeIndex(inst_data.src_node);
|
||||
|
||||
const bodies = extra.data.getBodies(@intCast(extra.end), self.code);
|
||||
|
||||
try stream.writeAll(" value=");
|
||||
try self.writeBracedDecl(stream, bodies.value_body);
|
||||
|
||||
if (bodies.align_body) |b| {
|
||||
try stream.writeAll(" align=");
|
||||
try self.writeBracedDecl(stream, b);
|
||||
}
|
||||
|
||||
if (bodies.linksection_body) |b| {
|
||||
try stream.writeAll(" linksection=");
|
||||
try self.writeBracedDecl(stream, b);
|
||||
}
|
||||
|
||||
if (bodies.addrspace_body) |b| {
|
||||
try stream.writeAll(" addrspace=");
|
||||
try self.writeBracedDecl(stream, b);
|
||||
}
|
||||
}
|
||||
|
||||
try stream.writeAll(") ");
|
||||
try self.writeSrc(stream, inst_data.src());
|
||||
}
|
||||
|
||||
fn writeInstRef(self: *Writer, stream: anytype, ref: Zir.Inst.Ref) !void {
|
||||
if (ref == .none) {
|
||||
return stream.writeAll(".none");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user