diff --git a/src/AstGen.zig b/src/AstGen.zig index db80a2f350..ea0e0f0b53 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -4386,6 +4386,7 @@ fn structDeclInner( .backing_int_body_len = 0, .known_non_opv = false, .known_comptime_only = false, + .is_tuple = false, }); return indexToRef(decl_inst); } @@ -4467,22 +4468,59 @@ fn structDeclInner( // No defer needed here because it is handled by `wip_members.deinit()` above. const bodies_start = astgen.scratch.items.len; + var is_tuple = false; + const node_tags = tree.nodes.items(.tag); + for (container_decl.ast.members) |member_node| { + switch (node_tags[member_node]) { + .container_field_init => is_tuple = tree.containerFieldInit(member_node).ast.tuple_like, + .container_field_align => is_tuple = tree.containerFieldAlign(member_node).ast.tuple_like, + .container_field => is_tuple = tree.containerField(member_node).ast.tuple_like, + else => continue, + } + if (is_tuple) break; + } + if (is_tuple) for (container_decl.ast.members) |member_node| { + switch (node_tags[member_node]) { + .container_field_init, + .container_field_align, + .container_field, + .@"comptime", + => continue, + else => { + return astgen.failNode(member_node, "tuple declarations cannot contain declarations", .{}); + }, + } + }; + var known_non_opv = false; var known_comptime_only = false; for (container_decl.ast.members) |member_node| { - const member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) { + var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) { .decl => continue, .field => |field| field, }; + if (member.ast.tuple_like and !is_tuple and member.ast.type_expr != 0 and + astgen.tree.nodes.items(.tag)[member.ast.type_expr] == .identifier) + { + const ident = astgen.tree.nodes.items(.main_token)[member.ast.type_expr]; + member.ast.tuple_like = false; + member.ast.main_token = ident; + member.ast.type_expr = 0; + } else if (is_tuple and !member.ast.tuple_like) { + return astgen.failTok(member.ast.main_token, "tuple field has a name", .{}); + } - const field_name = try astgen.identAsString(member.ast.name_token); - wip_members.appendToField(field_name); + if (!is_tuple) { + if (member.ast.tuple_like) return astgen.failTok(member.ast.main_token, "struct field missing name", .{}); + const field_name = try astgen.identAsString(member.ast.main_token); + wip_members.appendToField(field_name); + } const doc_comment_index = try astgen.docCommentAsString(member.firstToken()); wip_members.appendToField(doc_comment_index); if (member.ast.type_expr == 0) { - return astgen.failTok(member.ast.name_token, "struct field missing type", .{}); + return astgen.failTok(member.ast.main_token, "struct field missing type", .{}); } const field_type = try typeExpr(&block_scope, &namespace.base, member.ast.type_expr); @@ -4562,6 +4600,7 @@ fn structDeclInner( .backing_int_body_len = @intCast(u32, backing_int_body_len), .known_non_opv = known_non_opv, .known_comptime_only = known_comptime_only, + .is_tuple = is_tuple, }); wip_members.finishBits(bits_per_field); @@ -4640,15 +4679,25 @@ fn unionDeclInner( defer wip_members.deinit(); for (members) |member_node| { - const member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) { + var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) { .decl => continue, .field => |field| field, }; + if (member.ast.tuple_like and member.ast.type_expr != 0 and + astgen.tree.nodes.items(.tag)[member.ast.type_expr] == .identifier) + { + const ident = astgen.tree.nodes.items(.main_token)[member.ast.type_expr]; + member.ast.tuple_like = false; + member.ast.main_token = ident; + member.ast.type_expr = 0; + } else if (member.ast.tuple_like) { + return astgen.failTok(member.ast.main_token, "union field missing name", .{}); + } if (member.comptime_token) |comptime_token| { return astgen.failTok(comptime_token, "union fields cannot be marked comptime", .{}); } - const field_name = try astgen.identAsString(member.ast.name_token); + const field_name = try astgen.identAsString(member.ast.main_token); wip_members.appendToField(field_name); const doc_comment_index = try astgen.docCommentAsString(member.firstToken()); @@ -4787,7 +4836,7 @@ fn containerDecl( var nonexhaustive_node: Ast.Node.Index = 0; var nonfinal_nonexhaustive = false; for (container_decl.ast.members) |member_node| { - const member = switch (node_tags[member_node]) { + var 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), @@ -4796,6 +4845,16 @@ fn containerDecl( continue; }, }; + if (member.ast.tuple_like and member.ast.type_expr != 0 and + astgen.tree.nodes.items(.tag)[member.ast.type_expr] == .identifier) + { + const ident = astgen.tree.nodes.items(.main_token)[member.ast.type_expr]; + member.ast.tuple_like = false; + member.ast.main_token = ident; + member.ast.type_expr = 0; + } else if (member.ast.tuple_like) { + return astgen.failTok(member.ast.main_token, "enum field missing name", .{}); + } if (member.comptime_token) |comptime_token| { return astgen.failTok(comptime_token, "enum fields cannot be marked comptime", .{}); } @@ -4816,7 +4875,7 @@ fn containerDecl( // Alignment expressions in enums are caught by the parser. assert(member.ast.align_expr == 0); - const name_token = member.ast.name_token; + const name_token = member.ast.main_token; if (mem.eql(u8, tree.tokenSlice(name_token), "_")) { if (nonexhaustive_node != 0) { return astgen.failNodeNotes( @@ -4915,15 +4974,23 @@ fn containerDecl( for (container_decl.ast.members) |member_node| { if (member_node == counts.nonexhaustive_node) continue; - const member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) { + var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) { .decl => continue, .field => |field| field, }; + if (member.ast.tuple_like and member.ast.type_expr != 0 and + astgen.tree.nodes.items(.tag)[member.ast.type_expr] == .identifier) + { + const ident = astgen.tree.nodes.items(.main_token)[member.ast.type_expr]; + member.ast.tuple_like = false; + member.ast.main_token = ident; + member.ast.type_expr = 0; + } assert(member.comptime_token == null); assert(member.ast.type_expr == 0); assert(member.ast.align_expr == 0); - const field_name = try astgen.identAsString(member.ast.name_token); + const field_name = try astgen.identAsString(member.ast.main_token); wip_members.appendToField(field_name); const doc_comment_index = try astgen.docCommentAsString(member.firstToken()); @@ -11786,6 +11853,7 @@ const GenZir = struct { layout: std.builtin.Type.ContainerLayout, known_non_opv: bool, known_comptime_only: bool, + is_tuple: bool, }) !void { const astgen = gz.astgen; const gpa = astgen.gpa; @@ -11820,6 +11888,7 @@ const GenZir = struct { .has_backing_int = args.backing_int_ref != .none, .known_non_opv = args.known_non_opv, .known_comptime_only = args.known_comptime_only, + .is_tuple = args.is_tuple, .name_strategy = gz.anon_name_strategy, .layout = args.layout, }), diff --git a/src/Module.zig b/src/Module.zig index d598993c3f..8ea49f13b3 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -6138,7 +6138,7 @@ fn queryFieldSrc( .name => .{ .file_scope = file_scope, .parent_decl_node = 0, - .lazy = .{ .token_abs = field.ast.name_token }, + .lazy = .{ .token_abs = field.ast.main_token }, }, .type => .{ .file_scope = file_scope, diff --git a/src/Zir.zig b/src/Zir.zig index c30642d6c5..c7e1d22d22 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -3166,7 +3166,7 @@ pub const Inst = struct { /// 0b0X00: whether corresponding field is comptime /// 0bX000: whether corresponding field has a type expression /// 9. fields: { // for every fields_len - /// field_name: u32, + /// field_name: u32, // if !is_tuple /// doc_comment: u32, // 0 if no doc comment /// field_type: Ref, // if corresponding bit is not set. none means anytype. /// field_type_body_len: u32, // if corresponding bit is set @@ -3186,9 +3186,10 @@ pub const Inst = struct { has_backing_int: bool, known_non_opv: bool, known_comptime_only: bool, + is_tuple: bool, name_strategy: NameStrategy, layout: std.builtin.Type.ContainerLayout, - _: u6 = undefined, + _: u5 = undefined, }; }; diff --git a/src/print_zir.zig b/src/print_zir.zig index d434abd439..9135c22010 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -1262,6 +1262,7 @@ const Writer = struct { try self.writeFlag(stream, "known_non_opv, ", small.known_non_opv); try self.writeFlag(stream, "known_comptime_only, ", small.known_comptime_only); + try self.writeFlag(stream, "tuple, ", small.is_tuple); try stream.print("{s}, ", .{@tagName(small.name_strategy)}); @@ -1335,8 +1336,11 @@ const Writer = struct { const has_type_body = @truncate(u1, cur_bit_bag) != 0; cur_bit_bag >>= 1; - const field_name = self.code.extra[extra_index]; - extra_index += 1; + var field_name: u32 = 0; + if (!small.is_tuple) { + field_name = self.code.extra[extra_index]; + extra_index += 1; + } const doc_comment_index = self.code.extra[extra_index]; extra_index += 1; @@ -1370,13 +1374,16 @@ const Writer = struct { try stream.writeAll("{\n"); self.indent += 2; - for (fields) |field| { - const field_name = self.code.nullTerminatedString(field.name); - + for (fields) |field, i| { try self.writeDocComment(stream, field.doc_comment_index); try stream.writeByteNTimes(' ', self.indent); try self.writeFlag(stream, "comptime ", field.is_comptime); - try stream.print("{}: ", .{std.zig.fmtId(field_name)}); + if (field.name != 0) { + const field_name = self.code.nullTerminatedString(field.name); + try stream.print("{}: ", .{std.zig.fmtId(field_name)}); + } else { + try stream.print("@\"{d}\": ", .{i}); + } if (field.field_type != .none) { try self.writeInstRef(stream, field.field_type); }