diff --git a/src/AstGen.zig b/src/AstGen.zig index ba6fa74626..668a6e2002 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -3254,6 +3254,12 @@ fn structDeclInner( .fields_len = @intCast(u32, field_index), .decls_len = @intCast(u32, wip_decls.decl_index), }); + astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty. + if (wip_decls.decl_index != 0) { + astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag); + } + astgen.extra.appendSliceAssumeCapacity(wip_decls.payload.items); + astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items); astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty. @@ -3262,12 +3268,6 @@ fn structDeclInner( } astgen.extra.appendSliceAssumeCapacity(fields_data.items); - astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty. - if (wip_decls.decl_index != 0) { - astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag); - } - astgen.extra.appendSliceAssumeCapacity(wip_decls.payload.items); - return gz.indexToRef(decl_inst); } @@ -3479,18 +3479,18 @@ fn unionDeclInner( .fields_len = @intCast(u32, field_index), .decls_len = @intCast(u32, wip_decls.decl_index), }); - astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items); - - astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty. - astgen.extra.appendAssumeCapacity(cur_bit_bag); - astgen.extra.appendSliceAssumeCapacity(fields_data.items); - astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty. if (wip_decls.decl_index != 0) { astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag); } astgen.extra.appendSliceAssumeCapacity(wip_decls.payload.items); + astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items); + + astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty. + astgen.extra.appendAssumeCapacity(cur_bit_bag); + astgen.extra.appendSliceAssumeCapacity(fields_data.items); + return gz.indexToRef(decl_inst); } @@ -3811,11 +3811,121 @@ fn containerDecl( .fields_len = @intCast(u32, field_index), .decls_len = @intCast(u32, wip_decls.decl_index), }); + astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty. + if (wip_decls.decl_index != 0) { + astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag); + } + astgen.extra.appendSliceAssumeCapacity(wip_decls.payload.items); + astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items); 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, gz.indexToRef(decl_inst), node); + }, + .keyword_opaque => { + var wip_decls: WipDecls = .{}; + defer wip_decls.deinit(gpa); + + for (container_decl.ast.members) |member_node| { + 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), + + .fn_decl => { + const fn_proto = node_datas[member_node].lhs; + const body = node_datas[member_node].rhs; + switch (node_tags[fn_proto]) { + .fn_proto_simple => { + var params: [1]ast.Node.Index = undefined; + try astgen.fnDecl(gz, &wip_decls, body, tree.fnProtoSimple(¶ms, fn_proto)); + continue; + }, + .fn_proto_multi => { + try astgen.fnDecl(gz, &wip_decls, body, tree.fnProtoMulti(fn_proto)); + continue; + }, + .fn_proto_one => { + var params: [1]ast.Node.Index = undefined; + try astgen.fnDecl(gz, &wip_decls, body, tree.fnProtoOne(¶ms, fn_proto)); + continue; + }, + .fn_proto => { + try astgen.fnDecl(gz, &wip_decls, body, tree.fnProto(fn_proto)); + continue; + }, + else => unreachable, + } + }, + .fn_proto_simple => { + var params: [1]ast.Node.Index = undefined; + try astgen.fnDecl(gz, &wip_decls, 0, tree.fnProtoSimple(¶ms, member_node)); + continue; + }, + .fn_proto_multi => { + try astgen.fnDecl(gz, &wip_decls, 0, tree.fnProtoMulti(member_node)); + continue; + }, + .fn_proto_one => { + var params: [1]ast.Node.Index = undefined; + try astgen.fnDecl(gz, &wip_decls, 0, tree.fnProtoOne(¶ms, member_node)); + continue; + }, + .fn_proto => { + try astgen.fnDecl(gz, &wip_decls, 0, tree.fnProto(member_node)); + continue; + }, + + .global_var_decl => { + try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.globalVarDecl(member_node)); + continue; + }, + .local_var_decl => { + try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.localVarDecl(member_node)); + continue; + }, + .simple_var_decl => { + try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.simpleVarDecl(member_node)); + continue; + }, + .aligned_var_decl => { + try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.alignedVarDecl(member_node)); + continue; + }, + + .@"comptime" => { + try astgen.comptimeDecl(gz, scope, member_node); + continue; + }, + .@"usingnamespace" => { + try astgen.usingnamespaceDecl(gz, scope, member_node); + continue; + }, + .test_decl => { + try astgen.testDecl(gz, scope, member_node); + continue; + }, + else => unreachable, + }; + } + { + const empty_slot_count = WipDecls.fields_per_u32 - (wip_decls.decl_index % WipDecls.fields_per_u32); + if (empty_slot_count < WipDecls.fields_per_u32) { + wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * WipDecls.bits_per_field); + } + } + const decl_inst = try gz.addBlock(.opaque_decl, node); + try gz.instructions.append(gpa, decl_inst); + + try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.OpaqueDecl).Struct.fields.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.OpaqueDecl{ + .decls_len = @intCast(u32, wip_decls.decl_index), + }); astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty. if (wip_decls.decl_index != 0) { astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag); @@ -3824,10 +3934,6 @@ fn containerDecl( return rvalue(gz, scope, rl, gz.indexToRef(decl_inst), node); }, - .keyword_opaque => { - const result = try gz.addNode(.opaque_decl, node); - return rvalue(gz, scope, rl, result, node); - }, else => unreachable, } } diff --git a/src/Zir.zig b/src/Zir.zig index 7f8f0f2e74..14cc7aaac2 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -312,7 +312,7 @@ pub const Inst = struct { /// Same as `enum_decl`, except the enum is non-exhaustive. enum_decl_nonexhaustive, /// An opaque type definition. Provides an AST node only. - /// Uses the `node` union field. + /// Uses the `pl_node` union field. Payload is `OpaqueDecl`. opaque_decl, /// An error set type definition. Contains a list of field names. /// Uses the `pl_node` union field. Payload is `ErrorSetDecl`. @@ -2368,29 +2368,29 @@ pub const Inst = struct { }; /// Trailing: - /// 0. inst: Index // for every body_len - /// 1. 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 - /// 2. 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 - /// } - /// 3. decl_bits: u32 // for every 8 decls + /// 0. 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 - /// 4. decl: { // for every decls_len + /// 1. decl: { // for every decls_len /// name: u32, // null terminated string index /// value: Index, /// 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 16 fields + /// - sets of 2 bits: + /// 0b0X: whether corresponding field has an align expression + /// 0bX0: whether corresponding field has a default expression + /// 4. 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 { body_len: u32, fields_len: u32, @@ -2398,25 +2398,25 @@ pub const Inst = struct { }; /// Trailing: - /// 0. inst: Index // for every body_len - /// 1. has_bits: u32 // for every 32 fields - /// - the bit is whether corresponding field has an value expression - /// 2. fields: { // for every fields_len - /// field_name: u32, - /// value: Ref, // if corresponding bit is set - /// } - /// 3. decl_bits: u32 // for every 8 decls + /// 0. 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 - /// 4. decl: { // for every decls_len + /// 1. decl: { // for every decls_len /// name: u32, // null terminated string index /// value: Index, /// 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 + /// - the bit is whether corresponding field has an value expression + /// 4. 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, @@ -2426,8 +2426,20 @@ pub const Inst = struct { }; /// Trailing: - /// 0. inst: Index // for every body_len - /// 1. has_bits: u32 // for every 8 fields + /// 0. 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 + /// name: u32, // null terminated string index + /// value: Index, + /// 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 /// - sets of 4 bits: /// 0b000X: whether corresponding field has a type expression /// 0b00X0: whether corresponding field has a align expression @@ -2437,24 +2449,12 @@ pub const Inst = struct { /// to indicate whether auto enum tag is enabled. /// 0 = union(tag_type) /// 1 = union(enum(tag_type)) - /// 2. fields: { // for every fields_len + /// 4. 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 /// } - /// 3. 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 - /// 4. decl: { // for every decls_len - /// name: u32, // null terminated string index - /// value: Index, - /// align: Ref, // if corresponding bit is set - /// link_section: Ref, // if corresponding bit is set - /// } pub const UnionDecl = struct { /// Can be `Ref.none`. tag_type: Ref, @@ -2463,6 +2463,23 @@ pub const Inst = struct { decls_len: u32, }; + /// Trailing: + /// 0. 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 + /// name: u32, // null terminated string index + /// value: Index, + /// align: Ref, // if corresponding bit is set + /// link_section: Ref, // if corresponding bit is set + /// } + pub const OpaqueDecl = struct { + decls_len: u32, + }; + /// Trailing: field_name: u32 // for every field: null terminated string index pub const ErrorSetDecl = struct { fields_len: u32, @@ -2897,6 +2914,8 @@ const Writer = struct { .enum_decl_nonexhaustive, => try self.writeEnumDecl(stream, inst), + .opaque_decl => try self.writeOpaqueDecl(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), @@ -2919,7 +2938,6 @@ const Writer = struct { .breakpoint, .fence, - .opaque_decl, .dbg_stmt_node, .repeat, .repeat_inline, @@ -3321,27 +3339,45 @@ const Writer = struct { 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 body = self.code.extra[extra.end..][0..extra.data.body_len]; const fields_len = extra.data.fields_len; const decls_len = extra.data.decls_len; var extra_index: usize = undefined; + 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); + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("}) "); + } + + const body = self.code.extra[extra_index..][0..extra.data.body_len]; + extra_index += body.len; + if (fields_len == 0) { assert(body.len == 0); try stream.writeAll("{}, {}, {"); extra_index = extra.end; } else { - try stream.writeAll("{\n"); self.indent += 2; - try self.writeBody(stream, body); + if (body.len == 0) { + try stream.writeAll("{}, {\n"); + } else { + try stream.writeAll("{\n"); + try self.writeBody(stream, body); - try stream.writeByteNTimes(' ', self.indent - 2); - try stream.writeAll("}, {\n"); + try stream.writeByteNTimes(' ', self.indent - 2); + try stream.writeAll("}, {\n"); + } const bit_bags_count = std.math.divCeil(usize, fields_len, 16) catch unreachable; - const body_end = extra.end + body.len; - extra_index = body_end + bit_bags_count; + const body_end = extra_index; + extra_index += bit_bags_count; var bit_bag_index: usize = body_end; var cur_bit_bag: u32 = undefined; var field_i: u32 = 0; @@ -3386,27 +3422,30 @@ const Writer = struct { try stream.writeByteNTimes(' ', self.indent); try stream.writeAll("}, {"); } - if (decls_len == 0) { - try stream.writeAll("}) "); - } else { - try stream.writeAll("\n"); - self.indent += 2; - try self.writeDecls(stream, decls_len, extra_index); - self.indent -= 2; - try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("}) "); - } try self.writeSrc(stream, inst_data.src()); } 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 body = self.code.extra[extra.end..][0..extra.data.body_len]; const fields_len = extra.data.fields_len; const decls_len = extra.data.decls_len; const tag_type_ref = extra.data.tag_type; + var extra_index: usize = undefined; + + 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); + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("}, "); + } + assert(fields_len != 0); var first_has_auto_enum: ?bool = null; @@ -3415,20 +3454,25 @@ const Writer = struct { try stream.writeAll(", "); } - var extra_index: usize = undefined; + const body = self.code.extra[extra_index..][0..extra.data.body_len]; + extra_index += body.len; - try stream.writeAll("{\n"); self.indent += 2; - try self.writeBody(stream, body); + if (body.len == 0) { + try stream.writeAll("{}, {\n"); + } else { + try stream.writeAll("{\n"); + try self.writeBody(stream, body); - try stream.writeByteNTimes(' ', self.indent - 2); - try stream.writeAll("}, {\n"); + try stream.writeByteNTimes(' ', self.indent - 2); + try stream.writeAll("}, {\n"); + } 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; - const body_end = extra.end + body.len; - extra_index = body_end + bit_bags_count; + const body_end = extra_index; + extra_index += bit_bags_count; var bit_bag_index: usize = body_end; var cur_bit_bag: u32 = undefined; var field_i: u32 = 0; @@ -3482,23 +3526,13 @@ const Writer = struct { self.indent -= 2; try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("}, {"); - if (decls_len == 0) { - try stream.writeAll("}"); - } else { - try stream.writeAll("\n"); - self.indent += 2; - try self.writeDecls(stream, decls_len, extra_index); - self.indent -= 2; - try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("}"); - } + try stream.writeAll("}"); try self.writeFlag(stream, ", autoenum", first_has_auto_enum.?); try stream.writeAll(") "); try self.writeSrc(stream, inst_data.src()); } - fn writeDecls(self: *Writer, stream: anytype, decls_len: u32, extra_start: usize) !void { + fn writeDecls(self: *Writer, stream: anytype, decls_len: u32, extra_start: usize) !usize { const parent_decl_node = self.parent_decl_node; const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable; var extra_index = extra_start + bit_bags_count; @@ -3561,38 +3595,56 @@ const Writer = struct { try self.writeSrc(stream, decl_block_inst_data.src()); try stream.writeAll("\n"); } + 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 body = self.code.extra[extra.end..][0..extra.data.body_len]; const fields_len = extra.data.fields_len; const decls_len = extra.data.decls_len; const tag_type_ref = extra.data.tag_type; + var extra_index: usize = undefined; + + 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); + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("}, "); + } + if (tag_type_ref != .none) { try self.writeInstRef(stream, tag_type_ref); try stream.writeAll(", "); } - var extra_index: usize = undefined; + const body = self.code.extra[extra_index..][0..extra.data.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 { - try stream.writeAll("{\n"); self.indent += 2; - try self.writeBody(stream, body); + if (body.len == 0) { + try stream.writeAll("{}, {\n"); + } else { + try stream.writeAll("{\n"); + try self.writeBody(stream, body); - try stream.writeByteNTimes(' ', self.indent - 2); - try stream.writeAll("}, {\n"); + try stream.writeByteNTimes(' ', self.indent - 2); + try stream.writeAll("}, {\n"); + } const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable; - const body_end = extra.end + body.len; - extra_index = body_end + bit_bags_count; + const body_end = extra_index; + extra_index += bit_bags_count; var bit_bag_index: usize = body_end; var cur_bit_bag: u32 = undefined; var field_i: u32 = 0; @@ -3621,14 +3673,22 @@ const Writer = struct { } self.indent -= 2; try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("}, {"); + try stream.writeAll("}) "); } + try self.writeSrc(stream, inst_data.src()); + } + + fn writeOpaqueDecl(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.OpaqueDecl, inst_data.payload_index); + const decls_len = extra.data.decls_len; + if (decls_len == 0) { try stream.writeAll("}) "); } else { try stream.writeAll("\n"); self.indent += 2; - try self.writeDecls(stream, decls_len, extra_index); + _ = try self.writeDecls(stream, decls_len, extra.end); self.indent -= 2; try stream.writeByteNTimes(' ', self.indent); try stream.writeAll("}) ");