Commit b9a099e83c
Changed files (6)
lib/std/builtin.zig
@@ -263,7 +263,7 @@ pub const TypeInfo = union(enum) {
/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
- pub const ContainerLayout = enum {
+ pub const ContainerLayout = enum(u2) {
Auto,
Extern,
Packed,
src/AstGen.zig
@@ -85,6 +85,7 @@ pub fn generate(gpa: *Allocator, tree: ast.Tree) InnerError!Zir {
var gen_scope: GenZir = .{
.force_comptime = true,
.parent = null,
+ .anon_name_strategy = .parent,
.decl_node_index = 0,
.decl_line = 0,
.astgen = &astgen,
@@ -105,7 +106,7 @@ pub fn generate(gpa: *Allocator, tree: ast.Tree) InnerError!Zir {
&gen_scope.base,
0,
container_decl,
- .struct_decl,
+ .Auto,
)) |struct_decl_ref| {
astgen.extra.items[@enumToInt(Zir.ExtraIndex.main_struct)] = @enumToInt(struct_decl_ref);
} else |err| switch (err) {
@@ -1959,16 +1960,12 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
.union_init_ptr,
.field_type,
.field_type_ref,
- .struct_decl,
- .struct_decl_packed,
- .struct_decl_extern,
- .union_decl,
- .union_decl_packed,
- .union_decl_extern,
- .enum_decl,
- .enum_decl_nonexhaustive,
.opaque_decl,
+ .opaque_decl_anon,
+ .opaque_decl_func,
.error_set_decl,
+ .error_set_decl_anon,
+ .error_set_decl_func,
.int_to_enum,
.enum_to_int,
.type_info,
@@ -2166,7 +2163,7 @@ fn varDecl(
const local_val = s.cast(Scope.LocalVal).?;
if (local_val.name == ident_name) {
return astgen.failTokNotes(name_token, "redeclaration of '{s}'", .{
- @ptrCast([*:0]const u8, astgen.string_bytes.items.ptr) + ident_name,
+ astgen.nullTerminatedString(ident_name),
}, &[_]u32{
try astgen.errNoteTok(
local_val.token_src,
@@ -2181,7 +2178,7 @@ fn varDecl(
const local_ptr = s.cast(Scope.LocalPtr).?;
if (local_ptr.name == ident_name) {
return astgen.failTokNotes(name_token, "redeclaration of '{s}'", .{
- @ptrCast([*:0]const u8, astgen.string_bytes.items.ptr) + ident_name,
+ astgen.nullTerminatedString(ident_name),
}, &[_]u32{
try astgen.errNoteTok(
local_ptr.token_src,
@@ -2941,12 +2938,16 @@ fn globalVarDecl(
// of the top level declaration.
const block_inst = try gz.addBlock(.block_inline, node);
+ const name_token = var_decl.ast.mut_token + 1;
+ const name_str_index = try astgen.identAsString(name_token);
+
var block_scope: GenZir = .{
.parent = scope,
.decl_node_index = node,
.decl_line = gz.calcLine(node),
.astgen = astgen,
.force_comptime = true,
+ .anon_name_strategy = .parent,
};
defer block_scope.instructions.deinit(gpa);
@@ -3043,9 +3044,6 @@ fn globalVarDecl(
_ = try block_scope.addBreak(.break_inline, block_inst, var_inst);
try block_scope.setBlockBody(block_inst);
- const name_token = var_decl.ast.mut_token + 1;
- const name_str_index = try astgen.identAsString(name_token);
-
try wip_decls.payload.ensureUnusedCapacity(gpa, 9);
{
const contents_hash = std.zig.hashSrc(tree.getNodeSource(node));
@@ -3258,14 +3256,18 @@ fn structDeclInner(
scope: *Scope,
node: ast.Node.Index,
container_decl: ast.full.ContainerDecl,
- tag: Zir.Inst.Tag,
+ layout: std.builtin.TypeInfo.ContainerLayout,
) InnerError!Zir.Inst.Ref {
if (container_decl.ast.members.len == 0) {
- return gz.addPlNode(tag, node, Zir.Inst.StructDecl{
+ const decl_inst = try gz.reserveInstructionIndex();
+ try gz.setStruct(decl_inst, .{
+ .src_node = node,
+ .layout = layout,
.fields_len = 0,
.body_len = 0,
.decls_len = 0,
});
+ return gz.indexToRef(decl_inst);
}
const astgen = gz.astgen;
@@ -3437,23 +3439,24 @@ fn structDeclInner(
}
}
- const decl_inst = try gz.addBlock(tag, node);
- try gz.instructions.append(gpa, decl_inst);
+ const decl_inst = try gz.reserveInstructionIndex();
if (block_scope.instructions.items.len != 0) {
_ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
}
- try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.StructDecl).Struct.fields.len +
- bit_bag.items.len + @boolToInt(field_index != 0) + fields_data.items.len +
- block_scope.instructions.items.len +
- wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) +
- wip_decls.payload.items.len);
- const zir_datas = astgen.instructions.items(.data);
- zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.StructDecl{
+ try gz.setStruct(decl_inst, .{
+ .src_node = node,
+ .layout = layout,
.body_len = @intCast(u32, block_scope.instructions.items.len),
.fields_len = @intCast(u32, field_index),
.decls_len = @intCast(u32, wip_decls.decl_index),
});
+
+ try astgen.extra.ensureUnusedCapacity(gpa, bit_bag.items.len +
+ @boolToInt(field_index != 0) + fields_data.items.len +
+ block_scope.instructions.items.len +
+ wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) +
+ wip_decls.payload.items.len);
astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.
if (wip_decls.decl_index != 0) {
astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);
@@ -3476,7 +3479,7 @@ fn unionDeclInner(
scope: *Scope,
node: ast.Node.Index,
members: []const ast.Node.Index,
- tag: Zir.Inst.Tag,
+ layout: std.builtin.TypeInfo.ContainerLayout,
arg_inst: Zir.Inst.Ref,
have_auto_enum: bool,
) InnerError!Zir.Inst.Ref {
@@ -3611,11 +3614,12 @@ fn unionDeclInner(
const have_type = member.ast.type_expr != 0;
const have_align = member.ast.align_expr != 0;
const have_value = member.ast.value_expr != 0;
+ const unused = false;
cur_bit_bag = (cur_bit_bag >> bits_per_field) |
(@as(u32, @boolToInt(have_type)) << 28) |
(@as(u32, @boolToInt(have_align)) << 29) |
(@as(u32, @boolToInt(have_value)) << 30) |
- (@as(u32, @boolToInt(have_auto_enum)) << 31);
+ (@as(u32, @boolToInt(unused)) << 31);
if (have_type) {
const field_type = try typeExpr(&block_scope, &block_scope.base, member.ast.type_expr);
@@ -3662,24 +3666,26 @@ fn unionDeclInner(
}
}
- const decl_inst = try gz.addBlock(tag, node);
- try gz.instructions.append(gpa, decl_inst);
+ const decl_inst = try gz.reserveInstructionIndex();
if (block_scope.instructions.items.len != 0) {
_ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
}
- try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.UnionDecl).Struct.fields.len +
- bit_bag.items.len + 1 + fields_data.items.len +
- block_scope.instructions.items.len +
- wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) +
- wip_decls.payload.items.len);
- const zir_datas = astgen.instructions.items(.data);
- zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.UnionDecl{
+ try gz.setUnion(decl_inst, .{
+ .src_node = node,
+ .layout = layout,
.tag_type = arg_inst,
.body_len = @intCast(u32, block_scope.instructions.items.len),
.fields_len = @intCast(u32, field_index),
.decls_len = @intCast(u32, wip_decls.decl_index),
+ .auto_enum_tag = have_auto_enum,
});
+
+ try astgen.extra.ensureUnusedCapacity(gpa, bit_bag.items.len +
+ 1 + fields_data.items.len +
+ block_scope.instructions.items.len +
+ wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) +
+ wip_decls.payload.items.len);
astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.
if (wip_decls.decl_index != 0) {
astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);
@@ -3719,29 +3725,27 @@ fn containerDecl(
switch (token_tags[container_decl.ast.main_token]) {
.keyword_struct => {
- const tag = if (container_decl.layout_token) |t| switch (token_tags[t]) {
- .keyword_packed => Zir.Inst.Tag.struct_decl_packed,
- .keyword_extern => Zir.Inst.Tag.struct_decl_extern,
+ const layout = if (container_decl.layout_token) |t| switch (token_tags[t]) {
+ .keyword_packed => std.builtin.TypeInfo.ContainerLayout.Packed,
+ .keyword_extern => std.builtin.TypeInfo.ContainerLayout.Extern,
else => unreachable,
- } else Zir.Inst.Tag.struct_decl;
+ } else std.builtin.TypeInfo.ContainerLayout.Auto;
assert(arg_inst == .none);
- const result = try structDeclInner(gz, scope, node, container_decl, tag);
+ const result = try structDeclInner(gz, scope, node, container_decl, layout);
return rvalue(gz, scope, rl, result, node);
},
.keyword_union => {
- const tag = if (container_decl.layout_token) |t| switch (token_tags[t]) {
- .keyword_packed => Zir.Inst.Tag.union_decl_packed,
- .keyword_extern => Zir.Inst.Tag.union_decl_extern,
+ const layout = if (container_decl.layout_token) |t| switch (token_tags[t]) {
+ .keyword_packed => std.builtin.TypeInfo.ContainerLayout.Packed,
+ .keyword_extern => std.builtin.TypeInfo.ContainerLayout.Extern,
else => unreachable,
- } else Zir.Inst.Tag.union_decl;
+ } else std.builtin.TypeInfo.ContainerLayout.Auto;
- // See `Zir.Inst.UnionDecl` doc comments for why this is stored along
- // with fields instead of separately.
const have_auto_enum = container_decl.ast.enum_token != null;
- const result = try unionDeclInner(gz, scope, node, container_decl.ast.members, tag, arg_inst, have_auto_enum);
+ const result = try unionDeclInner(gz, scope, node, container_decl.ast.members, layout, arg_inst, have_auto_enum);
return rvalue(gz, scope, rl, result, node);
},
.keyword_enum => {
@@ -3832,10 +3836,7 @@ fn containerDecl(
}
// In this case we must generate ZIR code for the tag values, similar to
// how structs are handled above.
- const tag: Zir.Inst.Tag = if (counts.nonexhaustive_node == 0)
- .enum_decl
- else
- .enum_decl_nonexhaustive;
+ const nonexhaustive = counts.nonexhaustive_node != 0;
// The enum_decl instruction introduces a scope in which the decls of the enum
// are in scope, so that tag values can refer to decls within the enum itself.
@@ -3995,24 +3996,25 @@ fn containerDecl(
}
}
- const decl_inst = try gz.addBlock(tag, node);
- try gz.instructions.append(gpa, decl_inst);
+ const decl_inst = try gz.reserveInstructionIndex();
if (block_scope.instructions.items.len != 0) {
_ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
}
- try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.EnumDecl).Struct.fields.len +
- bit_bag.items.len + 1 + fields_data.items.len +
- block_scope.instructions.items.len +
- wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) +
- wip_decls.payload.items.len);
- const zir_datas = astgen.instructions.items(.data);
- zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.EnumDecl{
+ try gz.setEnum(decl_inst, .{
+ .src_node = node,
+ .nonexhaustive = nonexhaustive,
.tag_type = arg_inst,
.body_len = @intCast(u32, block_scope.instructions.items.len),
.fields_len = @intCast(u32, field_index),
.decls_len = @intCast(u32, wip_decls.decl_index),
});
+
+ try astgen.extra.ensureUnusedCapacity(gpa, bit_bag.items.len +
+ 1 + fields_data.items.len +
+ block_scope.instructions.items.len +
+ wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) +
+ wip_decls.payload.items.len);
astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.
if (wip_decls.decl_index != 0) {
astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);
@@ -4118,7 +4120,12 @@ fn containerDecl(
wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * WipDecls.bits_per_field);
}
}
- const decl_inst = try gz.addBlock(.opaque_decl, node);
+ const tag: Zir.Inst.Tag = switch (gz.anon_name_strategy) {
+ .parent => .opaque_decl,
+ .anon => .opaque_decl_anon,
+ .func => .opaque_decl_func,
+ };
+ const decl_inst = try gz.addBlock(tag, node);
try gz.instructions.append(gpa, decl_inst);
try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.OpaqueDecl).Struct.fields.len +
@@ -4173,6 +4180,11 @@ fn errorSetDecl(
}
}
+ const tag: Zir.Inst.Tag = switch (gz.anon_name_strategy) {
+ .parent => .error_set_decl,
+ .anon => .error_set_decl_anon,
+ .func => .error_set_decl_func,
+ };
const result = try gz.addPlNode(.error_set_decl, node, Zir.Inst.ErrorSetDecl{
.fields_len = @intCast(u32, field_names.items.len),
});
@@ -5907,7 +5919,6 @@ fn charLiteral(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index)
const value = std.zig.parseCharLiteral(slice, &bad_index) catch |err| switch (err) {
error.InvalidCharacter => {
const bad_byte = slice[bad_index];
- const token_starts = tree.tokens.items(.start);
return astgen.failOff(
main_token,
@intCast(u32, bad_index),
@@ -7779,6 +7790,8 @@ const GenZir = struct {
const base_tag: Scope.Tag = .gen_zir;
base: Scope = Scope{ .tag = base_tag },
force_comptime: bool,
+ /// How decls created in this scope should be named.
+ anon_name_strategy: Zir.Inst.NameStrategy = .anon,
/// The end of special indexes. `Zir.Inst.Ref` subtracts against this number to convert
/// to `Zir.Inst.Index`. The default here is correct if there are 0 parameters.
ref_start_index: u32 = Zir.Inst.Ref.typed_value_map.len,
@@ -8623,18 +8636,176 @@ const GenZir = struct {
return new_index;
}
+ fn setStruct(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
+ src_node: ast.Node.Index,
+ body_len: u32,
+ fields_len: u32,
+ decls_len: u32,
+ layout: std.builtin.TypeInfo.ContainerLayout,
+ }) !void {
+ const astgen = gz.astgen;
+ const gpa = astgen.gpa;
+
+ try astgen.extra.ensureUnusedCapacity(gpa, 4);
+ const payload_index = @intCast(u32, astgen.extra.items.len);
+
+ if (args.src_node != 0) {
+ const node_offset = gz.nodeIndexToRelative(args.src_node);
+ astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset));
+ }
+ if (args.body_len != 0) {
+ astgen.extra.appendAssumeCapacity(args.body_len);
+ }
+ if (args.fields_len != 0) {
+ astgen.extra.appendAssumeCapacity(args.fields_len);
+ }
+ if (args.decls_len != 0) {
+ astgen.extra.appendAssumeCapacity(args.decls_len);
+ }
+ astgen.instructions.set(inst, .{
+ .tag = .extended,
+ .data = .{ .extended = .{
+ .opcode = .struct_decl,
+ .small = @bitCast(u16, Zir.Inst.StructDecl.Small{
+ .has_src_node = args.src_node != 0,
+ .has_body_len = args.body_len != 0,
+ .has_fields_len = args.fields_len != 0,
+ .has_decls_len = args.decls_len != 0,
+ .name_strategy = gz.anon_name_strategy,
+ .layout = args.layout,
+ }),
+ .operand = payload_index,
+ } },
+ });
+ }
+
+ fn setUnion(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
+ src_node: ast.Node.Index,
+ tag_type: Zir.Inst.Ref,
+ body_len: u32,
+ fields_len: u32,
+ decls_len: u32,
+ layout: std.builtin.TypeInfo.ContainerLayout,
+ auto_enum_tag: bool,
+ }) !void {
+ const astgen = gz.astgen;
+ const gpa = astgen.gpa;
+
+ try astgen.extra.ensureUnusedCapacity(gpa, 5);
+ const payload_index = @intCast(u32, astgen.extra.items.len);
+
+ if (args.src_node != 0) {
+ const node_offset = gz.nodeIndexToRelative(args.src_node);
+ astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset));
+ }
+ if (args.tag_type != .none) {
+ astgen.extra.appendAssumeCapacity(@enumToInt(args.tag_type));
+ }
+ if (args.body_len != 0) {
+ astgen.extra.appendAssumeCapacity(args.body_len);
+ }
+ if (args.fields_len != 0) {
+ astgen.extra.appendAssumeCapacity(args.fields_len);
+ }
+ if (args.decls_len != 0) {
+ astgen.extra.appendAssumeCapacity(args.decls_len);
+ }
+ astgen.instructions.set(inst, .{
+ .tag = .extended,
+ .data = .{ .extended = .{
+ .opcode = .union_decl,
+ .small = @bitCast(u16, Zir.Inst.UnionDecl.Small{
+ .has_src_node = args.src_node != 0,
+ .has_tag_type = args.tag_type != .none,
+ .has_body_len = args.body_len != 0,
+ .has_fields_len = args.fields_len != 0,
+ .has_decls_len = args.decls_len != 0,
+ .name_strategy = gz.anon_name_strategy,
+ .layout = args.layout,
+ .auto_enum_tag = args.auto_enum_tag,
+ }),
+ .operand = payload_index,
+ } },
+ });
+ }
+
+ fn setEnum(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
+ src_node: ast.Node.Index,
+ tag_type: Zir.Inst.Ref,
+ body_len: u32,
+ fields_len: u32,
+ decls_len: u32,
+ nonexhaustive: bool,
+ }) !void {
+ const astgen = gz.astgen;
+ const gpa = astgen.gpa;
+
+ try astgen.extra.ensureUnusedCapacity(gpa, 5);
+ const payload_index = @intCast(u32, astgen.extra.items.len);
+
+ if (args.src_node != 0) {
+ const node_offset = gz.nodeIndexToRelative(args.src_node);
+ astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset));
+ }
+ if (args.tag_type != .none) {
+ astgen.extra.appendAssumeCapacity(@enumToInt(args.tag_type));
+ }
+ if (args.body_len != 0) {
+ astgen.extra.appendAssumeCapacity(args.body_len);
+ }
+ if (args.fields_len != 0) {
+ astgen.extra.appendAssumeCapacity(args.fields_len);
+ }
+ if (args.decls_len != 0) {
+ astgen.extra.appendAssumeCapacity(args.decls_len);
+ }
+ astgen.instructions.set(inst, .{
+ .tag = .extended,
+ .data = .{ .extended = .{
+ .opcode = .enum_decl,
+ .small = @bitCast(u16, Zir.Inst.EnumDecl.Small{
+ .has_src_node = args.src_node != 0,
+ .has_tag_type = args.tag_type != .none,
+ .has_body_len = args.body_len != 0,
+ .has_fields_len = args.fields_len != 0,
+ .has_decls_len = args.decls_len != 0,
+ .name_strategy = gz.anon_name_strategy,
+ .nonexhaustive = args.nonexhaustive,
+ }),
+ .operand = payload_index,
+ } },
+ });
+ }
+
fn add(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Ref {
return gz.indexToRef(try gz.addAsIndex(inst));
}
fn addAsIndex(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Index {
const gpa = gz.astgen.gpa;
- try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
- try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
+ try gz.instructions.ensureUnusedCapacity(gpa, 1);
+ try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
gz.astgen.instructions.appendAssumeCapacity(inst);
gz.instructions.appendAssumeCapacity(new_index);
return new_index;
}
+
+ fn reserveInstructionIndex(gz: *GenZir) !Zir.Inst.Index {
+ const gpa = gz.astgen.gpa;
+ try gz.instructions.ensureUnusedCapacity(gpa, 1);
+ try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
+
+ const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
+ gz.astgen.instructions.len += 1;
+ gz.instructions.appendAssumeCapacity(new_index);
+ return new_index;
+ }
};
+
+/// This can only be for short-lived references; the memory becomes invalidated
+/// when another string is added.
+fn nullTerminatedString(astgen: AstGen, index: usize) [*:0]const u8 {
+ return @ptrCast([*:0]const u8, astgen.string_bytes.items.ptr) + index;
+}
src/Module.zig
@@ -75,6 +75,8 @@ failed_files: std.AutoArrayHashMapUnmanaged(*Scope.File, ?*ErrorMsg) = .{},
/// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator.
failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{},
+next_anon_name_index: usize = 0,
+
/// Candidates for deletion. After a semantic analysis update completes, this list
/// contains Decls that need to be deleted if they end up having no references to them.
deletion_set: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{},
@@ -884,8 +886,11 @@ pub const Scope = struct {
/// Declaration order is preserved via entry order.
/// Key memory is owned by `decl.name`.
/// TODO save memory with https://github.com/ziglang/zig/issues/8619.
+ /// Anonymous decls are not stored here; they are kept in `anon_decls` instead.
decls: std.StringArrayHashMapUnmanaged(*Decl) = .{},
+ anon_decls: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{},
+
pub fn deinit(ns: *Namespace, mod: *Module) void {
ns.clearDecls(mod);
ns.* = undefined;
@@ -899,15 +904,27 @@ pub const Scope = struct {
var decls = ns.decls;
ns.decls = .{};
+ var anon_decls = ns.anon_decls;
+ ns.anon_decls = .{};
+
for (decls.items()) |entry| {
entry.value.destroy(mod);
}
decls.deinit(gpa);
+
+ for (anon_decls.items()) |entry| {
+ entry.key.destroy(mod);
+ }
+ anon_decls.deinit(gpa);
}
pub fn removeDecl(ns: *Namespace, child: *Decl) void {
- // Preserve declaration order.
- _ = ns.decls.orderedRemove(mem.spanZ(child.name));
+ if (child.zir_decl_index == 0) {
+ _ = ns.anon_decls.swapRemove(child);
+ } else {
+ // Preserve declaration order.
+ _ = ns.decls.orderedRemove(mem.spanZ(child.name));
+ }
}
// This renders e.g. "std.fs.Dir.OpenOptions"
@@ -2607,10 +2624,14 @@ fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !void {
}
if (decl.getInnerNamespace()) |namespace| {
- for (namespace.decls.items()) |*entry| {
+ for (namespace.decls.items()) |entry| {
const sub_decl = entry.value;
try decl_stack.append(gpa, sub_decl);
}
+ for (namespace.anon_decls.items()) |entry| {
+ const sub_decl = entry.key;
+ try decl_stack.append(gpa, sub_decl);
+ }
}
}
}
@@ -3741,31 +3762,17 @@ pub fn constIntBig(mod: *Module, arena: *Allocator, src: LazySrcLoc, ty: Type, b
pub fn createAnonymousDecl(mod: *Module, scope: *Scope, typed_value: TypedValue) !*Decl {
const scope_decl = scope.ownerDecl().?;
const namespace = scope_decl.namespace;
- try namespace.decls.ensureUnusedCapacity(mod.gpa, 1);
-
- // Find a unique name for the anon decl.
- var name_buf = std.ArrayList(u8).init(mod.gpa);
- defer name_buf.deinit();
-
- try name_buf.appendSlice(mem.spanZ(scope_decl.name));
- var name_index: usize = namespace.decls.count();
-
- const new_decl = while (true) {
- const gop = namespace.decls.getOrPutAssumeCapacity(name_buf.items);
- if (!gop.found_existing) {
- const name = try name_buf.toOwnedSliceSentinel(0);
- const new_decl = try mod.allocateNewDecl(namespace, scope_decl.src_node);
- new_decl.name = name;
- gop.entry.key = name;
- gop.entry.value = new_decl;
- break gop.entry.value;
- }
+ try namespace.anon_decls.ensureUnusedCapacity(mod.gpa, 1);
+
+ const name_index = mod.getNextAnonNameIndex();
+ const name = try std.fmt.allocPrintZ(mod.gpa, "{s}__anon_{d}", .{
+ scope_decl.name, name_index,
+ });
+ errdefer mod.gpa.free(name);
- name_buf.clearRetainingCapacity();
- try name_buf.writer().print("{s}__anon_{d}", .{ scope_decl.name, name_index });
- name_index += 1;
- } else unreachable; // TODO should not need else unreachable on while(true)
+ const new_decl = try mod.allocateNewDecl(namespace, scope_decl.src_node);
+ new_decl.name = name;
new_decl.src_line = scope_decl.src_line;
new_decl.ty = typed_value.ty;
new_decl.val = typed_value.val;
@@ -3773,6 +3780,8 @@ pub fn createAnonymousDecl(mod: *Module, scope: *Scope, typed_value: TypedValue)
new_decl.analysis = .complete;
new_decl.generation = mod.generation;
+ namespace.anon_decls.putAssumeCapacityNoClobber(new_decl, {});
+
// TODO: This generates the Decl into the machine code file if it is of a
// type that is non-zero size. We should be able to further improve the
// compiler to omit Decls which are only referenced at compile-time and not runtime.
@@ -3784,6 +3793,10 @@ pub fn createAnonymousDecl(mod: *Module, scope: *Scope, typed_value: TypedValue)
return new_decl;
}
+fn getNextAnonNameIndex(mod: *Module) usize {
+ return @atomicRmw(usize, &mod.next_anon_name_index, .Add, 1, .Monotonic);
+}
+
/// This looks up a bare identifier in the given scope. This will walk up the tree of namespaces
/// in scope and check each one for the identifier.
/// TODO emit a compile error if more than one decl would be matched.
@@ -4394,18 +4407,38 @@ pub fn analyzeStructFields(mod: *Module, struct_obj: *Struct) InnerError!void {
const gpa = mod.gpa;
const zir = struct_obj.owner_decl.namespace.file_scope.zir;
- const inst_data = zir.instructions.items(.data)[struct_obj.zir_index].pl_node;
- const src = inst_data.src();
- const extra = zir.extraData(Zir.Inst.StructDecl, inst_data.payload_index);
- const fields_len = extra.data.fields_len;
- const decls_len = extra.data.decls_len;
+ const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended;
+ assert(extended.opcode == .struct_decl);
+ const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
+ var extra_index: usize = extended.operand;
+
+ const src: LazySrcLoc = .{ .node_offset = struct_obj.node_offset };
+ extra_index += @boolToInt(small.has_src_node);
+
+ const body_len = if (small.has_body_len) blk: {
+ const body_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk body_len;
+ } else 0;
+
+ const fields_len = if (small.has_fields_len) blk: {
+ const fields_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk fields_len;
+ } else 0;
+
+ const decls_len = if (small.has_decls_len) decls_len: {
+ const decls_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :decls_len decls_len;
+ } else 0;
// Skip over decls.
- var decls_it = zir.declIterator(struct_obj.zir_index);
+ var decls_it = zir.declIteratorInner(extra_index, decls_len);
while (decls_it.next()) |_| {}
- var extra_index = decls_it.extra_index;
+ extra_index = decls_it.extra_index;
- const body = zir.extra[extra_index..][0..extra.data.body_len];
+ const body = zir.extra[extra_index..][0..body_len];
if (fields_len == 0) {
assert(body.len == 0);
return;
@@ -4525,18 +4558,44 @@ pub fn analyzeUnionFields(mod: *Module, union_obj: *Union) InnerError!void {
const gpa = mod.gpa;
const zir = union_obj.owner_decl.namespace.file_scope.zir;
- const inst_data = zir.instructions.items(.data)[union_obj.zir_index].pl_node;
- const src = inst_data.src();
- const extra = zir.extraData(Zir.Inst.UnionDecl, inst_data.payload_index);
- const fields_len = extra.data.fields_len;
- const decls_len = extra.data.decls_len;
+ const extended = zir.instructions.items(.data)[union_obj.zir_index].extended;
+ assert(extended.opcode == .union_decl);
+ const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small);
+ var extra_index: usize = extended.operand;
+
+ const src: LazySrcLoc = .{ .node_offset = union_obj.node_offset };
+ extra_index += @boolToInt(small.has_src_node);
+
+ const tag_type_ref = if (small.has_tag_type) blk: {
+ const tag_type_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
+ extra_index += 1;
+ break :blk tag_type_ref;
+ } else .none;
+
+ const body_len = if (small.has_body_len) blk: {
+ const body_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk body_len;
+ } else 0;
+
+ const fields_len = if (small.has_fields_len) blk: {
+ const fields_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk fields_len;
+ } else 0;
+
+ const decls_len = if (small.has_decls_len) decls_len: {
+ const decls_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :decls_len decls_len;
+ } else 0;
// Skip over decls.
- var decls_it = zir.declIterator(union_obj.zir_index);
+ var decls_it = zir.declIteratorInner(extra_index, decls_len);
while (decls_it.next()) |_| {}
- var extra_index = decls_it.extra_index;
+ extra_index = decls_it.extra_index;
- const body = zir.extra[extra_index..][0..extra.data.body_len];
+ const body = zir.extra[extra_index..][0..body_len];
if (fields_len == 0) {
assert(body.len == 0);
return;
@@ -4580,8 +4639,6 @@ pub fn analyzeUnionFields(mod: *Module, union_obj: *Union) InnerError!void {
_ = try sema.analyzeBody(&block, body);
}
- var auto_enum_tag: ?bool = null;
-
const bits_per_field = 4;
const fields_per_u32 = 32 / bits_per_field;
const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
@@ -4603,10 +4660,6 @@ pub fn analyzeUnionFields(mod: *Module, union_obj: *Union) InnerError!void {
const unused = @truncate(u1, cur_bit_bag) != 0;
cur_bit_bag >>= 1;
- if (auto_enum_tag == null) {
- auto_enum_tag = unused;
- }
-
const field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]);
extra_index += 1;
@@ -4653,7 +4706,7 @@ pub fn analyzeUnionFields(mod: *Module, union_obj: *Union) InnerError!void {
}
}
- // TODO resolve the union tag type
+ // TODO resolve the union tag_type_ref
}
/// Called from `performAllTheWork`, after all AstGen workers have finished,
src/Sema.zig
@@ -350,16 +350,12 @@ pub fn analyzeBody(
.trunc => try sema.zirUnaryMath(block, inst),
.round => try sema.zirUnaryMath(block, inst),
- .struct_decl => try sema.zirStructDecl(block, inst, .Auto),
- .struct_decl_packed => try sema.zirStructDecl(block, inst, .Packed),
- .struct_decl_extern => try sema.zirStructDecl(block, inst, .Extern),
- .enum_decl => try sema.zirEnumDecl(block, inst, false),
- .enum_decl_nonexhaustive => try sema.zirEnumDecl(block, inst, true),
- .union_decl => try sema.zirUnionDecl(block, inst, .Auto),
- .union_decl_packed => try sema.zirUnionDecl(block, inst, .Packed),
- .union_decl_extern => try sema.zirUnionDecl(block, inst, .Extern),
- .opaque_decl => try sema.zirOpaqueDecl(block, inst),
- .error_set_decl => try sema.zirErrorSetDecl(block, inst),
+ .opaque_decl => try sema.zirOpaqueDecl(block, inst, .parent),
+ .opaque_decl_anon => try sema.zirOpaqueDecl(block, inst, .anon),
+ .opaque_decl_func => try sema.zirOpaqueDecl(block, inst, .func),
+ .error_set_decl => try sema.zirErrorSetDecl(block, inst, .parent),
+ .error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon),
+ .error_set_decl_func => try sema.zirErrorSetDecl(block, inst, .func),
.add => try sema.zirArithmetic(block, inst),
.addwrap => try sema.zirArithmetic(block, inst),
@@ -515,6 +511,9 @@ fn zirExtended(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro
// zig fmt: off
.func => return sema.zirFuncExtended( block, extended, inst),
.variable => return sema.zirVarExtended( block, extended),
+ .struct_decl => return sema.zirStructDecl( block, extended, inst),
+ .enum_decl => return sema.zirEnumDecl( block, extended),
+ .union_decl => return sema.zirUnionDecl( block, extended, inst),
.ret_ptr => return sema.zirRetPtr( block, extended),
.ret_type => return sema.zirRetType( block, extended),
.this => return sema.zirThis( block, extended),
@@ -686,21 +685,34 @@ pub fn analyzeStructDecl(
inst: Zir.Inst.Index,
struct_obj: *Module.Struct,
) InnerError!void {
- const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
- const extra = sema.code.extraData(Zir.Inst.StructDecl, inst_data.payload_index);
- const decls_len = extra.data.decls_len;
+ const extended = sema.code.instructions.items(.data)[inst].extended;
+ assert(extended.opcode == .struct_decl);
+ const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
+
+ var extra_index: usize = extended.operand;
+ extra_index += @boolToInt(small.has_src_node);
+ extra_index += @boolToInt(small.has_body_len);
+ extra_index += @boolToInt(small.has_fields_len);
+ const decls_len = if (small.has_decls_len) blk: {
+ const decls_len = sema.code.extra[extra_index];
+ extra_index += 1;
+ break :blk decls_len;
+ } else 0;
- _ = try sema.mod.scanNamespace(&struct_obj.namespace, extra.end, decls_len, new_decl);
+ _ = try sema.mod.scanNamespace(&struct_obj.namespace, extra_index, decls_len, new_decl);
}
fn zirStructDecl(
sema: *Sema,
block: *Scope.Block,
+ extended: Zir.Inst.Extended.InstData,
inst: Zir.Inst.Index,
- layout: std.builtin.TypeInfo.ContainerLayout,
) InnerError!*Inst {
- const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
- const src = inst_data.src();
+ const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
+ const src: LazySrcLoc = if (small.has_src_node) blk: {
+ const node_offset = @bitCast(i32, sema.code.extra[extended.operand]);
+ break :blk .{ .node_offset = node_offset };
+ } else sema.src;
var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
@@ -714,9 +726,9 @@ fn zirStructDecl(
struct_obj.* = .{
.owner_decl = new_decl,
.fields = .{},
- .node_offset = inst_data.src_node,
+ .node_offset = src.node_offset,
.zir_index = inst,
- .layout = layout,
+ .layout = small.layout,
.status = .none,
.namespace = .{
.parent = sema.owner_decl.namespace,
@@ -735,27 +747,53 @@ fn zirStructDecl(
fn zirEnumDecl(
sema: *Sema,
block: *Scope.Block,
- inst: Zir.Inst.Index,
- nonexhaustive: bool,
+ extended: Zir.Inst.Extended.InstData,
) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
const gpa = sema.gpa;
- const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
- const src = inst_data.src();
- const extra = sema.code.extraData(Zir.Inst.EnumDecl, inst_data.payload_index);
- const fields_len = extra.data.fields_len;
- const decls_len = extra.data.decls_len;
+ const small = @bitCast(Zir.Inst.EnumDecl.Small, extended.small);
+ var extra_index: usize = extended.operand;
+
+ const src: LazySrcLoc = if (small.has_src_node) blk: {
+ const node_offset = @bitCast(i32, sema.code.extra[extra_index]);
+ extra_index += 1;
+ break :blk .{ .node_offset = node_offset };
+ } else sema.src;
+
+ const tag_type_ref = if (small.has_tag_type) blk: {
+ const tag_type_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
+ extra_index += 1;
+ break :blk tag_type_ref;
+ } else .none;
+
+ const body_len = if (small.has_body_len) blk: {
+ const body_len = sema.code.extra[extra_index];
+ extra_index += 1;
+ break :blk body_len;
+ } else 0;
+
+ const fields_len = if (small.has_fields_len) blk: {
+ const fields_len = sema.code.extra[extra_index];
+ extra_index += 1;
+ break :blk fields_len;
+ } else 0;
+
+ const decls_len = if (small.has_decls_len) blk: {
+ const decls_len = sema.code.extra[extra_index];
+ extra_index += 1;
+ break :blk decls_len;
+ } else 0;
var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
const tag_ty = blk: {
- if (extra.data.tag_type != .none) {
+ if (tag_type_ref != .none) {
// TODO better source location
// TODO (needs AstGen fix too) move this eval to the block so it gets allocated
// in the new decl arena.
- break :blk try sema.resolveType(block, src, extra.data.tag_type);
+ break :blk try sema.resolveType(block, src, tag_type_ref);
}
const bits = std.math.log2_int_ceil(usize, fields_len);
break :blk try Type.Tag.int_unsigned.create(&new_decl_arena.allocator, bits);
@@ -764,7 +802,7 @@ fn zirEnumDecl(
const enum_obj = try new_decl_arena.allocator.create(Module.EnumFull);
const enum_ty_payload = try new_decl_arena.allocator.create(Type.Payload.EnumFull);
enum_ty_payload.* = .{
- .base = .{ .tag = if (nonexhaustive) .enum_nonexhaustive else .enum_full },
+ .base = .{ .tag = if (small.nonexhaustive) .enum_nonexhaustive else .enum_full },
.data = enum_obj,
};
const enum_ty = Type.initPayload(&enum_ty_payload.base);
@@ -778,7 +816,7 @@ fn zirEnumDecl(
.tag_ty = tag_ty,
.fields = .{},
.values = .{},
- .node_offset = inst_data.src_node,
+ .node_offset = src.node_offset,
.namespace = .{
.parent = sema.owner_decl.namespace,
.ty = enum_ty,
@@ -789,14 +827,9 @@ fn zirEnumDecl(
&enum_obj.namespace, new_decl, new_decl.name,
});
- var extra_index: usize = try sema.mod.scanNamespace(
- &enum_obj.namespace,
- extra.end,
- decls_len,
- new_decl,
- );
+ extra_index = try sema.mod.scanNamespace(&enum_obj.namespace, extra_index, decls_len, new_decl);
- const body = sema.code.extra[extra_index..][0..extra.data.body_len];
+ const body = sema.code.extra[extra_index..][0..body_len];
if (fields_len == 0) {
assert(body.len == 0);
try new_decl.finalizeNewArena(&new_decl_arena);
@@ -894,16 +927,30 @@ fn zirEnumDecl(
fn zirUnionDecl(
sema: *Sema,
block: *Scope.Block,
+ extended: Zir.Inst.Extended.InstData,
inst: Zir.Inst.Index,
- layout: std.builtin.TypeInfo.ContainerLayout,
) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
- const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
- const src = inst_data.src();
- const extra = sema.code.extraData(Zir.Inst.UnionDecl, inst_data.payload_index);
- const decls_len = extra.data.decls_len;
+ const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small);
+ var extra_index: usize = extended.operand;
+
+ const src: LazySrcLoc = if (small.has_src_node) blk: {
+ const node_offset = @bitCast(i32, sema.code.extra[extra_index]);
+ extra_index += 1;
+ break :blk .{ .node_offset = node_offset };
+ } else sema.src;
+
+ extra_index += @boolToInt(small.has_tag_type);
+ extra_index += @boolToInt(small.has_body_len);
+ extra_index += @boolToInt(small.has_fields_len);
+
+ const decls_len = if (small.has_decls_len) blk: {
+ const decls_len = sema.code.extra[extra_index];
+ extra_index += 1;
+ break :blk decls_len;
+ } else 0;
var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
@@ -918,9 +965,9 @@ fn zirUnionDecl(
.owner_decl = new_decl,
.tag_ty = Type.initTag(.@"null"),
.fields = .{},
- .node_offset = inst_data.src_node,
+ .node_offset = src.node_offset,
.zir_index = inst,
- .layout = layout,
+ .layout = small.layout,
.status = .none,
.namespace = .{
.parent = sema.owner_decl.namespace,
@@ -932,13 +979,18 @@ fn zirUnionDecl(
&union_obj.namespace, new_decl, new_decl.name,
});
- _ = try sema.mod.scanNamespace(&union_obj.namespace, extra.end, decls_len, new_decl);
+ _ = try sema.mod.scanNamespace(&union_obj.namespace, extra_index, decls_len, new_decl);
try new_decl.finalizeNewArena(&new_decl_arena);
return sema.analyzeDeclVal(block, src, new_decl);
}
-fn zirOpaqueDecl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+fn zirOpaqueDecl(
+ sema: *Sema,
+ block: *Scope.Block,
+ inst: Zir.Inst.Index,
+ name_strategy: Zir.Inst.NameStrategy,
+) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
@@ -949,7 +1001,12 @@ fn zirOpaqueDecl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerEr
return sema.mod.fail(&block.base, sema.src, "TODO implement zirOpaqueDecl", .{});
}
-fn zirErrorSetDecl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+fn zirErrorSetDecl(
+ sema: *Sema,
+ block: *Scope.Block,
+ inst: Zir.Inst.Index,
+ name_strategy: Zir.Inst.NameStrategy,
+) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
src/Zir.zig
@@ -296,34 +296,16 @@ pub const Inst = struct {
/// only the taken branch is analyzed. The then block and else block must
/// terminate with an "inline" variant of a noreturn instruction.
condbr_inline,
- /// A struct type definition. Contains references to ZIR instructions for
- /// the field types, defaults, and alignments.
- /// Uses the `pl_node` union field. Payload is `StructDecl`.
- struct_decl,
- /// Same as `struct_decl`, except has the `packed` layout.
- struct_decl_packed,
- /// Same as `struct_decl`, except has the `extern` layout.
- struct_decl_extern,
- /// A union type definition. Contains references to ZIR instructions for
- /// the field types and optional type tag expression.
- /// Uses the `pl_node` union field. Payload is `UnionDecl`.
- union_decl,
- /// Same as `union_decl`, except has the `packed` layout.
- union_decl_packed,
- /// Same as `union_decl`, except has the `extern` layout.
- union_decl_extern,
- /// An enum type definition. Contains references to ZIR instructions for
- /// the field value expressions and optional type tag expression.
- /// Uses the `pl_node` union field. Payload is `EnumDecl`.
- enum_decl,
- /// Same as `enum_decl`, except the enum is non-exhaustive.
- enum_decl_nonexhaustive,
/// An opaque type definition. Provides an AST node only.
/// Uses the `pl_node` union field. Payload is `OpaqueDecl`.
opaque_decl,
+ opaque_decl_anon,
+ opaque_decl_func,
/// An error set type definition. Contains a list of field names.
/// Uses the `pl_node` union field. Payload is `ErrorSetDecl`.
error_set_decl,
+ error_set_decl_anon,
+ error_set_decl_func,
/// Declares the beginning of a statement. Used for debug info.
/// Uses the `dbg_stmt` union field. The line and column are offset
/// from the parent declaration.
@@ -1011,16 +993,12 @@ pub const Inst = struct {
.cmp_gt,
.cmp_neq,
.coerce_result_ptr,
- .struct_decl,
- .struct_decl_packed,
- .struct_decl_extern,
- .union_decl,
- .union_decl_packed,
- .union_decl_extern,
- .enum_decl,
- .enum_decl_nonexhaustive,
.opaque_decl,
+ .opaque_decl_anon,
+ .opaque_decl_func,
.error_set_decl,
+ .error_set_decl_anon,
+ .error_set_decl_func,
.dbg_stmt,
.decl_ref,
.decl_val,
@@ -1271,16 +1249,12 @@ pub const Inst = struct {
.coerce_result_ptr = .bin,
.condbr = .pl_node,
.condbr_inline = .pl_node,
- .struct_decl = .pl_node,
- .struct_decl_packed = .pl_node,
- .struct_decl_extern = .pl_node,
- .union_decl = .pl_node,
- .union_decl_packed = .pl_node,
- .union_decl_extern = .pl_node,
- .enum_decl = .pl_node,
- .enum_decl_nonexhaustive = .pl_node,
.opaque_decl = .pl_node,
+ .opaque_decl_anon = .pl_node,
+ .opaque_decl_func = .pl_node,
.error_set_decl = .pl_node,
+ .error_set_decl_anon = .pl_node,
+ .error_set_decl_func = .pl_node,
.dbg_stmt = .dbg_stmt,
.decl_ref = .str_tok,
.decl_val = .str_tok,
@@ -1507,6 +1481,21 @@ pub const Inst = struct {
/// `operand` is payload index to `ExtendedVar`.
/// `small` is `ExtendedVar.Small`.
variable,
+ /// A struct type definition. Contains references to ZIR instructions for
+ /// the field types, defaults, and alignments.
+ /// `operand` is payload index to `StructDecl`.
+ /// `small` is `StructDecl.Small`.
+ struct_decl,
+ /// An enum type definition. Contains references to ZIR instructions for
+ /// the field value expressions and optional type tag expression.
+ /// `operand` is payload index to `EnumDecl`.
+ /// `small` is `EnumDecl.Small`.
+ enum_decl,
+ /// A union type definition. Contains references to ZIR instructions for
+ /// the field types and optional type tag expression.
+ /// `operand` is payload index to `UnionDecl`.
+ /// `small` is `UnionDecl.Small`.
+ union_decl,
/// Obtains a pointer to the return value.
/// `operand` is `src_node: i32`.
ret_ptr,
@@ -2251,9 +2240,9 @@ pub const Inst = struct {
body_len: u32,
pub const SrcLocs = struct {
- /// Absolute line number in the source file.
+ /// Absolute line index in the source file.
lbrace_line: u32,
- /// Absolute line number in the source file.
+ /// Absolute line index in the source file.
rbrace_line: u32,
/// lbrace_column is least significant bits u16
/// rbrace_column is most significant bits u16
@@ -2414,13 +2403,17 @@ pub const Inst = struct {
};
/// Trailing:
- /// 0. decl_bits: u32 // for every 8 decls
+ /// 0. src_node: i32, // if has_src_node
+ /// 1. body_len: u32, // if has_body_len
+ /// 2. fields_len: u32, // if has_fields_len
+ /// 3. decls_len: u32, // if has_decls_len
+ /// 4. 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 expression
- /// 1. decl: { // for every decls_len
+ /// 5. decl: { // for every decls_len
/// src_hash: [4]u32, // hash of source bytes
/// line: u32, // line number of decl, relative to parent
/// name: u32, // null terminated string index
@@ -2433,14 +2426,14 @@ pub const Inst = struct {
/// align: Ref, // if corresponding bit is set
/// link_section: Ref, // if corresponding bit is set
/// }
- /// 2. inst: Index // for every body_len
- /// 3. flags: u32 // for every 8 fields
+ /// 6. inst: Index // for every body_len
+ /// 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: unused
- /// 4. fields: { // for every fields_len
+ /// 8. fields: { // for every fields_len
/// field_name: u32,
/// field_type: Ref,
/// - if none, means `anytype`.
@@ -2448,19 +2441,42 @@ pub const Inst = struct {
/// default_value: Ref, // if corresponding bit is set
/// }
pub const StructDecl = struct {
- body_len: u32,
- fields_len: u32,
- decls_len: u32,
+ pub const Small = packed struct {
+ has_src_node: bool,
+ has_body_len: bool,
+ has_fields_len: bool,
+ has_decls_len: bool,
+ name_strategy: NameStrategy,
+ layout: std.builtin.TypeInfo.ContainerLayout,
+ _: u8 = undefined,
+ };
+ };
+
+ pub const NameStrategy = enum(u2) {
+ /// Use the same name as the parent declaration name.
+ /// e.g. `const Foo = struct {...};`.
+ parent,
+ /// Use the name of the currently executing comptime function call,
+ /// with the current parameters. e.g. `ArrayList(i32)`.
+ func,
+ /// Create an anonymous name for this declaration.
+ /// Like this: "ParentDeclName_struct_69"
+ anon,
};
/// Trailing:
- /// 0. decl_bits: u32 // for every 8 decls
+ /// 0. src_node: i32, // if has_src_node
+ /// 1. tag_type: Ref, // if has_tag_type
+ /// 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 expression
- /// 1. decl: { // for every decls_len
+ /// 6. decl: { // for every decls_len
/// src_hash: [4]u32, // hash of source bytes
/// line: u32, // line number of decl, relative to parent
/// name: u32, // null terminated string index
@@ -2473,29 +2489,39 @@ pub const Inst = struct {
/// align: Ref, // if corresponding bit is set
/// link_section: Ref, // if corresponding bit is set
/// }
- /// 2. inst: Index // for every body_len
- /// 3. has_bits: u32 // for every 32 fields
+ /// 7. inst: Index // for every body_len
+ /// 8. has_bits: u32 // for every 32 fields
/// - the bit is whether corresponding field has an value expression
- /// 4. fields: { // for every fields_len
+ /// 9. fields: { // for every fields_len
/// field_name: u32,
/// value: Ref, // if corresponding bit is set
/// }
pub const EnumDecl = struct {
- /// Can be `Ref.none`.
- tag_type: Ref,
- body_len: u32,
- fields_len: u32,
- decls_len: u32,
+ pub const Small = packed struct {
+ has_src_node: bool,
+ has_tag_type: bool,
+ has_body_len: bool,
+ has_fields_len: bool,
+ has_decls_len: bool,
+ name_strategy: NameStrategy,
+ nonexhaustive: bool,
+ _: u8 = undefined,
+ };
};
/// Trailing:
- /// 0. decl_bits: u32 // for every 8 decls
+ /// 0. src_node: i32, // if has_src_node
+ /// 1. tag_type: Ref, // if has_tag_type
+ /// 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 expression
- /// 1. decl: { // for every decls_len
+ /// 6. decl: { // for every decls_len
/// src_hash: [4]u32, // hash of source bytes
/// line: u32, // line number of decl, relative to parent
/// name: u32, // null terminated string index
@@ -2508,29 +2534,33 @@ pub const Inst = struct {
/// align: Ref, // if corresponding bit is set
/// link_section: Ref, // if corresponding bit is set
/// }
- /// 2. inst: Index // for every body_len
- /// 3. has_bits: u32 // for every 8 fields
+ /// 7. inst: Index // for every body_len
+ /// 8. 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(*)
- /// * the first unused bit (the unused bit of the first field) is used
- /// to indicate whether auto enum tag is enabled.
- /// 0 = union(tag_type)
- /// 1 = union(enum(tag_type))
- /// 4. fields: { // for every fields_len
+ /// 0bX000: unused
+ /// 9. fields: { // for every fields_len
/// field_name: u32, // null terminated string index
/// field_type: Ref, // if corresponding bit is set
/// align: Ref, // if corresponding bit is set
/// tag_value: Ref, // if corresponding bit is set
/// }
pub const UnionDecl = struct {
- /// Can be `Ref.none`.
- tag_type: Ref,
- body_len: u32,
- fields_len: u32,
- decls_len: u32,
+ pub const Small = packed struct {
+ has_src_node: bool,
+ has_tag_type: bool,
+ has_body_len: bool,
+ has_fields_len: bool,
+ has_decls_len: bool,
+ name_strategy: NameStrategy,
+ layout: std.builtin.TypeInfo.ContainerLayout,
+ /// false: union(tag_type)
+ /// true: union(enum(tag_type))
+ auto_enum_tag: bool,
+ _: u6 = undefined,
+ };
};
/// Trailing:
@@ -2901,8 +2931,6 @@ const Writer = struct {
.field_type => try self.writeFieldType(stream, inst),
.field_type_ref => try self.writeFieldTypeRef(stream, inst),
- .error_set_decl => try self.writePlNodeErrorSetDecl(stream, inst),
-
.add,
.addwrap,
.array_cat,
@@ -2980,21 +3008,13 @@ const Writer = struct {
.condbr_inline,
=> try self.writePlNodeCondBr(stream, inst),
- .struct_decl,
- .struct_decl_packed,
- .struct_decl_extern,
- => try self.writeStructDecl(stream, inst),
-
- .union_decl,
- .union_decl_packed,
- .union_decl_extern,
- => try self.writeUnionDecl(stream, inst),
-
- .enum_decl,
- .enum_decl_nonexhaustive,
- => try self.writeEnumDecl(stream, inst),
+ .opaque_decl => try self.writeOpaqueDecl(stream, inst, .parent),
+ .opaque_decl_anon => try self.writeOpaqueDecl(stream, inst, .anon),
+ .opaque_decl_func => try self.writeOpaqueDecl(stream, inst, .func),
- .opaque_decl => try self.writeOpaqueDecl(stream, inst),
+ .error_set_decl => try self.writeErrorSetDecl(stream, inst, .parent),
+ .error_set_decl_anon => try self.writeErrorSetDecl(stream, inst, .anon),
+ .error_set_decl_func => try self.writeErrorSetDecl(stream, inst, .func),
.switch_block => try self.writePlNodeSwitchBr(stream, inst, .none),
.switch_block_else => try self.writePlNodeSwitchBr(stream, inst, .@"else"),
@@ -3080,6 +3100,10 @@ const Writer = struct {
.shl_with_overflow,
=> try self.writeOverflowArithmetic(stream, extended),
+ .struct_decl => try self.writeStructDecl(stream, extended),
+ .union_decl => try self.writeUnionDecl(stream, extended),
+ .enum_decl => try self.writeEnumDecl(stream, extended),
+
.alloc,
.builtin_extern,
.c_undef,
@@ -3315,25 +3339,6 @@ const Writer = struct {
try self.writeSrc(stream, inst_data.src());
}
- fn writePlNodeErrorSetDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {
- const inst_data = self.code.instructions.items(.data)[inst].pl_node;
- const extra = self.code.extraData(Inst.ErrorSetDecl, inst_data.payload_index);
- const fields = self.code.extra[extra.end..][0..extra.data.fields_len];
-
- try stream.writeAll("{\n");
- self.indent += 2;
- for (fields) |str_index| {
- const name = self.code.nullTerminatedString(str_index);
- try stream.writeByteNTimes(' ', self.indent);
- try stream.print("{},\n", .{std.zig.fmtId(name)});
- }
- self.indent -= 2;
- try stream.writeByteNTimes(' ', self.indent);
- try stream.writeAll("}) ");
-
- try self.writeSrc(stream, inst_data.src());
- }
-
fn writeNodeMultiOp(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void {
const extra = self.code.extraData(Inst.NodeMultiOp, extended.operand);
const src: LazySrcLoc = .{ .node_offset = extra.data.src_node };
@@ -3483,33 +3488,56 @@ const Writer = struct {
try self.writeSrc(stream, inst_data.src());
}
- fn writeStructDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {
- const inst_data = self.code.instructions.items(.data)[inst].pl_node;
- const extra = self.code.extraData(Inst.StructDecl, inst_data.payload_index);
- const fields_len = extra.data.fields_len;
- const decls_len = extra.data.decls_len;
+ fn writeStructDecl(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void {
+ const small = @bitCast(Inst.StructDecl.Small, extended.small);
+
+ var extra_index: usize = extended.operand;
+
+ const src_node: ?i32 = if (small.has_src_node) blk: {
+ const src_node = @bitCast(i32, self.code.extra[extra_index]);
+ extra_index += 1;
+ break :blk src_node;
+ } else null;
+
+ const body_len = if (small.has_body_len) blk: {
+ const body_len = self.code.extra[extra_index];
+ extra_index += 1;
+ break :blk body_len;
+ } else 0;
- var extra_index: usize = undefined;
+ const fields_len = if (small.has_fields_len) blk: {
+ const fields_len = self.code.extra[extra_index];
+ extra_index += 1;
+ break :blk fields_len;
+ } else 0;
+
+ const decls_len = if (small.has_decls_len) blk: {
+ const decls_len = self.code.extra[extra_index];
+ extra_index += 1;
+ break :blk decls_len;
+ } else 0;
+
+ try stream.print("{s}, {s}, ", .{
+ @tagName(small.name_strategy), @tagName(small.layout),
+ });
if (decls_len == 0) {
try stream.writeAll("{}, ");
- extra_index = extra.end;
} else {
try stream.writeAll("{\n");
self.indent += 2;
- extra_index = try self.writeDecls(stream, decls_len, extra.end);
+ extra_index = try self.writeDecls(stream, decls_len, extra_index);
self.indent -= 2;
try stream.writeByteNTimes(' ', self.indent);
try stream.writeAll("}, ");
}
- const body = self.code.extra[extra_index..][0..extra.data.body_len];
+ const body = self.code.extra[extra_index..][0..body_len];
extra_index += body.len;
if (fields_len == 0) {
assert(body.len == 0);
- try stream.writeAll("{}, {}) ");
- extra_index = extra.end;
+ try stream.writeAll("{}, {})");
} else {
self.indent += 2;
if (body.len == 0) {
@@ -3575,41 +3603,70 @@ const Writer = struct {
self.indent -= 2;
try stream.writeByteNTimes(' ', self.indent);
- try stream.writeAll("}) ");
+ try stream.writeAll("})");
}
- try self.writeSrc(stream, inst_data.src());
+ try self.writeSrcNode(stream, src_node);
}
- fn writeUnionDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {
- const inst_data = self.code.instructions.items(.data)[inst].pl_node;
- const extra = self.code.extraData(Inst.UnionDecl, inst_data.payload_index);
- const fields_len = extra.data.fields_len;
- const decls_len = extra.data.decls_len;
- const tag_type_ref = extra.data.tag_type;
+ fn writeUnionDecl(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void {
+ const small = @bitCast(Inst.UnionDecl.Small, extended.small);
+
+ var extra_index: usize = extended.operand;
+
+ const src_node: ?i32 = if (small.has_src_node) blk: {
+ const src_node = @bitCast(i32, self.code.extra[extra_index]);
+ extra_index += 1;
+ break :blk src_node;
+ } else null;
+
+ const tag_type_ref = if (small.has_tag_type) blk: {
+ const tag_type_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
+ extra_index += 1;
+ break :blk tag_type_ref;
+ } else .none;
+
+ const body_len = if (small.has_body_len) blk: {
+ const body_len = self.code.extra[extra_index];
+ extra_index += 1;
+ break :blk body_len;
+ } else 0;
+
+ const fields_len = if (small.has_fields_len) blk: {
+ const fields_len = self.code.extra[extra_index];
+ extra_index += 1;
+ break :blk fields_len;
+ } else 0;
- var extra_index: usize = undefined;
+ const decls_len = if (small.has_decls_len) blk: {
+ const decls_len = self.code.extra[extra_index];
+ extra_index += 1;
+ break :blk decls_len;
+ } else 0;
+
+ try stream.print("{s}, {s}, ", .{
+ @tagName(small.name_strategy), @tagName(small.layout),
+ });
+ try self.writeFlag(stream, "autoenum, ", small.auto_enum_tag);
if (decls_len == 0) {
try stream.writeAll("{}, ");
- extra_index = extra.end;
} else {
try stream.writeAll("{\n");
self.indent += 2;
- extra_index = try self.writeDecls(stream, decls_len, extra.end);
+ extra_index = try self.writeDecls(stream, decls_len, extra_index);
self.indent -= 2;
try stream.writeByteNTimes(' ', self.indent);
try stream.writeAll("}, ");
}
assert(fields_len != 0);
- var first_has_auto_enum: ?bool = null;
if (tag_type_ref != .none) {
try self.writeInstRef(stream, tag_type_ref);
try stream.writeAll(", ");
}
- const body = self.code.extra[extra_index..][0..extra.data.body_len];
+ const body = self.code.extra[extra_index..][0..body_len];
extra_index += body.len;
self.indent += 2;
@@ -3642,12 +3699,10 @@ const Writer = struct {
cur_bit_bag >>= 1;
const has_value = @truncate(u1, cur_bit_bag) != 0;
cur_bit_bag >>= 1;
- const has_auto_enum = @truncate(u1, cur_bit_bag) != 0;
+ const unused = @truncate(u1, cur_bit_bag) != 0;
cur_bit_bag >>= 1;
- if (first_has_auto_enum == null) {
- first_has_auto_enum = has_auto_enum;
- }
+ _ = unused;
const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
extra_index += 1;
@@ -3681,10 +3736,8 @@ const Writer = struct {
self.indent -= 2;
try stream.writeByteNTimes(' ', self.indent);
- try stream.writeAll("}");
- try self.writeFlag(stream, ", autoenum", first_has_auto_enum.?);
- try stream.writeAll(") ");
- try self.writeSrc(stream, inst_data.src());
+ try stream.writeAll("})");
+ try self.writeSrcNode(stream, src_node);
}
fn writeDecls(self: *Writer, stream: anytype, decls_len: u32, extra_start: usize) !usize {
@@ -3776,22 +3829,49 @@ const Writer = struct {
return extra_index;
}
- fn writeEnumDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {
- const inst_data = self.code.instructions.items(.data)[inst].pl_node;
- const extra = self.code.extraData(Inst.EnumDecl, inst_data.payload_index);
- const fields_len = extra.data.fields_len;
- const decls_len = extra.data.decls_len;
- const tag_type_ref = extra.data.tag_type;
+ fn writeEnumDecl(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void {
+ const small = @bitCast(Inst.EnumDecl.Small, extended.small);
+ var extra_index: usize = extended.operand;
+
+ const src_node: ?i32 = if (small.has_src_node) blk: {
+ const src_node = @bitCast(i32, self.code.extra[extra_index]);
+ extra_index += 1;
+ break :blk src_node;
+ } else null;
+
+ const tag_type_ref = if (small.has_tag_type) blk: {
+ const tag_type_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
+ extra_index += 1;
+ break :blk tag_type_ref;
+ } else .none;
+
+ const body_len = if (small.has_body_len) blk: {
+ const body_len = self.code.extra[extra_index];
+ extra_index += 1;
+ break :blk body_len;
+ } else 0;
+
+ const fields_len = if (small.has_fields_len) blk: {
+ const fields_len = self.code.extra[extra_index];
+ extra_index += 1;
+ break :blk fields_len;
+ } else 0;
+
+ const decls_len = if (small.has_decls_len) blk: {
+ const decls_len = self.code.extra[extra_index];
+ extra_index += 1;
+ break :blk decls_len;
+ } else 0;
- var extra_index: usize = undefined;
+ try stream.print("{s}, ", .{@tagName(small.name_strategy)});
+ try self.writeFlag(stream, "nonexhaustive, ", small.nonexhaustive);
if (decls_len == 0) {
try stream.writeAll("{}, ");
- extra_index = extra.end;
} else {
try stream.writeAll("{\n");
self.indent += 2;
- extra_index = try self.writeDecls(stream, decls_len, extra.end);
+ extra_index = try self.writeDecls(stream, decls_len, extra_index);
self.indent -= 2;
try stream.writeByteNTimes(' ', self.indent);
try stream.writeAll("}, ");
@@ -3802,12 +3882,12 @@ const Writer = struct {
try stream.writeAll(", ");
}
- const body = self.code.extra[extra_index..][0..extra.data.body_len];
+ const body = self.code.extra[extra_index..][0..body_len];
extra_index += body.len;
if (fields_len == 0) {
assert(body.len == 0);
- try stream.writeAll("{}, {}) ");
+ try stream.writeAll("{}, {})");
} else {
self.indent += 2;
if (body.len == 0) {
@@ -3851,16 +3931,23 @@ const Writer = struct {
}
self.indent -= 2;
try stream.writeByteNTimes(' ', self.indent);
- try stream.writeAll("}) ");
+ try stream.writeAll("})");
}
- try self.writeSrc(stream, inst_data.src());
+ try self.writeSrcNode(stream, src_node);
}
- fn writeOpaqueDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {
+ fn writeOpaqueDecl(
+ self: *Writer,
+ stream: anytype,
+ inst: Inst.Index,
+ name_strategy: Inst.NameStrategy,
+ ) !void {
const inst_data = self.code.instructions.items(.data)[inst].pl_node;
const extra = self.code.extraData(Inst.OpaqueDecl, inst_data.payload_index);
const decls_len = extra.data.decls_len;
+ try stream.print("{s}, ", .{@tagName(name_strategy)});
+
if (decls_len == 0) {
try stream.writeAll("}) ");
} else {
@@ -3874,6 +3961,32 @@ const Writer = struct {
try self.writeSrc(stream, inst_data.src());
}
+ fn writeErrorSetDecl(
+ self: *Writer,
+ stream: anytype,
+ inst: Inst.Index,
+ name_strategy: Inst.NameStrategy,
+ ) !void {
+ const inst_data = self.code.instructions.items(.data)[inst].pl_node;
+ const extra = self.code.extraData(Inst.ErrorSetDecl, inst_data.payload_index);
+ const fields = self.code.extra[extra.end..][0..extra.data.fields_len];
+
+ try stream.print("{s}, ", .{@tagName(name_strategy)});
+
+ try stream.writeAll("{\n");
+ self.indent += 2;
+ for (fields) |str_index| {
+ const name = self.code.nullTerminatedString(str_index);
+ try stream.writeByteNTimes(' ', self.indent);
+ try stream.print("{},\n", .{std.zig.fmtId(name)});
+ }
+ self.indent -= 2;
+ try stream.writeByteNTimes(' ', self.indent);
+ try stream.writeAll("}) ");
+
+ try self.writeSrc(stream, inst_data.src());
+ }
+
fn writePlNodeSwitchBr(
self: *Writer,
stream: anytype,
@@ -4337,6 +4450,13 @@ const Writer = struct {
});
}
+ fn writeSrcNode(self: *Writer, stream: anytype, src_node: ?i32) !void {
+ const node_offset = src_node orelse return;
+ const src: LazySrcLoc = .{ .node_offset = node_offset };
+ try stream.writeAll(" ");
+ return self.writeSrc(stream, src);
+ }
+
fn writeBody(self: *Writer, stream: anytype, body: []const Inst.Index) !void {
for (body) |inst| {
try stream.writeByteNTimes(' ', self.indent);
@@ -4389,75 +4509,86 @@ pub const DeclIterator = struct {
pub fn declIterator(zir: Zir, decl_inst: u32) DeclIterator {
const tags = zir.instructions.items(.tag);
const datas = zir.instructions.items(.data);
- const decl_info: struct {
- extra_index: usize,
- decls_len: u32,
- } = switch (tags[decl_inst]) {
- .struct_decl,
- .struct_decl_packed,
- .struct_decl_extern,
- => blk: {
- const inst_data = datas[decl_inst].pl_node;
- const extra = zir.extraData(Inst.StructDecl, inst_data.payload_index);
- break :blk .{
- .extra_index = extra.end,
- .decls_len = extra.data.decls_len,
- };
- },
-
- .union_decl,
- .union_decl_packed,
- .union_decl_extern,
- => blk: {
- const inst_data = datas[decl_inst].pl_node;
- const extra = zir.extraData(Inst.UnionDecl, inst_data.payload_index);
- break :blk .{
- .extra_index = extra.end,
- .decls_len = extra.data.decls_len,
- };
- },
-
- .enum_decl,
- .enum_decl_nonexhaustive,
- => blk: {
- const inst_data = datas[decl_inst].pl_node;
- const extra = zir.extraData(Inst.EnumDecl, inst_data.payload_index);
- break :blk .{
- .extra_index = extra.end,
- .decls_len = extra.data.decls_len,
- };
- },
-
- .opaque_decl => blk: {
+ switch (tags[decl_inst]) {
+ .opaque_decl,
+ .opaque_decl_anon,
+ .opaque_decl_func,
+ => {
const inst_data = datas[decl_inst].pl_node;
const extra = zir.extraData(Inst.OpaqueDecl, inst_data.payload_index);
- break :blk .{
- .extra_index = extra.end,
- .decls_len = extra.data.decls_len,
- };
+ return declIteratorInner(zir, extra.end, extra.data.decls_len);
},
// Functions are allowed and yield no iterations.
+ // There is one case matching this in the extended instruction set below.
.func,
.func_inferred,
- .extended, // assume also a function
- => .{
- .extra_index = 0,
- .decls_len = 0,
- },
+ => return declIteratorInner(zir, 0, 0),
+ .extended => {
+ const extended = datas[decl_inst].extended;
+ switch (extended.opcode) {
+ .func => return declIteratorInner(zir, 0, 0),
+ .struct_decl => {
+ const small = @bitCast(Inst.StructDecl.Small, extended.small);
+ var extra_index: usize = extended.operand;
+ extra_index += @boolToInt(small.has_src_node);
+ extra_index += @boolToInt(small.has_body_len);
+ extra_index += @boolToInt(small.has_fields_len);
+ const decls_len = if (small.has_decls_len) decls_len: {
+ const decls_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :decls_len decls_len;
+ } else 0;
+
+ return declIteratorInner(zir, extra_index, decls_len);
+ },
+ .enum_decl => {
+ const small = @bitCast(Inst.EnumDecl.Small, extended.small);
+ var extra_index: usize = extended.operand;
+ extra_index += @boolToInt(small.has_src_node);
+ extra_index += @boolToInt(small.has_tag_type);
+ extra_index += @boolToInt(small.has_body_len);
+ extra_index += @boolToInt(small.has_fields_len);
+ const decls_len = if (small.has_decls_len) decls_len: {
+ const decls_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :decls_len decls_len;
+ } else 0;
+
+ return declIteratorInner(zir, extra_index, decls_len);
+ },
+ .union_decl => {
+ const small = @bitCast(Inst.UnionDecl.Small, extended.small);
+ var extra_index: usize = extended.operand;
+ extra_index += @boolToInt(small.has_src_node);
+ extra_index += @boolToInt(small.has_tag_type);
+ extra_index += @boolToInt(small.has_body_len);
+ extra_index += @boolToInt(small.has_fields_len);
+ const decls_len = if (small.has_decls_len) decls_len: {
+ const decls_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :decls_len decls_len;
+ } else 0;
+
+ return declIteratorInner(zir, extra_index, decls_len);
+ },
+ else => unreachable,
+ }
+ },
else => unreachable,
- };
-
- const bit_bags_count = std.math.divCeil(usize, decl_info.decls_len, 8) catch unreachable;
+ }
+}
+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 = decl_info.extra_index + bit_bags_count,
- .bit_bag_index = decl_info.extra_index,
+ .extra_index = extra_index + bit_bags_count,
+ .bit_bag_index = extra_index,
.cur_bit_bag = undefined,
.decl_i = 0,
- .decls_len = decl_info.decls_len,
+ .decls_len = decls_len,
};
}
@@ -4480,15 +4611,10 @@ fn findDeclsInner(
switch (tags[inst]) {
// Decl instructions are interesting but have no body.
- .struct_decl,
- .struct_decl_packed,
- .struct_decl_extern,
- .union_decl,
- .union_decl_packed,
- .union_decl_extern,
- .enum_decl,
- .enum_decl_nonexhaustive,
+ // TODO yes they do have a body actually. recurse over them just like block instructions.
.opaque_decl,
+ .opaque_decl_anon,
+ .opaque_decl_func,
=> return list.append(inst),
// Functions instructions are interesting and have a body.
@@ -4505,19 +4631,28 @@ fn findDeclsInner(
},
.extended => {
const extended = datas[inst].extended;
- if (extended.opcode != .func) return;
+ switch (extended.opcode) {
+ .func => {
+ try list.append(inst);
+
+ const extra = zir.extraData(Inst.ExtendedFunc, extended.operand);
+ const small = @bitCast(Inst.ExtendedFunc.Small, extended.small);
+ var extra_index: usize = extra.end;
+ extra_index += @boolToInt(small.has_lib_name);
+ extra_index += @boolToInt(small.has_cc);
+ extra_index += @boolToInt(small.has_align);
+ extra_index += extra.data.param_types_len;
+ const body = zir.extra[extra_index..][0..extra.data.body_len];
+ return zir.findDeclsBody(list, body);
+ },
- try list.append(inst);
+ .struct_decl,
+ .union_decl,
+ .enum_decl,
+ => return list.append(inst),
- const extra = zir.extraData(Inst.ExtendedFunc, extended.operand);
- const small = @bitCast(Inst.ExtendedFunc.Small, extended.small);
- var extra_index: usize = extra.end;
- extra_index += @boolToInt(small.has_lib_name);
- extra_index += @boolToInt(small.has_cc);
- extra_index += @boolToInt(small.has_align);
- extra_index += extra.data.param_types_len;
- const body = zir.extra[extra_index..][0..extra.data.body_len];
- return zir.findDeclsBody(list, body);
+ else => return,
+ }
},
// Block instructions, recurse over the bodies.
BRANCH_TODO
@@ -65,3 +65,6 @@
* use ZIR memory for decl names where possible and also for keys
- this will require more sophisticated changelist detection which does some
pre-emptive deletion of decls from the parent namespace
+
+ * better anonymous Decl naming convention
+ - avoid the global atomic integer for the number because of contention