mirror of
https://github.com/ziglang/zig.git
synced 2025-12-28 17:13:19 +00:00
stage2: AstGen and ZIR printing for struct decls
This commit is contained in:
parent
09000c3f77
commit
c66b48194f
139
src/AstGen.zig
139
src/AstGen.zig
@ -719,25 +719,25 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
|
||||
|
||||
.container_decl,
|
||||
.container_decl_trailing,
|
||||
=> return containerDecl(gz, scope, rl, tree.containerDecl(node)),
|
||||
=> return containerDecl(gz, scope, rl, node, tree.containerDecl(node)),
|
||||
.container_decl_two, .container_decl_two_trailing => {
|
||||
var buffer: [2]ast.Node.Index = undefined;
|
||||
return containerDecl(gz, scope, rl, tree.containerDeclTwo(&buffer, node));
|
||||
return containerDecl(gz, scope, rl, node, tree.containerDeclTwo(&buffer, node));
|
||||
},
|
||||
.container_decl_arg,
|
||||
.container_decl_arg_trailing,
|
||||
=> return containerDecl(gz, scope, rl, tree.containerDeclArg(node)),
|
||||
=> return containerDecl(gz, scope, rl, node, tree.containerDeclArg(node)),
|
||||
|
||||
.tagged_union,
|
||||
.tagged_union_trailing,
|
||||
=> return containerDecl(gz, scope, rl, tree.taggedUnion(node)),
|
||||
=> return containerDecl(gz, scope, rl, node, tree.taggedUnion(node)),
|
||||
.tagged_union_two, .tagged_union_two_trailing => {
|
||||
var buffer: [2]ast.Node.Index = undefined;
|
||||
return containerDecl(gz, scope, rl, tree.taggedUnionTwo(&buffer, node));
|
||||
return containerDecl(gz, scope, rl, node, tree.taggedUnionTwo(&buffer, node));
|
||||
},
|
||||
.tagged_union_enum_tag,
|
||||
.tagged_union_enum_tag_trailing,
|
||||
=> return containerDecl(gz, scope, rl, tree.taggedUnionEnumTag(node)),
|
||||
=> return containerDecl(gz, scope, rl, node, tree.taggedUnionEnumTag(node)),
|
||||
|
||||
.@"break" => return breakExpr(gz, scope, node),
|
||||
.@"continue" => return continueExpr(gz, scope, node),
|
||||
@ -804,6 +804,16 @@ pub fn structInitExpr(
|
||||
const astgen = gz.astgen;
|
||||
const mod = astgen.mod;
|
||||
const gpa = mod.gpa;
|
||||
|
||||
if (struct_init.ast.fields.len == 0) {
|
||||
if (struct_init.ast.type_expr == 0) {
|
||||
return rvalue(gz, scope, rl, .empty_struct, node);
|
||||
} else {
|
||||
const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
|
||||
const result = try gz.addUnNode(.struct_init_empty, ty_inst, node);
|
||||
return rvalue(gz, scope, rl, result, node);
|
||||
}
|
||||
}
|
||||
switch (rl) {
|
||||
.discard => return mod.failNode(scope, node, "TODO implement structInitExpr discard", .{}),
|
||||
.none => return mod.failNode(scope, node, "TODO implement structInitExpr none", .{}),
|
||||
@ -1310,6 +1320,11 @@ fn blockExprStmts(
|
||||
.switch_capture_multi_ref,
|
||||
.switch_capture_else,
|
||||
.switch_capture_else_ref,
|
||||
.struct_init_empty,
|
||||
.struct_decl,
|
||||
.union_decl,
|
||||
.enum_decl,
|
||||
.opaque_decl,
|
||||
=> break :b false,
|
||||
|
||||
// ZIR instructions that are always either `noreturn` or `void`.
|
||||
@ -1754,9 +1769,115 @@ fn containerDecl(
|
||||
gz: *GenZir,
|
||||
scope: *Scope,
|
||||
rl: ResultLoc,
|
||||
node: ast.Node.Index,
|
||||
container_decl: ast.full.ContainerDecl,
|
||||
) InnerError!zir.Inst.Ref {
|
||||
return gz.astgen.mod.failTok(scope, container_decl.ast.main_token, "TODO implement container decls", .{});
|
||||
const astgen = gz.astgen;
|
||||
const mod = astgen.mod;
|
||||
const gpa = mod.gpa;
|
||||
const tree = gz.tree();
|
||||
const token_tags = tree.tokens.items(.tag);
|
||||
const node_tags = tree.nodes.items(.tag);
|
||||
|
||||
// We must not create any types until Sema. Here the goal is only to generate
|
||||
// ZIR for all the field types, alignments, and default value expressions.
|
||||
|
||||
const arg_inst: zir.Inst.Ref = if (container_decl.ast.arg != 0)
|
||||
try comptimeExpr(gz, scope, .none, container_decl.ast.arg)
|
||||
else
|
||||
.none;
|
||||
|
||||
switch (token_tags[container_decl.ast.main_token]) {
|
||||
.keyword_struct => {
|
||||
if (container_decl.ast.members.len == 0) {
|
||||
const result = try gz.addPlNode(.struct_decl, node, zir.Inst.StructDecl{
|
||||
.fields_len = 0,
|
||||
});
|
||||
return rvalue(gz, scope, rl, result, node);
|
||||
}
|
||||
|
||||
assert(arg_inst == .none);
|
||||
var fields_data = ArrayListUnmanaged(u32){};
|
||||
defer fields_data.deinit(gpa);
|
||||
|
||||
// field_name and field_type are both mandatory
|
||||
try fields_data.ensureCapacity(gpa, container_decl.ast.members.len * 2);
|
||||
|
||||
// We only need this if there are greater than 16 fields.
|
||||
var bit_bag = ArrayListUnmanaged(u32){};
|
||||
defer bit_bag.deinit(gpa);
|
||||
|
||||
var cur_bit_bag: u32 = 0;
|
||||
var member_index: usize = 0;
|
||||
while (true) {
|
||||
const member_node = container_decl.ast.members[member_index];
|
||||
const member = switch (node_tags[member_node]) {
|
||||
.container_field_init => tree.containerFieldInit(member_node),
|
||||
.container_field_align => tree.containerFieldAlign(member_node),
|
||||
.container_field => tree.containerField(member_node),
|
||||
else => unreachable,
|
||||
};
|
||||
if (member.comptime_token) |comptime_token| {
|
||||
return mod.failTok(scope, comptime_token, "TODO implement comptime struct fields", .{});
|
||||
}
|
||||
try fields_data.ensureCapacity(gpa, fields_data.items.len + 4);
|
||||
|
||||
const field_name = try gz.identAsString(member.ast.name_token);
|
||||
fields_data.appendAssumeCapacity(field_name);
|
||||
|
||||
const field_type = try typeExpr(gz, scope, member.ast.type_expr);
|
||||
fields_data.appendAssumeCapacity(@enumToInt(field_type));
|
||||
|
||||
const have_align = member.ast.align_expr != 0;
|
||||
const have_value = member.ast.value_expr != 0;
|
||||
cur_bit_bag = (cur_bit_bag >> 2) |
|
||||
(@as(u32, @boolToInt(have_align)) << 30) |
|
||||
(@as(u32, @boolToInt(have_value)) << 31);
|
||||
|
||||
if (have_align) {
|
||||
const align_inst = try comptimeExpr(gz, scope, .{ .ty = .u32_type }, member.ast.align_expr);
|
||||
fields_data.appendAssumeCapacity(@enumToInt(align_inst));
|
||||
}
|
||||
if (have_value) {
|
||||
const default_inst = try comptimeExpr(gz, scope, .{ .ty = field_type }, member.ast.value_expr);
|
||||
fields_data.appendAssumeCapacity(@enumToInt(default_inst));
|
||||
}
|
||||
|
||||
member_index += 1;
|
||||
if (member_index < container_decl.ast.members.len) {
|
||||
if (member_index % 16 == 0) {
|
||||
try bit_bag.append(gpa, cur_bit_bag);
|
||||
cur_bit_bag = 0;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
const empty_slot_count = 16 - ((member_index - 1) % 16);
|
||||
cur_bit_bag >>= @intCast(u5, empty_slot_count * 2);
|
||||
|
||||
const result = try gz.addPlNode(.struct_decl, node, zir.Inst.StructDecl{
|
||||
.fields_len = @intCast(u32, container_decl.ast.members.len),
|
||||
});
|
||||
try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +
|
||||
bit_bag.items.len + 1 + fields_data.items.len);
|
||||
astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty.
|
||||
astgen.extra.appendAssumeCapacity(cur_bit_bag);
|
||||
astgen.extra.appendSliceAssumeCapacity(fields_data.items);
|
||||
return rvalue(gz, scope, rl, result, node);
|
||||
},
|
||||
.keyword_union => {
|
||||
return mod.failTok(scope, container_decl.ast.main_token, "TODO AstGen for union decl", .{});
|
||||
},
|
||||
.keyword_enum => {
|
||||
return mod.failTok(scope, container_decl.ast.main_token, "TODO AstGen for enum decl", .{});
|
||||
},
|
||||
.keyword_opaque => {
|
||||
const result = try gz.addNode(.opaque_decl, node);
|
||||
return rvalue(gz, scope, rl, result, node);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
fn errorSetDecl(
|
||||
@ -2809,10 +2930,10 @@ fn switchExpr(
|
||||
// This is the header as well as the optional else prong body, as well as all the
|
||||
// scalar cases.
|
||||
// At the end we will memcpy this into place.
|
||||
var scalar_cases_payload = std.ArrayListUnmanaged(u32){};
|
||||
var scalar_cases_payload = ArrayListUnmanaged(u32){};
|
||||
defer scalar_cases_payload.deinit(gpa);
|
||||
// Same deal, but this is only the `extra` data for the multi cases.
|
||||
var multi_cases_payload = std.ArrayListUnmanaged(u32){};
|
||||
var multi_cases_payload = ArrayListUnmanaged(u32){};
|
||||
defer multi_cases_payload.deinit(gpa);
|
||||
|
||||
var block_scope: GenZir = .{
|
||||
|
||||
70
src/Sema.zig
70
src/Sema.zig
@ -259,6 +259,12 @@ pub fn analyzeBody(
|
||||
.typeof_elem => try sema.zirTypeofElem(block, inst),
|
||||
.typeof_peer => try sema.zirTypeofPeer(block, inst),
|
||||
.xor => try sema.zirBitwise(block, inst, .xor),
|
||||
.struct_init_empty => try sema.zirStructInitEmpty(block, inst),
|
||||
|
||||
.struct_decl => try sema.zirStructDecl(block, inst),
|
||||
.enum_decl => try sema.zirEnumDecl(block, inst),
|
||||
.union_decl => try sema.zirUnionDecl(block, inst),
|
||||
.opaque_decl => try sema.zirOpaqueDecl(block, inst),
|
||||
|
||||
// Instructions that we know to *always* be noreturn based solely on their tag.
|
||||
// These functions match the return type of analyzeBody so that we can
|
||||
@ -514,6 +520,56 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) In
|
||||
return sema.mod.fail(&block.base, sema.src, "TODO implement zirCoerceResultPtr", .{});
|
||||
}
|
||||
|
||||
fn zirStructDecl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) 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.Block, inst_data.payload_index);
|
||||
|
||||
return sema.mod.fail(&block.base, sema.src, "TODO implement zirStructDecl", .{});
|
||||
|
||||
//const new_decl = try sema.mod.createAnonymousDecl(&block.base, &new_decl_arena, .{
|
||||
// .ty = decl_ty,
|
||||
// .val = decl_val,
|
||||
//});
|
||||
//return sema.analyzeDeclVal(block, src, new_decl);
|
||||
}
|
||||
|
||||
fn zirEnumDecl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) 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.Block, inst_data.payload_index);
|
||||
|
||||
return sema.mod.fail(&block.base, sema.src, "TODO implement zirEnumDecl", .{});
|
||||
}
|
||||
|
||||
fn zirUnionDecl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) 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.Block, inst_data.payload_index);
|
||||
|
||||
return sema.mod.fail(&block.base, sema.src, "TODO implement zirUnionDecl", .{});
|
||||
}
|
||||
|
||||
fn zirOpaqueDecl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) 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.Block, inst_data.payload_index);
|
||||
|
||||
return sema.mod.fail(&block.base, sema.src, "TODO implement zirOpaqueDecl", .{});
|
||||
}
|
||||
|
||||
fn zirRetPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
@ -3867,6 +3923,20 @@ fn zirPtrType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError
|
||||
return sema.mod.constType(sema.arena, src, ty);
|
||||
}
|
||||
|
||||
fn zirStructInitEmpty(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
|
||||
const src = inst_data.src();
|
||||
const struct_type = try sema.resolveType(block, src, inst_data.operand);
|
||||
|
||||
return sema.mod.constInst(sema.arena, src, .{
|
||||
.ty = struct_type,
|
||||
.val = Value.initTag(.empty_struct_value),
|
||||
});
|
||||
}
|
||||
|
||||
fn requireFunctionBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {
|
||||
if (sema.func == null) {
|
||||
return sema.mod.fail(&block.base, src, "instruction illegal outside function body", .{});
|
||||
|
||||
35
src/type.zig
35
src/type.zig
@ -93,6 +93,7 @@ pub const Type = extern union {
|
||||
.anyerror_void_error_union, .error_union => return .ErrorUnion,
|
||||
|
||||
.empty_struct => return .Struct,
|
||||
.empty_struct_literal => return .Struct,
|
||||
|
||||
.var_args_param => unreachable, // can be any type
|
||||
}
|
||||
@ -530,6 +531,7 @@ pub const Type = extern union {
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.var_args_param,
|
||||
.empty_struct_literal,
|
||||
=> unreachable,
|
||||
|
||||
.array_u8,
|
||||
@ -672,8 +674,7 @@ pub const Type = extern union {
|
||||
.@"null" => return out_stream.writeAll("@Type(.Null)"),
|
||||
.@"undefined" => return out_stream.writeAll("@Type(.Undefined)"),
|
||||
|
||||
// TODO this should print the structs name
|
||||
.empty_struct => return out_stream.writeAll("struct {}"),
|
||||
.empty_struct, .empty_struct_literal => return out_stream.writeAll("struct {}"),
|
||||
.anyerror_void_error_union => return out_stream.writeAll("anyerror!void"),
|
||||
.const_slice_u8 => return out_stream.writeAll("[]const u8"),
|
||||
.fn_noreturn_no_args => return out_stream.writeAll("fn() noreturn"),
|
||||
@ -960,6 +961,7 @@ pub const Type = extern union {
|
||||
.@"undefined",
|
||||
.enum_literal,
|
||||
.empty_struct,
|
||||
.empty_struct_literal,
|
||||
.@"opaque",
|
||||
=> false,
|
||||
|
||||
@ -1108,6 +1110,7 @@ pub const Type = extern union {
|
||||
.@"undefined",
|
||||
.enum_literal,
|
||||
.empty_struct,
|
||||
.empty_struct_literal,
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.@"opaque",
|
||||
@ -1135,6 +1138,7 @@ pub const Type = extern union {
|
||||
.enum_literal => unreachable,
|
||||
.single_const_pointer_to_comptime_int => unreachable,
|
||||
.empty_struct => unreachable,
|
||||
.empty_struct_literal => unreachable,
|
||||
.inferred_alloc_const => unreachable,
|
||||
.inferred_alloc_mut => unreachable,
|
||||
.@"opaque" => unreachable,
|
||||
@ -1313,6 +1317,7 @@ pub const Type = extern union {
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
.empty_struct_literal,
|
||||
.@"opaque",
|
||||
.var_args_param,
|
||||
=> false,
|
||||
@ -1386,6 +1391,7 @@ pub const Type = extern union {
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
.empty_struct_literal,
|
||||
.@"opaque",
|
||||
.var_args_param,
|
||||
=> unreachable,
|
||||
@ -1478,6 +1484,7 @@ pub const Type = extern union {
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
.empty_struct_literal,
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.@"opaque",
|
||||
@ -1554,6 +1561,7 @@ pub const Type = extern union {
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
.empty_struct_literal,
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.@"opaque",
|
||||
@ -1639,6 +1647,7 @@ pub const Type = extern union {
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
.empty_struct_literal,
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.@"opaque",
|
||||
@ -1719,6 +1728,7 @@ pub const Type = extern union {
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
.empty_struct_literal,
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.@"opaque",
|
||||
@ -1841,6 +1851,7 @@ pub const Type = extern union {
|
||||
.error_set => unreachable,
|
||||
.error_set_single => unreachable,
|
||||
.empty_struct => unreachable,
|
||||
.empty_struct_literal => unreachable,
|
||||
.inferred_alloc_const => unreachable,
|
||||
.inferred_alloc_mut => unreachable,
|
||||
.@"opaque" => unreachable,
|
||||
@ -1989,6 +2000,7 @@ pub const Type = extern union {
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
.empty_struct_literal,
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.@"opaque",
|
||||
@ -2059,6 +2071,7 @@ pub const Type = extern union {
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
.empty_struct_literal,
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.@"opaque",
|
||||
@ -2144,6 +2157,7 @@ pub const Type = extern union {
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
.empty_struct_literal,
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.@"opaque",
|
||||
@ -2225,6 +2239,7 @@ pub const Type = extern union {
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
.empty_struct_literal,
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.@"opaque",
|
||||
@ -2292,6 +2307,7 @@ pub const Type = extern union {
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
.empty_struct_literal,
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.@"opaque",
|
||||
@ -2387,6 +2403,7 @@ pub const Type = extern union {
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
.empty_struct_literal,
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.@"opaque",
|
||||
@ -2503,6 +2520,7 @@ pub const Type = extern union {
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
.empty_struct_literal,
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.@"opaque",
|
||||
@ -2585,6 +2603,7 @@ pub const Type = extern union {
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
.empty_struct_literal,
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.@"opaque",
|
||||
@ -2666,6 +2685,7 @@ pub const Type = extern union {
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
.empty_struct_literal,
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.@"opaque",
|
||||
@ -2747,6 +2767,7 @@ pub const Type = extern union {
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
.empty_struct_literal,
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.@"opaque",
|
||||
@ -2825,6 +2846,7 @@ pub const Type = extern union {
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
.empty_struct_literal,
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.@"opaque",
|
||||
@ -2903,6 +2925,7 @@ pub const Type = extern union {
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
.empty_struct_literal,
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.@"opaque",
|
||||
@ -2981,6 +3004,7 @@ pub const Type = extern union {
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
.empty_struct_literal,
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.@"opaque",
|
||||
@ -3046,7 +3070,7 @@ pub const Type = extern union {
|
||||
.var_args_param,
|
||||
=> return null,
|
||||
|
||||
.empty_struct => return Value.initTag(.empty_struct_value),
|
||||
.empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value),
|
||||
.void => return Value.initTag(.void_value),
|
||||
.noreturn => return Value.initTag(.unreachable_value),
|
||||
.@"null" => return Value.initTag(.null_value),
|
||||
@ -3149,6 +3173,7 @@ pub const Type = extern union {
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
.empty_struct_literal,
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.@"opaque",
|
||||
@ -3241,6 +3266,7 @@ pub const Type = extern union {
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.var_args_param,
|
||||
.empty_struct_literal,
|
||||
=> unreachable,
|
||||
|
||||
.empty_struct => self.castTag(.empty_struct).?.data,
|
||||
@ -3361,6 +3387,8 @@ pub const Type = extern union {
|
||||
/// This is a special type for variadic parameters of a function call.
|
||||
/// Casts to it will validate that the type can be passed to a c calling convetion function.
|
||||
var_args_param,
|
||||
/// Same as `empty_struct` except it has an empty namespace.
|
||||
empty_struct_literal,
|
||||
/// This is a special value that tracks a set of types that have been stored
|
||||
/// to an inferred allocation. It does not support most of the normal type queries.
|
||||
/// However it does respond to `isConstPtr`, `ptrSize`, `zigTypeTag`, etc.
|
||||
@ -3445,6 +3473,7 @@ pub const Type = extern union {
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.var_args_param,
|
||||
.empty_struct_literal,
|
||||
=> @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),
|
||||
|
||||
.array_u8,
|
||||
|
||||
133
src/zir.zig
133
src/zir.zig
@ -270,6 +270,21 @@ pub const Inst = struct {
|
||||
/// A comptime known value.
|
||||
/// Uses the `const` union field.
|
||||
@"const",
|
||||
/// 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,
|
||||
/// 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,
|
||||
/// 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,
|
||||
/// An opaque type definition. Provides an AST node only.
|
||||
/// Uses the `node` union field.
|
||||
opaque_decl,
|
||||
/// Declares the beginning of a statement. Used for debug info.
|
||||
/// Uses the `node` union field.
|
||||
dbg_stmt_node,
|
||||
@ -642,6 +657,9 @@ pub const Inst = struct {
|
||||
/// as well as missing fields, if applicable.
|
||||
/// Uses the `pl_node` field. Payload is `Block`.
|
||||
validate_struct_init_ptr,
|
||||
/// A struct literal with a specified type, with no fields.
|
||||
/// Uses the `un_node` field.
|
||||
struct_init_empty,
|
||||
|
||||
/// Returns whether the instruction is one of the control flow "noreturn" types.
|
||||
/// Function calls do not count.
|
||||
@ -688,6 +706,10 @@ pub const Inst = struct {
|
||||
.cmp_neq,
|
||||
.coerce_result_ptr,
|
||||
.@"const",
|
||||
.struct_decl,
|
||||
.union_decl,
|
||||
.enum_decl,
|
||||
.opaque_decl,
|
||||
.dbg_stmt_node,
|
||||
.decl_ref,
|
||||
.decl_val,
|
||||
@ -790,6 +812,7 @@ pub const Inst = struct {
|
||||
.switch_block_ref_under,
|
||||
.switch_block_ref_under_multi,
|
||||
.validate_struct_init_ptr,
|
||||
.struct_init_empty,
|
||||
=> false,
|
||||
|
||||
.@"break",
|
||||
@ -893,6 +916,8 @@ pub const Inst = struct {
|
||||
bool_true,
|
||||
/// `false`
|
||||
bool_false,
|
||||
/// `.{}` (untyped)
|
||||
empty_struct,
|
||||
/// `0` (usize)
|
||||
zero_usize,
|
||||
/// `1` (usize)
|
||||
@ -1104,6 +1129,10 @@ pub const Inst = struct {
|
||||
.ty = Type.initTag(.bool),
|
||||
.val = Value.initTag(.bool_false),
|
||||
},
|
||||
.empty_struct = .{
|
||||
.ty = Type.initTag(.empty_struct_literal),
|
||||
.val = Value.initTag(.empty_struct_value),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@ -1427,6 +1456,48 @@ pub const Inst = struct {
|
||||
dest_type: Ref,
|
||||
operand: Ref,
|
||||
};
|
||||
|
||||
/// Trailing:
|
||||
/// 0. has_bits: u32 // for every 16 fields
|
||||
/// - sets of 2 bits:
|
||||
/// 0b0X: whether corresponding field has an align expression
|
||||
/// 0bX0: whether corresponding field has a default expression
|
||||
/// 1. fields: { // for every fields_len
|
||||
/// field_name: u32,
|
||||
/// field_type: Ref,
|
||||
/// align: Ref, // if corresponding bit is set
|
||||
/// default_value: Ref, // if corresponding bit is set
|
||||
/// }
|
||||
pub const StructDecl = struct {
|
||||
fields_len: u32,
|
||||
};
|
||||
|
||||
/// Trailing:
|
||||
/// 0. has_bits: u32 // for every 32 fields
|
||||
/// - the bit is whether corresponding field has an value expression
|
||||
/// 1. field_name: u32 // for every field: null terminated string index
|
||||
/// 2. value: Ref // for every field for which corresponding bit is set
|
||||
pub const EnumDecl = struct {
|
||||
/// Can be `Ref.none`.
|
||||
tag_type: Ref,
|
||||
fields_len: u32,
|
||||
};
|
||||
|
||||
/// Trailing:
|
||||
/// 0. has_bits: u32 // for every 10 fields (+1)
|
||||
/// - first bit is special: set if and only if auto enum tag is enabled.
|
||||
/// - sets of 3 bits:
|
||||
/// 0b00X: whether corresponding field has a type expression
|
||||
/// 0b0X0: whether corresponding field has a align expression
|
||||
/// 0bX00: whether corresponding field has a tag value expression
|
||||
/// 1. field_name: u32 // for every field: null terminated string index
|
||||
/// 2. opt_exprs // Ref for every field for which corresponding bit is set
|
||||
/// - interleaved. type if present, align if present, tag value if present.
|
||||
pub const UnionDecl = struct {
|
||||
/// Can be `Ref.none`.
|
||||
tag_type: Ref,
|
||||
fields_len: u32,
|
||||
};
|
||||
};
|
||||
|
||||
pub const SpecialProng = enum { none, @"else", under };
|
||||
@ -1500,6 +1571,7 @@ const Writer = struct {
|
||||
.is_err_ptr,
|
||||
.typeof,
|
||||
.typeof_elem,
|
||||
.struct_init_empty,
|
||||
=> try self.writeUnNode(stream, inst),
|
||||
|
||||
.ref,
|
||||
@ -1536,6 +1608,8 @@ const Writer = struct {
|
||||
.slice_start,
|
||||
.slice_end,
|
||||
.slice_sentinel,
|
||||
.union_decl,
|
||||
.enum_decl,
|
||||
=> try self.writePlNode(stream, inst),
|
||||
|
||||
.add,
|
||||
@ -1581,6 +1655,8 @@ const Writer = struct {
|
||||
.condbr_inline,
|
||||
=> try self.writePlNodeCondBr(stream, inst),
|
||||
|
||||
.struct_decl => try self.writeStructDecl(stream, inst),
|
||||
|
||||
.switch_block => try self.writePlNodeSwitchBr(stream, inst, .none),
|
||||
.switch_block_else => try self.writePlNodeSwitchBr(stream, inst, .@"else"),
|
||||
.switch_block_under => try self.writePlNodeSwitchBr(stream, inst, .under),
|
||||
@ -1610,6 +1686,7 @@ const Writer = struct {
|
||||
.as_node => try self.writeAs(stream, inst),
|
||||
|
||||
.breakpoint,
|
||||
.opaque_decl,
|
||||
.dbg_stmt_node,
|
||||
.ret_ptr,
|
||||
.ret_type,
|
||||
@ -1808,6 +1885,62 @@ 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 bit_bags_count = std.math.divCeil(usize, fields_len, 16) catch unreachable;
|
||||
|
||||
try stream.writeAll("{\n");
|
||||
self.indent += 2;
|
||||
|
||||
var field_index: usize = extra.end + bit_bags_count;
|
||||
var bit_bag_index: usize = extra.end;
|
||||
var cur_bit_bag: u32 = undefined;
|
||||
var field_i: u32 = 0;
|
||||
while (field_i < fields_len) : (field_i += 1) {
|
||||
if (field_i % 16 == 0) {
|
||||
cur_bit_bag = self.code.extra[bit_bag_index];
|
||||
bit_bag_index += 1;
|
||||
}
|
||||
const has_align = @truncate(u1, cur_bit_bag) != 0;
|
||||
cur_bit_bag >>= 1;
|
||||
const has_default = @truncate(u1, cur_bit_bag) != 0;
|
||||
cur_bit_bag >>= 1;
|
||||
|
||||
const field_name = self.code.nullTerminatedString(self.code.extra[field_index]);
|
||||
field_index += 1;
|
||||
const field_type = @intToEnum(Inst.Ref, self.code.extra[field_index]);
|
||||
field_index += 1;
|
||||
|
||||
try stream.writeByteNTimes(' ', self.indent);
|
||||
try stream.print("{}: ", .{std.zig.fmtId(field_name)});
|
||||
try self.writeInstRef(stream, field_type);
|
||||
|
||||
if (has_align) {
|
||||
const align_ref = @intToEnum(Inst.Ref, self.code.extra[field_index]);
|
||||
field_index += 1;
|
||||
|
||||
try stream.writeAll(" align(");
|
||||
try self.writeInstRef(stream, align_ref);
|
||||
try stream.writeAll(")");
|
||||
}
|
||||
if (has_default) {
|
||||
const default_ref = @intToEnum(Inst.Ref, self.code.extra[field_index]);
|
||||
field_index += 1;
|
||||
|
||||
try stream.writeAll(" = ");
|
||||
try self.writeInstRef(stream, default_ref);
|
||||
}
|
||||
try stream.writeAll(",\n");
|
||||
}
|
||||
|
||||
self.indent -= 2;
|
||||
try stream.writeByteNTimes(' ', self.indent);
|
||||
try stream.writeAll("}) ");
|
||||
try self.writeSrc(stream, inst_data.src());
|
||||
}
|
||||
|
||||
fn writePlNodeSwitchBr(
|
||||
self: *Writer,
|
||||
stream: anytype,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user