compiler: remove anonymous struct types, unify all tuples

This commit reworks how anonymous struct literals and tuples work.

Previously, an untyped anonymous struct literal
(e.g. `const x = .{ .a = 123 }`) was given an "anonymous struct type",
which is a special kind of struct which coerces using structural
equivalence. This mechanism was a holdover from before we used
RLS / result types as the primary mechanism of type inference. This
commit changes the language so that the type assigned here is a "normal"
struct type. It uses a form of equivalence based on the AST node and the
type's structure, much like a reified (`@Type`) type.

Additionally, tuples have been simplified. The distinction between
"simple" and "complex" tuple types is eliminated. All tuples, even those
explicitly declared using `struct { ... }` syntax, use structural
equivalence, and do not undergo staged type resolution. Tuples are very
restricted: they cannot have non-`auto` layouts, cannot have aligned
fields, and cannot have default values with the exception of `comptime`
fields. Tuples currently do not have optimized layout, but this can be
changed in the future.

This change simplifies the language, and fixes some problematic
coercions through pointers which led to unintuitive behavior.

Resolves: #16865
This commit is contained in:
mlugg 2024-10-26 23:13:58 +01:00
parent a916bc7fdd
commit d11bbde5f9
No known key found for this signature in database
GPG Key ID: 3F5B7DCCBF4AF02E
62 changed files with 1067 additions and 1314 deletions

View File

@ -157,7 +157,7 @@ fn createType(desc: TypeDescription, it: *TypeDescription.TypeIterator, comp: *c
.len = element_count, .len = element_count,
.elem = child_ty, .elem = child_ty,
}; };
const vector_ty = .{ .specifier = .vector, .data = .{ .array = arr_ty } }; const vector_ty: Type = .{ .specifier = .vector, .data = .{ .array = arr_ty } };
builder.specifier = Type.Builder.fromType(vector_ty); builder.specifier = Type.Builder.fromType(vector_ty);
}, },
.q => { .q => {

View File

@ -8095,7 +8095,7 @@ fn primaryExpr(p: *Parser) Error!Result {
fn makePredefinedIdentifier(p: *Parser, strings_top: usize) !Result { fn makePredefinedIdentifier(p: *Parser, strings_top: usize) !Result {
const end: u32 = @intCast(p.strings.items.len); const end: u32 = @intCast(p.strings.items.len);
const elem_ty = .{ .specifier = .char, .qual = .{ .@"const" = true } }; const elem_ty: Type = .{ .specifier = .char, .qual = .{ .@"const" = true } };
const arr_ty = try p.arena.create(Type.Array); const arr_ty = try p.arena.create(Type.Array);
arr_ty.* = .{ .elem = elem_ty, .len = end - strings_top }; arr_ty.* = .{ .elem = elem_ty, .len = end - strings_top };
const ty: Type = .{ .specifier = .array, .data = .{ .array = arr_ty } }; const ty: Type = .{ .specifier = .array, .data = .{ .array = arr_ty } };

View File

@ -188,7 +188,7 @@ pub const Parser = struct {
pub fn err(self: *Parser, tag: Diagnostics.Tag, extra: Diagnostics.Message.Extra) void { pub fn err(self: *Parser, tag: Diagnostics.Tag, extra: Diagnostics.Message.Extra) void {
if (self.errored) return; if (self.errored) return;
self.errored = true; self.errored = true;
const diagnostic = .{ .tag = tag, .extra = extra }; const diagnostic: CharDiagnostic = .{ .tag = tag, .extra = extra };
if (self.errors_len == self.errors_buffer.len) { if (self.errors_len == self.errors_buffer.len) {
self.errors_buffer[self.errors_buffer.len - 1] = diagnostic; self.errors_buffer[self.errors_buffer.len - 1] = diagnostic;
} else { } else {

View File

@ -749,7 +749,7 @@ fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualH
const is_const = is_fn_proto or child_type.isConst(); const is_const = is_fn_proto or child_type.isConst();
const is_volatile = child_type.qual.@"volatile"; const is_volatile = child_type.qual.@"volatile";
const elem_type = try transType(c, scope, child_type, qual_handling, source_loc); const elem_type = try transType(c, scope, child_type, qual_handling, source_loc);
const ptr_info = .{ const ptr_info: @FieldType(ast.Payload.Pointer, "data") = .{
.is_const = is_const, .is_const = is_const,
.is_volatile = is_volatile, .is_volatile = is_volatile,
.elem_type = elem_type, .elem_type = elem_type,

View File

@ -6,7 +6,7 @@ const io = std.io;
const testing = std.testing; const testing = std.testing;
const assert = std.debug.assert; const assert = std.debug.assert;
pub const std_options = .{ pub const std_options: std.Options = .{
.logFn = log, .logFn = log,
}; };

View File

@ -299,7 +299,7 @@ test "precedence" {
test "zig_version" { test "zig_version" {
// An approximate Zig build that predates this test. // An approximate Zig build that predates this test.
const older_version = .{ .major = 0, .minor = 8, .patch = 0, .pre = "dev.874" }; const older_version: Version = .{ .major = 0, .minor = 8, .patch = 0, .pre = "dev.874" };
// Simulated compatibility check using Zig version. // Simulated compatibility check using Zig version.
const compatible = comptime @import("builtin").zig_version.order(older_version) == .gt; const compatible = comptime @import("builtin").zig_version.order(older_version) == .gt;

View File

@ -509,7 +509,7 @@ pub const Os = struct {
.max = .{ .major = 6, .minor = 10, .patch = 3 }, .max = .{ .major = 6, .minor = 10, .patch = 3 },
}, },
.glibc = blk: { .glibc = blk: {
const default_min = .{ .major = 2, .minor = 28, .patch = 0 }; const default_min: std.SemanticVersion = .{ .major = 2, .minor = 28, .patch = 0 };
for (std.zig.target.available_libcs) |libc| { for (std.zig.target.available_libcs) |libc| {
// We don't know the ABI here. We can get away with not checking it // We don't know the ABI here. We can get away with not checking it

View File

@ -100,7 +100,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
/// of this ArrayList. Empties this ArrayList. /// of this ArrayList. Empties this ArrayList.
pub fn moveToUnmanaged(self: *Self) ArrayListAlignedUnmanaged(T, alignment) { pub fn moveToUnmanaged(self: *Self) ArrayListAlignedUnmanaged(T, alignment) {
const allocator = self.allocator; const allocator = self.allocator;
const result = .{ .items = self.items, .capacity = self.capacity }; const result: ArrayListAlignedUnmanaged(T, alignment) = .{ .items = self.items, .capacity = self.capacity };
self.* = init(allocator); self.* = init(allocator);
return result; return result;
} }

View File

@ -258,8 +258,7 @@ fn kvSplit(str: []const u8) !struct { key: []const u8, value: []const u8 } {
var it = mem.splitScalar(u8, str, kv_delimiter_scalar); var it = mem.splitScalar(u8, str, kv_delimiter_scalar);
const key = it.first(); const key = it.first();
const value = it.next() orelse return Error.InvalidEncoding; const value = it.next() orelse return Error.InvalidEncoding;
const ret = .{ .key = key, .value = value }; return .{ .key = key, .value = value };
return ret;
} }
test "phc format - encoding/decoding" { test "phc format - encoding/decoding" {

View File

@ -1018,7 +1018,7 @@ fn CreateUniqueTuple(comptime N: comptime_int, comptime types: [N]type) type {
.type = T, .type = T,
.default_value = null, .default_value = null,
.is_comptime = false, .is_comptime = false,
.alignment = if (@sizeOf(T) > 0) @alignOf(T) else 0, .alignment = 0,
}; };
} }

View File

@ -1711,7 +1711,7 @@ fn structInitExpr(
return rvalue(gz, ri, val, node); return rvalue(gz, ri, val, node);
}, },
.none, .ref, .inferred_ptr => { .none, .ref, .inferred_ptr => {
return rvalue(gz, ri, .empty_struct, node); return rvalue(gz, ri, .empty_tuple, node);
}, },
.destructure => |destructure| { .destructure => |destructure| {
return astgen.failNodeNotes(node, "empty initializer cannot be destructured", .{}, &.{ return astgen.failNodeNotes(node, "empty initializer cannot be destructured", .{}, &.{
@ -1888,6 +1888,8 @@ fn structInitExprAnon(
const tree = astgen.tree; const tree = astgen.tree;
const payload_index = try addExtra(astgen, Zir.Inst.StructInitAnon{ const payload_index = try addExtra(astgen, Zir.Inst.StructInitAnon{
.abs_node = node,
.abs_line = astgen.source_line,
.fields_len = @intCast(struct_init.ast.fields.len), .fields_len = @intCast(struct_init.ast.fields.len),
}); });
const field_size = @typeInfo(Zir.Inst.StructInitAnon.Item).@"struct".fields.len; const field_size = @typeInfo(Zir.Inst.StructInitAnon.Item).@"struct".fields.len;
@ -1919,6 +1921,8 @@ fn structInitExprTyped(
const tree = astgen.tree; const tree = astgen.tree;
const payload_index = try addExtra(astgen, Zir.Inst.StructInit{ const payload_index = try addExtra(astgen, Zir.Inst.StructInit{
.abs_node = node,
.abs_line = astgen.source_line,
.fields_len = @intCast(struct_init.ast.fields.len), .fields_len = @intCast(struct_init.ast.fields.len),
}); });
const field_size = @typeInfo(Zir.Inst.StructInit.Item).@"struct".fields.len; const field_size = @typeInfo(Zir.Inst.StructInit.Item).@"struct".fields.len;
@ -5007,6 +5011,25 @@ fn structDeclInner(
layout: std.builtin.Type.ContainerLayout, layout: std.builtin.Type.ContainerLayout,
backing_int_node: Ast.Node.Index, backing_int_node: Ast.Node.Index,
) InnerError!Zir.Inst.Ref { ) InnerError!Zir.Inst.Ref {
const astgen = gz.astgen;
const gpa = astgen.gpa;
const tree = astgen.tree;
{
const is_tuple = for (container_decl.ast.members) |member_node| {
const container_field = tree.fullContainerField(member_node) orelse continue;
if (container_field.ast.tuple_like) break true;
} else false;
if (is_tuple) {
if (node == 0) {
return astgen.failTok(0, "file cannot be a tuple", .{});
} else {
return tupleDecl(gz, scope, node, container_decl, layout, backing_int_node);
}
}
}
const decl_inst = try gz.reserveInstructionIndex(); const decl_inst = try gz.reserveInstructionIndex();
if (container_decl.ast.members.len == 0 and backing_int_node == 0) { if (container_decl.ast.members.len == 0 and backing_int_node == 0) {
@ -5019,7 +5042,6 @@ fn structDeclInner(
.has_backing_int = false, .has_backing_int = false,
.known_non_opv = false, .known_non_opv = false,
.known_comptime_only = false, .known_comptime_only = false,
.is_tuple = false,
.any_comptime_fields = false, .any_comptime_fields = false,
.any_default_inits = false, .any_default_inits = false,
.any_aligned_fields = false, .any_aligned_fields = false,
@ -5028,10 +5050,6 @@ fn structDeclInner(
return decl_inst.toRef(); return decl_inst.toRef();
} }
const astgen = gz.astgen;
const gpa = astgen.gpa;
const tree = astgen.tree;
var namespace: Scope.Namespace = .{ var namespace: Scope.Namespace = .{
.parent = scope, .parent = scope,
.node = node, .node = node,
@ -5106,46 +5124,6 @@ fn structDeclInner(
// No defer needed here because it is handled by `wip_members.deinit()` above. // No defer needed here because it is handled by `wip_members.deinit()` above.
const bodies_start = astgen.scratch.items.len; const bodies_start = astgen.scratch.items.len;
const node_tags = tree.nodes.items(.tag);
const is_tuple = for (container_decl.ast.members) |member_node| {
const container_field = tree.fullContainerField(member_node) orelse continue;
if (container_field.ast.tuple_like) break true;
} else false;
if (is_tuple) switch (layout) {
.auto => {},
.@"extern" => return astgen.failNode(node, "extern tuples are not supported", .{}),
.@"packed" => return astgen.failNode(node, "packed tuples are not supported", .{}),
};
if (is_tuple) for (container_decl.ast.members) |member_node| {
switch (node_tags[member_node]) {
.container_field_init,
.container_field_align,
.container_field,
.@"comptime",
.test_decl,
=> continue,
else => {
const tuple_member = for (container_decl.ast.members) |maybe_tuple| switch (node_tags[maybe_tuple]) {
.container_field_init,
.container_field_align,
.container_field,
=> break maybe_tuple,
else => {},
} else unreachable;
return astgen.failNodeNotes(
member_node,
"tuple declarations cannot contain declarations",
.{},
&[_]u32{
try astgen.errNoteNode(tuple_member, "tuple field here", .{}),
},
);
},
}
};
const old_hasher = astgen.src_hasher; const old_hasher = astgen.src_hasher;
defer astgen.src_hasher = old_hasher; defer astgen.src_hasher = old_hasher;
astgen.src_hasher = std.zig.SrcHasher.init(.{}); astgen.src_hasher = std.zig.SrcHasher.init(.{});
@ -5167,16 +5145,10 @@ fn structDeclInner(
astgen.src_hasher.update(tree.getNodeSource(member_node)); astgen.src_hasher.update(tree.getNodeSource(member_node));
if (!is_tuple) { const field_name = try astgen.identAsString(member.ast.main_token);
const field_name = try astgen.identAsString(member.ast.main_token); member.convertToNonTupleLike(astgen.tree.nodes);
assert(!member.ast.tuple_like);
member.convertToNonTupleLike(astgen.tree.nodes); wip_members.appendToField(@intFromEnum(field_name));
assert(!member.ast.tuple_like);
wip_members.appendToField(@intFromEnum(field_name));
} else if (!member.ast.tuple_like) {
return astgen.failTok(member.ast.main_token, "tuple field has a name", .{});
}
const doc_comment_index = try astgen.docCommentAsString(member.firstToken()); const doc_comment_index = try astgen.docCommentAsString(member.firstToken());
wip_members.appendToField(@intFromEnum(doc_comment_index)); wip_members.appendToField(@intFromEnum(doc_comment_index));
@ -5270,7 +5242,6 @@ fn structDeclInner(
.has_backing_int = backing_int_ref != .none, .has_backing_int = backing_int_ref != .none,
.known_non_opv = known_non_opv, .known_non_opv = known_non_opv,
.known_comptime_only = known_comptime_only, .known_comptime_only = known_comptime_only,
.is_tuple = is_tuple,
.any_comptime_fields = any_comptime_fields, .any_comptime_fields = any_comptime_fields,
.any_default_inits = any_default_inits, .any_default_inits = any_default_inits,
.any_aligned_fields = any_aligned_fields, .any_aligned_fields = any_aligned_fields,
@ -5300,6 +5271,106 @@ fn structDeclInner(
return decl_inst.toRef(); return decl_inst.toRef();
} }
fn tupleDecl(
gz: *GenZir,
scope: *Scope,
node: Ast.Node.Index,
container_decl: Ast.full.ContainerDecl,
layout: std.builtin.Type.ContainerLayout,
backing_int_node: Ast.Node.Index,
) InnerError!Zir.Inst.Ref {
const astgen = gz.astgen;
const gpa = astgen.gpa;
const tree = astgen.tree;
const node_tags = tree.nodes.items(.tag);
switch (layout) {
.auto => {},
.@"extern" => return astgen.failNode(node, "extern tuples are not supported", .{}),
.@"packed" => return astgen.failNode(node, "packed tuples are not supported", .{}),
}
if (backing_int_node != 0) {
return astgen.failNode(backing_int_node, "tuple does not support backing integer type", .{});
}
// We will use the scratch buffer, starting here, for the field data:
// 1. fields: { // for every `fields_len` (stored in `extended.small`)
// type: Inst.Ref,
// init: Inst.Ref, // `.none` for non-`comptime` fields
// }
const fields_start = astgen.scratch.items.len;
defer astgen.scratch.items.len = fields_start;
try astgen.scratch.ensureUnusedCapacity(gpa, container_decl.ast.members.len * 2);
for (container_decl.ast.members) |member_node| {
const field = tree.fullContainerField(member_node) orelse {
const tuple_member = for (container_decl.ast.members) |maybe_tuple| switch (node_tags[maybe_tuple]) {
.container_field_init,
.container_field_align,
.container_field,
=> break maybe_tuple,
else => {},
} else unreachable;
return astgen.failNodeNotes(
member_node,
"tuple declarations cannot contain declarations",
.{},
&.{try astgen.errNoteNode(tuple_member, "tuple field here", .{})},
);
};
if (!field.ast.tuple_like) {
return astgen.failTok(field.ast.main_token, "tuple field has a name", .{});
}
if (field.ast.align_expr != 0) {
return astgen.failTok(field.ast.main_token, "tuple field has alignment", .{});
}
if (field.ast.value_expr != 0 and field.comptime_token == null) {
return astgen.failTok(field.ast.main_token, "non-comptime tuple field has default initialization value", .{});
}
if (field.ast.value_expr == 0 and field.comptime_token != null) {
return astgen.failTok(field.comptime_token.?, "comptime field without default initialization value", .{});
}
const field_type_ref = try typeExpr(gz, scope, field.ast.type_expr);
astgen.scratch.appendAssumeCapacity(@intFromEnum(field_type_ref));
if (field.ast.value_expr != 0) {
const field_init_ref = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = field_type_ref } }, field.ast.value_expr);
astgen.scratch.appendAssumeCapacity(@intFromEnum(field_init_ref));
} else {
astgen.scratch.appendAssumeCapacity(@intFromEnum(Zir.Inst.Ref.none));
}
}
const fields_len = std.math.cast(u16, container_decl.ast.members.len) orelse {
return astgen.failNode(node, "this compiler implementation only supports 65535 tuple fields", .{});
};
const extra_trail = astgen.scratch.items[fields_start..];
assert(extra_trail.len == fields_len * 2);
try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.TupleDecl).@"struct".fields.len + extra_trail.len);
const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.TupleDecl{
.src_node = gz.nodeIndexToRelative(node),
});
astgen.extra.appendSliceAssumeCapacity(extra_trail);
return gz.add(.{
.tag = .extended,
.data = .{ .extended = .{
.opcode = .tuple_decl,
.small = fields_len,
.operand = payload_index,
} },
});
}
fn unionDeclInner( fn unionDeclInner(
gz: *GenZir, gz: *GenZir,
scope: *Scope, scope: *Scope,
@ -11172,7 +11243,7 @@ fn rvalueInner(
as_ty | @intFromEnum(Zir.Inst.Ref.slice_const_u8_sentinel_0_type), as_ty | @intFromEnum(Zir.Inst.Ref.slice_const_u8_sentinel_0_type),
as_ty | @intFromEnum(Zir.Inst.Ref.anyerror_void_error_union_type), as_ty | @intFromEnum(Zir.Inst.Ref.anyerror_void_error_union_type),
as_ty | @intFromEnum(Zir.Inst.Ref.generic_poison_type), as_ty | @intFromEnum(Zir.Inst.Ref.generic_poison_type),
as_ty | @intFromEnum(Zir.Inst.Ref.empty_struct_type), as_ty | @intFromEnum(Zir.Inst.Ref.empty_tuple_type),
as_comptime_int | @intFromEnum(Zir.Inst.Ref.zero), as_comptime_int | @intFromEnum(Zir.Inst.Ref.zero),
as_comptime_int | @intFromEnum(Zir.Inst.Ref.one), as_comptime_int | @intFromEnum(Zir.Inst.Ref.one),
as_comptime_int | @intFromEnum(Zir.Inst.Ref.negative_one), as_comptime_int | @intFromEnum(Zir.Inst.Ref.negative_one),
@ -13173,7 +13244,6 @@ const GenZir = struct {
layout: std.builtin.Type.ContainerLayout, layout: std.builtin.Type.ContainerLayout,
known_non_opv: bool, known_non_opv: bool,
known_comptime_only: bool, known_comptime_only: bool,
is_tuple: bool,
any_comptime_fields: bool, any_comptime_fields: bool,
any_default_inits: bool, any_default_inits: bool,
any_aligned_fields: bool, any_aligned_fields: bool,
@ -13217,7 +13287,6 @@ const GenZir = struct {
.has_backing_int = args.has_backing_int, .has_backing_int = args.has_backing_int,
.known_non_opv = args.known_non_opv, .known_non_opv = args.known_non_opv,
.known_comptime_only = args.known_comptime_only, .known_comptime_only = args.known_comptime_only,
.is_tuple = args.is_tuple,
.name_strategy = gz.anon_name_strategy, .name_strategy = gz.anon_name_strategy,
.layout = args.layout, .layout = args.layout,
.any_comptime_fields = args.any_comptime_fields, .any_comptime_fields = args.any_comptime_fields,

View File

@ -1,5 +1,3 @@
const std = @import("std");
pub const Tag = enum { pub const Tag = enum {
add_with_overflow, add_with_overflow,
addrspace_cast, addrspace_cast,
@ -147,7 +145,7 @@ param_count: ?u8,
pub const list = list: { pub const list = list: {
@setEvalBranchQuota(3000); @setEvalBranchQuota(3000);
break :list std.StaticStringMap(@This()).initComptime(.{ break :list std.StaticStringMap(BuiltinFn).initComptime([_]struct { []const u8, BuiltinFn }{
.{ .{
"@addWithOverflow", "@addWithOverflow",
.{ .{
@ -1011,3 +1009,6 @@ pub const list = list: {
}, },
}); });
}; };
const std = @import("std");
const BuiltinFn = @This();

View File

@ -1887,6 +1887,10 @@ pub const Inst = struct {
/// `operand` is payload index to `OpaqueDecl`. /// `operand` is payload index to `OpaqueDecl`.
/// `small` is `OpaqueDecl.Small`. /// `small` is `OpaqueDecl.Small`.
opaque_decl, opaque_decl,
/// A tuple type. Note that tuples are not namespace/container types.
/// `operand` is payload index to `TupleDecl`.
/// `small` is `fields_len: u16`.
tuple_decl,
/// Implements the `@This` builtin. /// Implements the `@This` builtin.
/// `operand` is `src_node: i32`. /// `operand` is `src_node: i32`.
this, this,
@ -2187,7 +2191,7 @@ pub const Inst = struct {
anyerror_void_error_union_type, anyerror_void_error_union_type,
adhoc_inferred_error_set_type, adhoc_inferred_error_set_type,
generic_poison_type, generic_poison_type,
empty_struct_type, empty_tuple_type,
undef, undef,
zero, zero,
zero_usize, zero_usize,
@ -2202,7 +2206,7 @@ pub const Inst = struct {
null_value, null_value,
bool_true, bool_true,
bool_false, bool_false,
empty_struct, empty_tuple,
generic_poison, generic_poison,
/// This Ref does not correspond to any ZIR instruction or constant /// This Ref does not correspond to any ZIR instruction or constant
@ -3041,7 +3045,7 @@ pub const Inst = struct {
/// 0b0X00: whether corresponding field is comptime /// 0b0X00: whether corresponding field is comptime
/// 0bX000: whether corresponding field has a type expression /// 0bX000: whether corresponding field has a type expression
/// 9. fields: { // for every fields_len /// 9. fields: { // for every fields_len
/// field_name: u32, // if !is_tuple /// field_name: u32,
/// doc_comment: NullTerminatedString, // .empty if no doc comment /// doc_comment: NullTerminatedString, // .empty if no doc comment
/// field_type: Ref, // if corresponding bit is not set. none means anytype. /// field_type: Ref, // if corresponding bit is not set. none means anytype.
/// field_type_body_len: u32, // if corresponding bit is set /// field_type_body_len: u32, // if corresponding bit is set
@ -3071,13 +3075,12 @@ pub const Inst = struct {
has_backing_int: bool, has_backing_int: bool,
known_non_opv: bool, known_non_opv: bool,
known_comptime_only: bool, known_comptime_only: bool,
is_tuple: bool,
name_strategy: NameStrategy, name_strategy: NameStrategy,
layout: std.builtin.Type.ContainerLayout, layout: std.builtin.Type.ContainerLayout,
any_default_inits: bool, any_default_inits: bool,
any_comptime_fields: bool, any_comptime_fields: bool,
any_aligned_fields: bool, any_aligned_fields: bool,
_: u2 = undefined, _: u3 = undefined,
}; };
}; };
@ -3302,6 +3305,15 @@ pub const Inst = struct {
}; };
}; };
/// Trailing:
/// 1. fields: { // for every `fields_len` (stored in `extended.small`)
/// type: Inst.Ref,
/// init: Inst.Ref, // `.none` for non-`comptime` fields
/// }
pub const TupleDecl = struct {
src_node: i32, // relative
};
/// Trailing: /// Trailing:
/// { // for every fields_len /// { // for every fields_len
/// field_name: NullTerminatedString // null terminated string index /// field_name: NullTerminatedString // null terminated string index
@ -3329,6 +3341,11 @@ pub const Inst = struct {
/// Trailing is an item per field. /// Trailing is an item per field.
pub const StructInit = struct { pub const StructInit = struct {
/// If this is an anonymous initialization (the operand is poison), this instruction becomes the owner of a type.
/// To resolve source locations, we need an absolute source node.
abs_node: Ast.Node.Index,
/// Likewise, we need an absolute line number.
abs_line: u32,
fields_len: u32, fields_len: u32,
pub const Item = struct { pub const Item = struct {
@ -3344,6 +3361,11 @@ pub const Inst = struct {
/// TODO make this instead array of inits followed by array of names because /// TODO make this instead array of inits followed by array of names because
/// it will be simpler Sema code and better for CPU cache. /// it will be simpler Sema code and better for CPU cache.
pub const StructInitAnon = struct { pub const StructInitAnon = struct {
/// This is an anonymous initialization, meaning this instruction becomes the owner of a type.
/// To resolve source locations, we need an absolute source node.
abs_node: Ast.Node.Index,
/// Likewise, we need an absolute line number.
abs_line: u32,
fields_len: u32, fields_len: u32,
pub const Item = struct { pub const Item = struct {
@ -3741,6 +3763,8 @@ fn findDeclsInner(
defers: *std.AutoHashMapUnmanaged(u32, void), defers: *std.AutoHashMapUnmanaged(u32, void),
inst: Inst.Index, inst: Inst.Index,
) Allocator.Error!void { ) Allocator.Error!void {
comptime assert(Zir.inst_tracking_version == 0);
const tags = zir.instructions.items(.tag); const tags = zir.instructions.items(.tag);
const datas = zir.instructions.items(.data); const datas = zir.instructions.items(.data);
@ -3884,9 +3908,6 @@ fn findDeclsInner(
.struct_init_empty, .struct_init_empty,
.struct_init_empty_result, .struct_init_empty_result,
.struct_init_empty_ref_result, .struct_init_empty_ref_result,
.struct_init_anon,
.struct_init,
.struct_init_ref,
.validate_struct_init_ty, .validate_struct_init_ty,
.validate_struct_init_result_ty, .validate_struct_init_result_ty,
.validate_ptr_struct_init, .validate_ptr_struct_init,
@ -3978,6 +3999,12 @@ fn findDeclsInner(
.restore_err_ret_index_fn_entry, .restore_err_ret_index_fn_entry,
=> return, => return,
// Struct initializations need tracking, as they may create anonymous struct types.
.struct_init,
.struct_init_ref,
.struct_init_anon,
=> return list.append(gpa, inst),
.extended => { .extended => {
const extended = datas[@intFromEnum(inst)].extended; const extended = datas[@intFromEnum(inst)].extended;
switch (extended.opcode) { switch (extended.opcode) {
@ -4034,6 +4061,7 @@ fn findDeclsInner(
.builtin_value, .builtin_value,
.branch_hint, .branch_hint,
.inplace_arith_result_ty, .inplace_arith_result_ty,
.tuple_decl,
=> return, => return,
// `@TypeOf` has a body. // `@TypeOf` has a body.
@ -4110,8 +4138,7 @@ fn findDeclsInner(
const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0; const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0;
cur_bit_bag >>= 1; cur_bit_bag >>= 1;
fields_extra_index += @intFromBool(!small.is_tuple); // field_name fields_extra_index += 2; // field_name, doc_comment
fields_extra_index += 1; // doc_comment
if (has_type_body) { if (has_type_body) {
const field_type_body_len = zir.extra[fields_extra_index]; const field_type_body_len = zir.extra[fields_extra_index];
@ -4736,3 +4763,35 @@ pub fn getAssociatedSrcHash(zir: Zir, inst: Zir.Inst.Index) ?std.zig.SrcHash {
else => return null, else => return null,
} }
} }
/// When the ZIR update tracking logic must be modified to consider new instructions,
/// change this constant to trigger compile errors at all relevant locations.
pub const inst_tracking_version = 0;
/// Asserts that a ZIR instruction is tracked across incremental updates, and
/// thus may be given an `InternPool.TrackedInst`.
pub fn assertTrackable(zir: Zir, inst_idx: Zir.Inst.Index) void {
comptime assert(Zir.inst_tracking_version == 0);
const inst = zir.instructions.get(@intFromEnum(inst_idx));
switch (inst.tag) {
.struct_init,
.struct_init_ref,
.struct_init_anon,
=> {}, // tracked in order, as the owner instructions of anonymous struct types
.func,
.func_inferred,
.func_fancy,
=> {}, // tracked in order, as the owner instructions of function bodies
.declaration => {}, // tracked by correlating names in the namespace of the parent container
.extended => switch (inst.data.extended.opcode) {
.struct_decl,
.union_decl,
.enum_decl,
.opaque_decl,
.reify,
=> {}, // tracked in order, as the owner instructions of explicit container types
else => unreachable, // assertion failure; not trackable
},
else => unreachable, // assertion failure; not trackable
}
}

View File

@ -277,7 +277,7 @@ const SystemVersionTokenizer = struct {
}; };
test "detect" { test "detect" {
const cases = .{ const cases: [5]struct { []const u8, std.SemanticVersion } = .{
.{ .{
\\<?xml version="1.0" encoding="UTF-8"?> \\<?xml version="1.0" encoding="UTF-8"?>
\\<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> \\<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@ -388,8 +388,8 @@ test "detect" {
inline for (cases) |case| { inline for (cases) |case| {
const ver0 = try parseSystemVersion(case[0]); const ver0 = try parseSystemVersion(case[0]);
const ver1: std.SemanticVersion = case[1]; const ver1 = case[1];
try testing.expectEqual(@as(std.math.Order, .eq), ver0.order(ver1)); try testing.expectEqual(std.math.Order.eq, ver0.order(ver1));
} }
} }

View File

@ -962,7 +962,7 @@ pub const Inst = struct {
anyerror_void_error_union_type = @intFromEnum(InternPool.Index.anyerror_void_error_union_type), anyerror_void_error_union_type = @intFromEnum(InternPool.Index.anyerror_void_error_union_type),
adhoc_inferred_error_set_type = @intFromEnum(InternPool.Index.adhoc_inferred_error_set_type), adhoc_inferred_error_set_type = @intFromEnum(InternPool.Index.adhoc_inferred_error_set_type),
generic_poison_type = @intFromEnum(InternPool.Index.generic_poison_type), generic_poison_type = @intFromEnum(InternPool.Index.generic_poison_type),
empty_struct_type = @intFromEnum(InternPool.Index.empty_struct_type), empty_tuple_type = @intFromEnum(InternPool.Index.empty_tuple_type),
undef = @intFromEnum(InternPool.Index.undef), undef = @intFromEnum(InternPool.Index.undef),
zero = @intFromEnum(InternPool.Index.zero), zero = @intFromEnum(InternPool.Index.zero),
zero_usize = @intFromEnum(InternPool.Index.zero_usize), zero_usize = @intFromEnum(InternPool.Index.zero_usize),
@ -977,7 +977,7 @@ pub const Inst = struct {
null_value = @intFromEnum(InternPool.Index.null_value), null_value = @intFromEnum(InternPool.Index.null_value),
bool_true = @intFromEnum(InternPool.Index.bool_true), bool_true = @intFromEnum(InternPool.Index.bool_true),
bool_false = @intFromEnum(InternPool.Index.bool_false), bool_false = @intFromEnum(InternPool.Index.bool_false),
empty_struct = @intFromEnum(InternPool.Index.empty_struct), empty_tuple = @intFromEnum(InternPool.Index.empty_tuple),
generic_poison = @intFromEnum(InternPool.Index.generic_poison), generic_poison = @intFromEnum(InternPool.Index.generic_poison),
/// This Ref does not correspond to any AIR instruction or constant /// This Ref does not correspond to any AIR instruction or constant

View File

@ -501,7 +501,7 @@ pub fn checkType(ty: Type, zcu: *Zcu) bool {
.auto, .@"extern" => struct_obj.flagsUnordered(ip).fully_resolved, .auto, .@"extern" => struct_obj.flagsUnordered(ip).fully_resolved,
}; };
}, },
.anon_struct_type => |tuple| { .tuple_type => |tuple| {
for (0..tuple.types.len) |i| { for (0..tuple.types.len) |i| {
const field_is_comptime = tuple.values.get(ip)[i] != .none; const field_is_comptime = tuple.values.get(ip)[i] != .none;
if (field_is_comptime) continue; if (field_is_comptime) continue;

View File

@ -2081,7 +2081,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
log.debug("CacheMode.whole cache miss for {s}", .{comp.root_name}); log.debug("CacheMode.whole cache miss for {s}", .{comp.root_name});
// Compile the artifacts to a temporary directory. // Compile the artifacts to a temporary directory.
const tmp_artifact_directory = d: { const tmp_artifact_directory: Directory = d: {
const s = std.fs.path.sep_str; const s = std.fs.path.sep_str;
tmp_dir_rand_int = std.crypto.random.int(u64); tmp_dir_rand_int = std.crypto.random.int(u64);
const tmp_dir_sub_path = "tmp" ++ s ++ std.fmt.hex(tmp_dir_rand_int); const tmp_dir_sub_path = "tmp" ++ s ++ std.fmt.hex(tmp_dir_rand_int);

View File

@ -1787,10 +1787,11 @@ pub const Key = union(enum) {
/// or was created with `@Type`. It is unique and based on a declaration. /// or was created with `@Type`. It is unique and based on a declaration.
/// It may be a tuple, if declared like this: `struct {A, B, C}`. /// It may be a tuple, if declared like this: `struct {A, B, C}`.
struct_type: NamespaceType, struct_type: NamespaceType,
/// This is an anonymous struct or tuple type which has no corresponding /// This is a tuple type. Tuples are logically similar to structs, but have some
/// declaration. It is used for types that have no `struct` keyword in the /// important differences in semantics; they do not undergo staged type resolution,
/// source code, and were not created via `@Type`. /// so cannot be self-referential, and they are not considered container/namespace
anon_struct_type: AnonStructType, /// types, so cannot have declarations and have structural equality properties.
tuple_type: TupleType,
union_type: NamespaceType, union_type: NamespaceType,
opaque_type: NamespaceType, opaque_type: NamespaceType,
enum_type: NamespaceType, enum_type: NamespaceType,
@ -1919,27 +1920,10 @@ pub const Key = union(enum) {
child: Index, child: Index,
}; };
pub const AnonStructType = struct { pub const TupleType = struct {
types: Index.Slice, types: Index.Slice,
/// This may be empty, indicating this is a tuple.
names: NullTerminatedString.Slice,
/// These elements may be `none`, indicating runtime-known. /// These elements may be `none`, indicating runtime-known.
values: Index.Slice, values: Index.Slice,
pub fn isTuple(self: AnonStructType) bool {
return self.names.len == 0;
}
pub fn fieldName(
self: AnonStructType,
ip: *const InternPool,
index: usize,
) OptionalNullTerminatedString {
if (self.names.len == 0)
return .none;
return self.names.get(ip)[index].toOptional();
}
}; };
/// This is the hashmap key. To fetch other data associated with the type, see: /// This is the hashmap key. To fetch other data associated with the type, see:
@ -1965,18 +1949,15 @@ pub const Key = union(enum) {
/// The union for which this is a tag type. /// The union for which this is a tag type.
union_type: Index, union_type: Index,
}, },
/// This type originates from a reification via `@Type`. /// This type originates from a reification via `@Type`, or from an anonymous initialization.
/// It is hased based on its ZIR instruction index and fields, attributes, etc. /// It is hashed based on its ZIR instruction index and fields, attributes, etc.
/// To avoid making this key overly complex, the type-specific data is hased by Sema. /// To avoid making this key overly complex, the type-specific data is hased by Sema.
reified: struct { reified: struct {
/// A `reify` instruction. /// A `reify`, `struct_init`, `struct_init_ref`, or `struct_init_anon` instruction.
zir_index: TrackedInst.Index, zir_index: TrackedInst.Index,
/// A hash of this type's attributes, fields, etc, generated by Sema. /// A hash of this type's attributes, fields, etc, generated by Sema.
type_hash: u64, type_hash: u64,
}, },
/// This type is `@TypeOf(.{})`.
/// TODO: can we change the language spec to not special-case this type?
empty_struct: void,
}; };
pub const FuncType = struct { pub const FuncType = struct {
@ -2497,7 +2478,6 @@ pub const Key = union(enum) {
std.hash.autoHash(&hasher, reified.zir_index); std.hash.autoHash(&hasher, reified.zir_index);
std.hash.autoHash(&hasher, reified.type_hash); std.hash.autoHash(&hasher, reified.type_hash);
}, },
.empty_struct => {},
} }
return hasher.final(); return hasher.final();
}, },
@ -2570,7 +2550,7 @@ pub const Key = union(enum) {
const child = switch (ip.indexToKey(aggregate.ty)) { const child = switch (ip.indexToKey(aggregate.ty)) {
.array_type => |array_type| array_type.child, .array_type => |array_type| array_type.child,
.vector_type => |vector_type| vector_type.child, .vector_type => |vector_type| vector_type.child,
.anon_struct_type, .struct_type => .none, .tuple_type, .struct_type => .none,
else => unreachable, else => unreachable,
}; };
@ -2625,11 +2605,10 @@ pub const Key = union(enum) {
.error_set_type => |x| Hash.hash(seed, std.mem.sliceAsBytes(x.names.get(ip))), .error_set_type => |x| Hash.hash(seed, std.mem.sliceAsBytes(x.names.get(ip))),
.anon_struct_type => |anon_struct_type| { .tuple_type => |tuple_type| {
var hasher = Hash.init(seed); var hasher = Hash.init(seed);
for (anon_struct_type.types.get(ip)) |elem| std.hash.autoHash(&hasher, elem); for (tuple_type.types.get(ip)) |elem| std.hash.autoHash(&hasher, elem);
for (anon_struct_type.values.get(ip)) |elem| std.hash.autoHash(&hasher, elem); for (tuple_type.values.get(ip)) |elem| std.hash.autoHash(&hasher, elem);
for (anon_struct_type.names.get(ip)) |elem| std.hash.autoHash(&hasher, elem);
return hasher.final(); return hasher.final();
}, },
@ -2929,7 +2908,6 @@ pub const Key = union(enum) {
return a_r.zir_index == b_r.zir_index and return a_r.zir_index == b_r.zir_index and
a_r.type_hash == b_r.type_hash; a_r.type_hash == b_r.type_hash;
}, },
.empty_struct => return true,
} }
}, },
.aggregate => |a_info| { .aggregate => |a_info| {
@ -2981,11 +2959,10 @@ pub const Key = union(enum) {
}, },
} }
}, },
.anon_struct_type => |a_info| { .tuple_type => |a_info| {
const b_info = b.anon_struct_type; const b_info = b.tuple_type;
return std.mem.eql(Index, a_info.types.get(ip), b_info.types.get(ip)) and return std.mem.eql(Index, a_info.types.get(ip), b_info.types.get(ip)) and
std.mem.eql(Index, a_info.values.get(ip), b_info.values.get(ip)) and std.mem.eql(Index, a_info.values.get(ip), b_info.values.get(ip));
std.mem.eql(NullTerminatedString, a_info.names.get(ip), b_info.names.get(ip));
}, },
.error_set_type => |a_info| { .error_set_type => |a_info| {
const b_info = b.error_set_type; const b_info = b.error_set_type;
@ -3025,7 +3002,7 @@ pub const Key = union(enum) {
.union_type, .union_type,
.opaque_type, .opaque_type,
.enum_type, .enum_type,
.anon_struct_type, .tuple_type,
.func_type, .func_type,
=> .type_type, => .type_type,
@ -3054,7 +3031,7 @@ pub const Key = union(enum) {
.void => .void_type, .void => .void_type,
.null => .null_type, .null => .null_type,
.false, .true => .bool_type, .false, .true => .bool_type,
.empty_struct => .empty_struct_type, .empty_tuple => .empty_tuple_type,
.@"unreachable" => .noreturn_type, .@"unreachable" => .noreturn_type,
.generic_poison => .generic_poison_type, .generic_poison => .generic_poison_type,
}, },
@ -3411,13 +3388,11 @@ pub const LoadedStructType = struct {
// TODO: the non-fqn will be needed by the new dwarf structure // TODO: the non-fqn will be needed by the new dwarf structure
/// The name of this struct type. /// The name of this struct type.
name: NullTerminatedString, name: NullTerminatedString,
/// The `Cau` within which type resolution occurs. `none` when the struct is `@TypeOf(.{})`. /// The `Cau` within which type resolution occurs.
cau: Cau.Index.Optional, cau: Cau.Index,
/// `none` when the struct is `@TypeOf(.{})`. namespace: NamespaceIndex,
namespace: OptionalNamespaceIndex,
/// Index of the `struct_decl` or `reify` ZIR instruction. /// Index of the `struct_decl` or `reify` ZIR instruction.
/// Only `none` when the struct is `@TypeOf(.{})`. zir_index: TrackedInst.Index,
zir_index: TrackedInst.Index.Optional,
layout: std.builtin.Type.ContainerLayout, layout: std.builtin.Type.ContainerLayout,
field_names: NullTerminatedString.Slice, field_names: NullTerminatedString.Slice,
field_types: Index.Slice, field_types: Index.Slice,
@ -3913,10 +3888,6 @@ pub const LoadedStructType = struct {
@atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release); @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
} }
pub fn isTuple(s: LoadedStructType, ip: *InternPool) bool {
return s.layout != .@"packed" and s.flagsUnordered(ip).is_tuple;
}
pub fn hasReorderedFields(s: LoadedStructType) bool { pub fn hasReorderedFields(s: LoadedStructType) bool {
return s.layout == .auto; return s.layout == .auto;
} }
@ -4008,24 +3979,6 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
const item = unwrapped_index.getItem(ip); const item = unwrapped_index.getItem(ip);
switch (item.tag) { switch (item.tag) {
.type_struct => { .type_struct => {
if (item.data == 0) return .{
.tid = .main,
.extra_index = 0,
.name = .empty,
.cau = .none,
.namespace = .none,
.zir_index = .none,
.layout = .auto,
.field_names = NullTerminatedString.Slice.empty,
.field_types = Index.Slice.empty,
.field_inits = Index.Slice.empty,
.field_aligns = Alignment.Slice.empty,
.runtime_order = LoadedStructType.RuntimeOrder.Slice.empty,
.comptime_bits = LoadedStructType.ComptimeBits.empty,
.offsets = LoadedStructType.Offsets.empty,
.names_map = .none,
.captures = CaptureValue.Slice.empty,
};
const name: NullTerminatedString = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "name").?]); const name: NullTerminatedString = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "name").?]);
const cau: Cau.Index = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "cau").?]); const cau: Cau.Index = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "cau").?]);
const namespace: NamespaceIndex = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?]); const namespace: NamespaceIndex = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?]);
@ -4045,7 +3998,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
}; };
extra_index += captures_len; extra_index += captures_len;
if (flags.is_reified) { if (flags.is_reified) {
extra_index += 2; // PackedU64 extra_index += 2; // type_hash: PackedU64
} }
const field_types: Index.Slice = .{ const field_types: Index.Slice = .{
.tid = unwrapped_index.tid, .tid = unwrapped_index.tid,
@ -4053,7 +4006,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
.len = fields_len, .len = fields_len,
}; };
extra_index += fields_len; extra_index += fields_len;
const names_map: OptionalMapIndex, const names = if (!flags.is_tuple) n: { const names_map: OptionalMapIndex, const names = n: {
const names_map: OptionalMapIndex = @enumFromInt(extra_list.view().items(.@"0")[extra_index]); const names_map: OptionalMapIndex = @enumFromInt(extra_list.view().items(.@"0")[extra_index]);
extra_index += 1; extra_index += 1;
const names: NullTerminatedString.Slice = .{ const names: NullTerminatedString.Slice = .{
@ -4063,7 +4016,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
}; };
extra_index += fields_len; extra_index += fields_len;
break :n .{ names_map, names }; break :n .{ names_map, names };
} else .{ .none, NullTerminatedString.Slice.empty }; };
const inits: Index.Slice = if (flags.any_default_inits) i: { const inits: Index.Slice = if (flags.any_default_inits) i: {
const inits: Index.Slice = .{ const inits: Index.Slice = .{
.tid = unwrapped_index.tid, .tid = unwrapped_index.tid,
@ -4114,9 +4067,9 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
.tid = unwrapped_index.tid, .tid = unwrapped_index.tid,
.extra_index = item.data, .extra_index = item.data,
.name = name, .name = name,
.cau = cau.toOptional(), .cau = cau,
.namespace = namespace.toOptional(), .namespace = namespace,
.zir_index = zir_index.toOptional(), .zir_index = zir_index,
.layout = if (flags.is_extern) .@"extern" else .auto, .layout = if (flags.is_extern) .@"extern" else .auto,
.field_names = names, .field_names = names,
.field_types = field_types, .field_types = field_types,
@ -4178,9 +4131,9 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
.tid = unwrapped_index.tid, .tid = unwrapped_index.tid,
.extra_index = item.data, .extra_index = item.data,
.name = name, .name = name,
.cau = cau.toOptional(), .cau = cau,
.namespace = namespace.toOptional(), .namespace = namespace,
.zir_index = zir_index.toOptional(), .zir_index = zir_index,
.layout = .@"packed", .layout = .@"packed",
.field_names = field_names, .field_names = field_names,
.field_types = field_types, .field_types = field_types,
@ -4407,9 +4360,9 @@ pub const Item = struct {
/// `primitives` in AstGen.zig. /// `primitives` in AstGen.zig.
pub const Index = enum(u32) { pub const Index = enum(u32) {
pub const first_type: Index = .u0_type; pub const first_type: Index = .u0_type;
pub const last_type: Index = .empty_struct_type; pub const last_type: Index = .empty_tuple_type;
pub const first_value: Index = .undef; pub const first_value: Index = .undef;
pub const last_value: Index = .empty_struct; pub const last_value: Index = .empty_tuple;
u0_type, u0_type,
i0_type, i0_type,
@ -4466,8 +4419,9 @@ pub const Index = enum(u32) {
/// Used for the inferred error set of inline/comptime function calls. /// Used for the inferred error set of inline/comptime function calls.
adhoc_inferred_error_set_type, adhoc_inferred_error_set_type,
generic_poison_type, generic_poison_type,
/// `@TypeOf(.{})` /// `@TypeOf(.{})`; a tuple with zero elements.
empty_struct_type, /// This is not the same as `struct {}`, since that is a struct rather than a tuple.
empty_tuple_type,
/// `undefined` (untyped) /// `undefined` (untyped)
undef, undef,
@ -4497,8 +4451,8 @@ pub const Index = enum(u32) {
bool_true, bool_true,
/// `false` /// `false`
bool_false, bool_false,
/// `.{}` (untyped) /// `.{}`
empty_struct, empty_tuple,
/// Used for generic parameters where the type and value /// Used for generic parameters where the type and value
/// is not known until generic function instantiation. /// is not known until generic function instantiation.
@ -4606,16 +4560,14 @@ pub const Index = enum(u32) {
values: []Index, values: []Index,
}, },
}; };
const DataIsExtraIndexOfTypeStructAnon = struct { const DataIsExtraIndexOfTypeTuple = struct {
const @"data.fields_len" = opaque {}; const @"data.fields_len" = opaque {};
data: *TypeStructAnon, data: *TypeTuple,
@"trailing.types.len": *@"data.fields_len", @"trailing.types.len": *@"data.fields_len",
@"trailing.values.len": *@"data.fields_len", @"trailing.values.len": *@"data.fields_len",
@"trailing.names.len": *@"data.fields_len",
trailing: struct { trailing: struct {
types: []Index, types: []Index,
values: []Index, values: []Index,
names: []NullTerminatedString,
}, },
}; };
@ -4649,10 +4601,9 @@ pub const Index = enum(u32) {
simple_type: void, simple_type: void,
type_opaque: struct { data: *Tag.TypeOpaque }, type_opaque: struct { data: *Tag.TypeOpaque },
type_struct: struct { data: *Tag.TypeStruct }, type_struct: struct { data: *Tag.TypeStruct },
type_struct_anon: DataIsExtraIndexOfTypeStructAnon,
type_struct_packed: struct { data: *Tag.TypeStructPacked }, type_struct_packed: struct { data: *Tag.TypeStructPacked },
type_struct_packed_inits: struct { data: *Tag.TypeStructPacked }, type_struct_packed_inits: struct { data: *Tag.TypeStructPacked },
type_tuple_anon: DataIsExtraIndexOfTypeStructAnon, type_tuple: DataIsExtraIndexOfTypeTuple,
type_union: struct { data: *Tag.TypeUnion }, type_union: struct { data: *Tag.TypeUnion },
type_function: struct { type_function: struct {
const @"data.flags.has_comptime_bits" = opaque {}; const @"data.flags.has_comptime_bits" = opaque {};
@ -4936,11 +4887,10 @@ pub const static_keys = [_]Key{
// generic_poison_type // generic_poison_type
.{ .simple_type = .generic_poison }, .{ .simple_type = .generic_poison },
// empty_struct_type // empty_tuple_type
.{ .anon_struct_type = .{ .{ .tuple_type = .{
.types = Index.Slice.empty, .types = .empty,
.names = NullTerminatedString.Slice.empty, .values = .empty,
.values = Index.Slice.empty,
} }, } },
.{ .simple_value = .undefined }, .{ .simple_value = .undefined },
@ -4991,7 +4941,7 @@ pub const static_keys = [_]Key{
.{ .simple_value = .null }, .{ .simple_value = .null },
.{ .simple_value = .true }, .{ .simple_value = .true },
.{ .simple_value = .false }, .{ .simple_value = .false },
.{ .simple_value = .empty_struct }, .{ .simple_value = .empty_tuple },
.{ .simple_value = .generic_poison }, .{ .simple_value = .generic_poison },
}; };
@ -5071,20 +5021,16 @@ pub const Tag = enum(u8) {
type_opaque, type_opaque,
/// A non-packed struct type. /// A non-packed struct type.
/// data is 0 or extra index of `TypeStruct`. /// data is 0 or extra index of `TypeStruct`.
/// data == 0 represents `@TypeOf(.{})`.
type_struct, type_struct,
/// An AnonStructType which stores types, names, and values for fields.
/// data is extra index of `TypeStructAnon`.
type_struct_anon,
/// A packed struct, no fields have any init values. /// A packed struct, no fields have any init values.
/// data is extra index of `TypeStructPacked`. /// data is extra index of `TypeStructPacked`.
type_struct_packed, type_struct_packed,
/// A packed struct, one or more fields have init values. /// A packed struct, one or more fields have init values.
/// data is extra index of `TypeStructPacked`. /// data is extra index of `TypeStructPacked`.
type_struct_packed_inits, type_struct_packed_inits,
/// An AnonStructType which has only types and values for fields. /// A `TupleType`.
/// data is extra index of `TypeStructAnon`. /// data is extra index of `TypeTuple`.
type_tuple_anon, type_tuple,
/// A union type. /// A union type.
/// `data` is extra index of `TypeUnion`. /// `data` is extra index of `TypeUnion`.
type_union, type_union,
@ -5299,9 +5245,8 @@ pub const Tag = enum(u8) {
.simple_type => unreachable, .simple_type => unreachable,
.type_opaque => TypeOpaque, .type_opaque => TypeOpaque,
.type_struct => TypeStruct, .type_struct => TypeStruct,
.type_struct_anon => TypeStructAnon,
.type_struct_packed, .type_struct_packed_inits => TypeStructPacked, .type_struct_packed, .type_struct_packed_inits => TypeStructPacked,
.type_tuple_anon => TypeStructAnon, .type_tuple => TypeTuple,
.type_union => TypeUnion, .type_union => TypeUnion,
.type_function => TypeFunction, .type_function => TypeFunction,
@ -5546,18 +5491,15 @@ pub const Tag = enum(u8) {
/// 1. capture: CaptureValue // for each `captures_len` /// 1. capture: CaptureValue // for each `captures_len`
/// 2. type_hash: PackedU64 // if `is_reified` /// 2. type_hash: PackedU64 // if `is_reified`
/// 3. type: Index for each field in declared order /// 3. type: Index for each field in declared order
/// 4. if not is_tuple: /// 4. if any_default_inits:
/// names_map: MapIndex,
/// name: NullTerminatedString // for each field in declared order
/// 5. if any_default_inits:
/// init: Index // for each field in declared order /// init: Index // for each field in declared order
/// 6. if any_aligned_fields: /// 5. if any_aligned_fields:
/// align: Alignment // for each field in declared order /// align: Alignment // for each field in declared order
/// 7. if any_comptime_fields: /// 6. if any_comptime_fields:
/// field_is_comptime_bits: u32 // minimal number of u32s needed, LSB is field 0 /// field_is_comptime_bits: u32 // minimal number of u32s needed, LSB is field 0
/// 8. if not is_extern: /// 7. if not is_extern:
/// field_index: RuntimeOrder // for each field in runtime order /// field_index: RuntimeOrder // for each field in runtime order
/// 9. field_offset: u32 // for each field in declared order, undef until layout_resolved /// 8. field_offset: u32 // for each field in declared order, undef until layout_resolved
pub const TypeStruct = struct { pub const TypeStruct = struct {
name: NullTerminatedString, name: NullTerminatedString,
cau: Cau.Index, cau: Cau.Index,
@ -5572,7 +5514,6 @@ pub const Tag = enum(u8) {
is_extern: bool = false, is_extern: bool = false,
known_non_opv: bool = false, known_non_opv: bool = false,
requires_comptime: RequiresComptime = @enumFromInt(0), requires_comptime: RequiresComptime = @enumFromInt(0),
is_tuple: bool = false,
assumed_runtime_bits: bool = false, assumed_runtime_bits: bool = false,
assumed_pointer_aligned: bool = false, assumed_pointer_aligned: bool = false,
any_comptime_fields: bool = false, any_comptime_fields: bool = false,
@ -5597,7 +5538,7 @@ pub const Tag = enum(u8) {
// which `layout_resolved` does not ensure. // which `layout_resolved` does not ensure.
fully_resolved: bool = false, fully_resolved: bool = false,
is_reified: bool = false, is_reified: bool = false,
_: u7 = 0, _: u8 = 0,
}; };
}; };
@ -5659,9 +5600,7 @@ pub const Repeated = struct {
/// Trailing: /// Trailing:
/// 0. type: Index for each fields_len /// 0. type: Index for each fields_len
/// 1. value: Index for each fields_len /// 1. value: Index for each fields_len
/// 2. name: NullTerminatedString for each fields_len pub const TypeTuple = struct {
/// The set of field names is omitted when the `Tag` is `type_tuple_anon`.
pub const TypeStructAnon = struct {
fields_len: u32, fields_len: u32,
}; };
@ -5708,8 +5647,8 @@ pub const SimpleValue = enum(u32) {
void = @intFromEnum(Index.void_value), void = @intFromEnum(Index.void_value),
/// This is untyped `null`. /// This is untyped `null`.
null = @intFromEnum(Index.null_value), null = @intFromEnum(Index.null_value),
/// This is the untyped empty struct literal: `.{}` /// This is the untyped empty struct/array literal: `.{}`
empty_struct = @intFromEnum(Index.empty_struct), empty_tuple = @intFromEnum(Index.empty_tuple),
true = @intFromEnum(Index.bool_true), true = @intFromEnum(Index.bool_true),
false = @intFromEnum(Index.bool_false), false = @intFromEnum(Index.bool_false),
@"unreachable" = @intFromEnum(Index.unreachable_value), @"unreachable" = @intFromEnum(Index.unreachable_value),
@ -6266,11 +6205,10 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {
// This inserts all the statically-known values into the intern pool in the // This inserts all the statically-known values into the intern pool in the
// order expected. // order expected.
for (&static_keys, 0..) |key, key_index| switch (@as(Index, @enumFromInt(key_index))) { for (&static_keys, 0..) |key, key_index| switch (@as(Index, @enumFromInt(key_index))) {
.empty_struct_type => assert(try ip.getAnonStructType(gpa, .main, .{ .empty_tuple_type => assert(try ip.getTupleType(gpa, .main, .{
.types = &.{}, .types = &.{},
.names = &.{},
.values = &.{}, .values = &.{},
}) == .empty_struct_type), }) == .empty_tuple_type),
else => |expected_index| assert(try ip.get(gpa, .main, key) == expected_index), else => |expected_index| assert(try ip.get(gpa, .main, key) == expected_index),
}; };
@ -6412,7 +6350,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
} }, } },
.type_struct => .{ .struct_type = ns: { .type_struct => .{ .struct_type = ns: {
if (data == 0) break :ns .empty_struct;
const extra_list = unwrapped_index.getExtra(ip); const extra_list = unwrapped_index.getExtra(ip);
const extra_items = extra_list.view().items(.@"0"); const extra_items = extra_list.view().items(.@"0");
const zir_index: TrackedInst.Index = @enumFromInt(extra_items[data + std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?]); const zir_index: TrackedInst.Index = @enumFromInt(extra_items[data + std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?]);
@ -6457,8 +6394,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
} else CaptureValue.Slice.empty }, } else CaptureValue.Slice.empty },
} }; } };
} }, } },
.type_struct_anon => .{ .anon_struct_type = extraTypeStructAnon(unwrapped_index.tid, unwrapped_index.getExtra(ip), data) }, .type_tuple => .{ .tuple_type = extraTypeTuple(unwrapped_index.tid, unwrapped_index.getExtra(ip), data) },
.type_tuple_anon => .{ .anon_struct_type = extraTypeTupleAnon(unwrapped_index.tid, unwrapped_index.getExtra(ip), data) },
.type_union => .{ .union_type = ns: { .type_union => .{ .union_type = ns: {
const extra_list = unwrapped_index.getExtra(ip); const extra_list = unwrapped_index.getExtra(ip);
const extra = extraDataTrail(extra_list, Tag.TypeUnion, data); const extra = extraDataTrail(extra_list, Tag.TypeUnion, data);
@ -6764,10 +6700,10 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
// There is only one possible value precisely due to the // There is only one possible value precisely due to the
// fact that this values slice is fully populated! // fact that this values slice is fully populated!
.type_struct_anon, .type_tuple_anon => { .type_tuple => {
const type_struct_anon = extraDataTrail(ty_extra, TypeStructAnon, ty_item.data); const type_tuple = extraDataTrail(ty_extra, TypeTuple, ty_item.data);
const fields_len = type_struct_anon.data.fields_len; const fields_len = type_tuple.data.fields_len;
const values = ty_extra.view().items(.@"0")[type_struct_anon.end + fields_len ..][0..fields_len]; const values = ty_extra.view().items(.@"0")[type_tuple.end + fields_len ..][0..fields_len];
return .{ .aggregate = .{ return .{ .aggregate = .{
.ty = ty, .ty = ty,
.storage = .{ .elems = @ptrCast(values) }, .storage = .{ .elems = @ptrCast(values) },
@ -6850,47 +6786,20 @@ fn extraErrorSet(tid: Zcu.PerThread.Id, extra: Local.Extra, extra_index: u32) Ke
}; };
} }
fn extraTypeStructAnon(tid: Zcu.PerThread.Id, extra: Local.Extra, extra_index: u32) Key.AnonStructType { fn extraTypeTuple(tid: Zcu.PerThread.Id, extra: Local.Extra, extra_index: u32) Key.TupleType {
const type_struct_anon = extraDataTrail(extra, TypeStructAnon, extra_index); const type_tuple = extraDataTrail(extra, TypeTuple, extra_index);
const fields_len = type_struct_anon.data.fields_len; const fields_len = type_tuple.data.fields_len;
return .{ return .{
.types = .{ .types = .{
.tid = tid, .tid = tid,
.start = type_struct_anon.end, .start = type_tuple.end,
.len = fields_len, .len = fields_len,
}, },
.values = .{ .values = .{
.tid = tid, .tid = tid,
.start = type_struct_anon.end + fields_len, .start = type_tuple.end + fields_len,
.len = fields_len, .len = fields_len,
}, },
.names = .{
.tid = tid,
.start = type_struct_anon.end + fields_len + fields_len,
.len = fields_len,
},
};
}
fn extraTypeTupleAnon(tid: Zcu.PerThread.Id, extra: Local.Extra, extra_index: u32) Key.AnonStructType {
const type_struct_anon = extraDataTrail(extra, TypeStructAnon, extra_index);
const fields_len = type_struct_anon.data.fields_len;
return .{
.types = .{
.tid = tid,
.start = type_struct_anon.end,
.len = fields_len,
},
.values = .{
.tid = tid,
.start = type_struct_anon.end + fields_len,
.len = fields_len,
},
.names = .{
.tid = tid,
.start = 0,
.len = 0,
},
}; };
} }
@ -7361,7 +7270,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
}, },
.struct_type => unreachable, // use getStructType() instead .struct_type => unreachable, // use getStructType() instead
.anon_struct_type => unreachable, // use getAnonStructType() instead .tuple_type => unreachable, // use getTupleType() instead
.union_type => unreachable, // use getUnionType() instead .union_type => unreachable, // use getUnionType() instead
.opaque_type => unreachable, // use getOpaqueType() instead .opaque_type => unreachable, // use getOpaqueType() instead
@ -7469,9 +7378,9 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
.field => { .field => {
assert(base_ptr_type.flags.size == .One); assert(base_ptr_type.flags.size == .One);
switch (ip.indexToKey(base_ptr_type.child)) { switch (ip.indexToKey(base_ptr_type.child)) {
.anon_struct_type => |anon_struct_type| { .tuple_type => |tuple_type| {
assert(ptr.base_addr == .field); assert(ptr.base_addr == .field);
assert(base_index.index < anon_struct_type.types.len); assert(base_index.index < tuple_type.types.len);
}, },
.struct_type => { .struct_type => {
assert(ptr.base_addr == .field); assert(ptr.base_addr == .field);
@ -7808,12 +7717,12 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
const child = switch (ty_key) { const child = switch (ty_key) {
.array_type => |array_type| array_type.child, .array_type => |array_type| array_type.child,
.vector_type => |vector_type| vector_type.child, .vector_type => |vector_type| vector_type.child,
.anon_struct_type, .struct_type => .none, .tuple_type, .struct_type => .none,
else => unreachable, else => unreachable,
}; };
const sentinel = switch (ty_key) { const sentinel = switch (ty_key) {
.array_type => |array_type| array_type.sentinel, .array_type => |array_type| array_type.sentinel,
.vector_type, .anon_struct_type, .struct_type => .none, .vector_type, .tuple_type, .struct_type => .none,
else => unreachable, else => unreachable,
}; };
const len_including_sentinel = len + @intFromBool(sentinel != .none); const len_including_sentinel = len + @intFromBool(sentinel != .none);
@ -7845,8 +7754,8 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
assert(ip.typeOf(elem) == field_ty); assert(ip.typeOf(elem) == field_ty);
} }
}, },
.anon_struct_type => |anon_struct_type| { .tuple_type => |tuple_type| {
for (aggregate.storage.values(), anon_struct_type.types.get(ip)) |elem, ty| { for (aggregate.storage.values(), tuple_type.types.get(ip)) |elem, ty| {
assert(ip.typeOf(elem) == ty); assert(ip.typeOf(elem) == ty);
} }
}, },
@ -7862,9 +7771,9 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
} }
switch (ty_key) { switch (ty_key) {
.anon_struct_type => |anon_struct_type| opv: { .tuple_type => |tuple_type| opv: {
switch (aggregate.storage) { switch (aggregate.storage) {
.bytes => |bytes| for (anon_struct_type.values.get(ip), bytes.at(0, ip)..) |value, byte| { .bytes => |bytes| for (tuple_type.values.get(ip), bytes.at(0, ip)..) |value, byte| {
if (value == .none) break :opv; if (value == .none) break :opv;
switch (ip.indexToKey(value)) { switch (ip.indexToKey(value)) {
.undef => break :opv, .undef => break :opv,
@ -7877,10 +7786,10 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
}, },
.elems => |elems| if (!std.mem.eql( .elems => |elems| if (!std.mem.eql(
Index, Index,
anon_struct_type.values.get(ip), tuple_type.values.get(ip),
elems, elems,
)) break :opv, )) break :opv,
.repeated_elem => |elem| for (anon_struct_type.values.get(ip)) |value| { .repeated_elem => |elem| for (tuple_type.values.get(ip)) |value| {
if (value != elem) break :opv; if (value != elem) break :opv;
}, },
} }
@ -8244,7 +8153,6 @@ pub const StructTypeInit = struct {
fields_len: u32, fields_len: u32,
known_non_opv: bool, known_non_opv: bool,
requires_comptime: RequiresComptime, requires_comptime: RequiresComptime,
is_tuple: bool,
any_comptime_fields: bool, any_comptime_fields: bool,
any_default_inits: bool, any_default_inits: bool,
inits_resolved: bool, inits_resolved: bool,
@ -8404,7 +8312,6 @@ pub fn getStructType(
.is_extern = is_extern, .is_extern = is_extern,
.known_non_opv = ini.known_non_opv, .known_non_opv = ini.known_non_opv,
.requires_comptime = ini.requires_comptime, .requires_comptime = ini.requires_comptime,
.is_tuple = ini.is_tuple,
.assumed_runtime_bits = false, .assumed_runtime_bits = false,
.assumed_pointer_aligned = false, .assumed_pointer_aligned = false,
.any_comptime_fields = ini.any_comptime_fields, .any_comptime_fields = ini.any_comptime_fields,
@ -8442,10 +8349,8 @@ pub fn getStructType(
}, },
} }
extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len);
if (!ini.is_tuple) { extra.appendAssumeCapacity(.{@intFromEnum(names_map)});
extra.appendAssumeCapacity(.{@intFromEnum(names_map)}); extra.appendNTimesAssumeCapacity(.{@intFromEnum(OptionalNullTerminatedString.none)}, ini.fields_len);
extra.appendNTimesAssumeCapacity(.{@intFromEnum(OptionalNullTerminatedString.none)}, ini.fields_len);
}
if (ini.any_default_inits) { if (ini.any_default_inits) {
extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len);
} }
@ -8468,19 +8373,17 @@ pub fn getStructType(
} }; } };
} }
pub const AnonStructTypeInit = struct { pub const TupleTypeInit = struct {
types: []const Index, types: []const Index,
/// This may be empty, indicating this is a tuple.
names: []const NullTerminatedString,
/// These elements may be `none`, indicating runtime-known. /// These elements may be `none`, indicating runtime-known.
values: []const Index, values: []const Index,
}; };
pub fn getAnonStructType( pub fn getTupleType(
ip: *InternPool, ip: *InternPool,
gpa: Allocator, gpa: Allocator,
tid: Zcu.PerThread.Id, tid: Zcu.PerThread.Id,
ini: AnonStructTypeInit, ini: TupleTypeInit,
) Allocator.Error!Index { ) Allocator.Error!Index {
assert(ini.types.len == ini.values.len); assert(ini.types.len == ini.values.len);
for (ini.types) |elem| assert(elem != .none); for (ini.types) |elem| assert(elem != .none);
@ -8494,23 +8397,17 @@ pub fn getAnonStructType(
try items.ensureUnusedCapacity(1); try items.ensureUnusedCapacity(1);
try extra.ensureUnusedCapacity( try extra.ensureUnusedCapacity(
@typeInfo(TypeStructAnon).@"struct".fields.len + (fields_len * 3), @typeInfo(TypeTuple).@"struct".fields.len + (fields_len * 3),
); );
const extra_index = addExtraAssumeCapacity(extra, TypeStructAnon{ const extra_index = addExtraAssumeCapacity(extra, TypeTuple{
.fields_len = fields_len, .fields_len = fields_len,
}); });
extra.appendSliceAssumeCapacity(.{@ptrCast(ini.types)}); extra.appendSliceAssumeCapacity(.{@ptrCast(ini.types)});
extra.appendSliceAssumeCapacity(.{@ptrCast(ini.values)}); extra.appendSliceAssumeCapacity(.{@ptrCast(ini.values)});
errdefer extra.mutate.len = prev_extra_len; errdefer extra.mutate.len = prev_extra_len;
var gop = try ip.getOrPutKey(gpa, tid, .{ var gop = try ip.getOrPutKey(gpa, tid, .{ .tuple_type = extraTypeTuple(tid, extra.list.*, extra_index) });
.anon_struct_type = if (ini.names.len == 0) extraTypeTupleAnon(tid, extra.list.*, extra_index) else k: {
assert(ini.names.len == ini.types.len);
extra.appendSliceAssumeCapacity(.{@ptrCast(ini.names)});
break :k extraTypeStructAnon(tid, extra.list.*, extra_index);
},
});
defer gop.deinit(); defer gop.deinit();
if (gop == .existing) { if (gop == .existing) {
extra.mutate.len = prev_extra_len; extra.mutate.len = prev_extra_len;
@ -8518,7 +8415,7 @@ pub fn getAnonStructType(
} }
items.appendAssumeCapacity(.{ items.appendAssumeCapacity(.{
.tag = if (ini.names.len == 0) .type_tuple_anon else .type_struct_anon, .tag = .type_tuple,
.data = extra_index, .data = extra_index,
}); });
return gop.put(); return gop.put();
@ -10181,12 +10078,12 @@ pub fn getCoerced(
direct: { direct: {
const old_ty_child = switch (ip.indexToKey(old_ty)) { const old_ty_child = switch (ip.indexToKey(old_ty)) {
inline .array_type, .vector_type => |seq_type| seq_type.child, inline .array_type, .vector_type => |seq_type| seq_type.child,
.anon_struct_type, .struct_type => break :direct, .tuple_type, .struct_type => break :direct,
else => unreachable, else => unreachable,
}; };
const new_ty_child = switch (ip.indexToKey(new_ty)) { const new_ty_child = switch (ip.indexToKey(new_ty)) {
inline .array_type, .vector_type => |seq_type| seq_type.child, inline .array_type, .vector_type => |seq_type| seq_type.child,
.anon_struct_type, .struct_type => break :direct, .tuple_type, .struct_type => break :direct,
else => unreachable, else => unreachable,
}; };
if (old_ty_child != new_ty_child) break :direct; if (old_ty_child != new_ty_child) break :direct;
@ -10235,7 +10132,7 @@ pub fn getCoerced(
for (agg_elems, 0..) |*elem, i| { for (agg_elems, 0..) |*elem, i| {
const new_elem_ty = switch (ip.indexToKey(new_ty)) { const new_elem_ty = switch (ip.indexToKey(new_ty)) {
inline .array_type, .vector_type => |seq_type| seq_type.child, inline .array_type, .vector_type => |seq_type| seq_type.child,
.anon_struct_type => |anon_struct_type| anon_struct_type.types.get(ip)[i], .tuple_type => |tuple_type| tuple_type.types.get(ip)[i],
.struct_type => ip.loadStructType(new_ty).field_types.get(ip)[i], .struct_type => ip.loadStructType(new_ty).field_types.get(ip)[i],
else => unreachable, else => unreachable,
}; };
@ -10425,7 +10322,7 @@ pub fn isErrorUnionType(ip: *const InternPool, ty: Index) bool {
pub fn isAggregateType(ip: *const InternPool, ty: Index) bool { pub fn isAggregateType(ip: *const InternPool, ty: Index) bool {
return switch (ip.indexToKey(ty)) { return switch (ip.indexToKey(ty)) {
.array_type, .vector_type, .anon_struct_type, .struct_type => true, .array_type, .vector_type, .tuple_type, .struct_type => true,
else => false, else => false,
}; };
} }
@ -10549,7 +10446,6 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
break :b @sizeOf(u32) * ints; break :b @sizeOf(u32) * ints;
}, },
.type_struct => b: { .type_struct => b: {
if (data == 0) break :b 0;
const extra = extraDataTrail(extra_list, Tag.TypeStruct, data); const extra = extraDataTrail(extra_list, Tag.TypeStruct, data);
const info = extra.data; const info = extra.data;
var ints: usize = @typeInfo(Tag.TypeStruct).@"struct".fields.len; var ints: usize = @typeInfo(Tag.TypeStruct).@"struct".fields.len;
@ -10558,10 +10454,8 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
ints += 1 + captures_len; ints += 1 + captures_len;
} }
ints += info.fields_len; // types ints += info.fields_len; // types
if (!info.flags.is_tuple) { ints += 1; // names_map
ints += 1; // names_map ints += info.fields_len; // names
ints += info.fields_len; // names
}
if (info.flags.any_default_inits) if (info.flags.any_default_inits)
ints += info.fields_len; // inits ints += info.fields_len; // inits
if (info.flags.any_aligned_fields) if (info.flags.any_aligned_fields)
@ -10573,10 +10467,6 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
ints += info.fields_len; // offsets ints += info.fields_len; // offsets
break :b @sizeOf(u32) * ints; break :b @sizeOf(u32) * ints;
}, },
.type_struct_anon => b: {
const info = extraData(extra_list, TypeStructAnon, data);
break :b @sizeOf(TypeStructAnon) + (@sizeOf(u32) * 3 * info.fields_len);
},
.type_struct_packed => b: { .type_struct_packed => b: {
const extra = extraDataTrail(extra_list, Tag.TypeStructPacked, data); const extra = extraDataTrail(extra_list, Tag.TypeStructPacked, data);
const captures_len = if (extra.data.flags.any_captures) const captures_len = if (extra.data.flags.any_captures)
@ -10597,9 +10487,9 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
@intFromBool(extra.data.flags.any_captures) + captures_len + @intFromBool(extra.data.flags.any_captures) + captures_len +
extra.data.fields_len * 3); extra.data.fields_len * 3);
}, },
.type_tuple_anon => b: { .type_tuple => b: {
const info = extraData(extra_list, TypeStructAnon, data); const info = extraData(extra_list, TypeTuple, data);
break :b @sizeOf(TypeStructAnon) + (@sizeOf(u32) * 2 * info.fields_len); break :b @sizeOf(TypeTuple) + (@sizeOf(u32) * 2 * info.fields_len);
}, },
.type_union => b: { .type_union => b: {
@ -10760,10 +10650,9 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
.type_enum_auto, .type_enum_auto,
.type_opaque, .type_opaque,
.type_struct, .type_struct,
.type_struct_anon,
.type_struct_packed, .type_struct_packed,
.type_struct_packed_inits, .type_struct_packed_inits,
.type_tuple_anon, .type_tuple,
.type_union, .type_union,
.type_function, .type_function,
.undef, .undef,
@ -11396,7 +11285,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
.anyerror_void_error_union_type, .anyerror_void_error_union_type,
.adhoc_inferred_error_set_type, .adhoc_inferred_error_set_type,
.generic_poison_type, .generic_poison_type,
.empty_struct_type, .empty_tuple_type,
=> .type_type, => .type_type,
.undef => .undefined_type, .undef => .undefined_type,
@ -11407,7 +11296,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
.unreachable_value => .noreturn_type, .unreachable_value => .noreturn_type,
.null_value => .null_type, .null_value => .null_type,
.bool_true, .bool_false => .bool_type, .bool_true, .bool_false => .bool_type,
.empty_struct => .empty_struct_type, .empty_tuple => .empty_tuple_type,
.generic_poison => .generic_poison_type, .generic_poison => .generic_poison_type,
// This optimization on tags is needed so that indexToKey can call // This optimization on tags is needed so that indexToKey can call
@ -11436,10 +11325,9 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
.type_enum_nonexhaustive, .type_enum_nonexhaustive,
.type_opaque, .type_opaque,
.type_struct, .type_struct,
.type_struct_anon,
.type_struct_packed, .type_struct_packed,
.type_struct_packed_inits, .type_struct_packed_inits,
.type_tuple_anon, .type_tuple,
.type_union, .type_union,
.type_function, .type_function,
=> .type_type, => .type_type,
@ -11533,7 +11421,7 @@ pub fn toEnum(ip: *const InternPool, comptime E: type, i: Index) E {
pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 { pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 {
return switch (ip.indexToKey(ty)) { return switch (ip.indexToKey(ty)) {
.struct_type => ip.loadStructType(ty).field_types.len, .struct_type => ip.loadStructType(ty).field_types.len,
.anon_struct_type => |anon_struct_type| anon_struct_type.types.len, .tuple_type => |tuple_type| tuple_type.types.len,
.array_type => |array_type| array_type.len, .array_type => |array_type| array_type.len,
.vector_type => |vector_type| vector_type.len, .vector_type => |vector_type| vector_type.len,
else => unreachable, else => unreachable,
@ -11543,7 +11431,7 @@ pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 {
pub fn aggregateTypeLenIncludingSentinel(ip: *const InternPool, ty: Index) u64 { pub fn aggregateTypeLenIncludingSentinel(ip: *const InternPool, ty: Index) u64 {
return switch (ip.indexToKey(ty)) { return switch (ip.indexToKey(ty)) {
.struct_type => ip.loadStructType(ty).field_types.len, .struct_type => ip.loadStructType(ty).field_types.len,
.anon_struct_type => |anon_struct_type| anon_struct_type.types.len, .tuple_type => |tuple_type| tuple_type.types.len,
.array_type => |array_type| array_type.lenIncludingSentinel(), .array_type => |array_type| array_type.lenIncludingSentinel(),
.vector_type => |vector_type| vector_type.len, .vector_type => |vector_type| vector_type.len,
else => unreachable, else => unreachable,
@ -11708,7 +11596,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois
.optional_noreturn_type => .optional, .optional_noreturn_type => .optional,
.anyerror_void_error_union_type => .error_union, .anyerror_void_error_union_type => .error_union,
.empty_struct_type => .@"struct", .empty_tuple_type => .@"struct",
.generic_poison_type => return error.GenericPoison, .generic_poison_type => return error.GenericPoison,
@ -11727,7 +11615,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois
.null_value => unreachable, .null_value => unreachable,
.bool_true => unreachable, .bool_true => unreachable,
.bool_false => unreachable, .bool_false => unreachable,
.empty_struct => unreachable, .empty_tuple => unreachable,
.generic_poison => unreachable, .generic_poison => unreachable,
_ => switch (index.unwrap(ip).getTag(ip)) { _ => switch (index.unwrap(ip).getTag(ip)) {
@ -11768,10 +11656,9 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois
.type_opaque => .@"opaque", .type_opaque => .@"opaque",
.type_struct, .type_struct,
.type_struct_anon,
.type_struct_packed, .type_struct_packed,
.type_struct_packed_inits, .type_struct_packed_inits,
.type_tuple_anon, .type_tuple,
=> .@"struct", => .@"struct",
.type_union => .@"union", .type_union => .@"union",
@ -12013,14 +11900,6 @@ pub fn unwrapCoercedFunc(ip: *const InternPool, index: Index) Index {
}; };
} }
pub fn anonStructFieldTypes(ip: *const InternPool, i: Index) []const Index {
return ip.indexToKey(i).anon_struct_type.types;
}
pub fn anonStructFieldsLen(ip: *const InternPool, i: Index) u32 {
return @intCast(ip.indexToKey(i).anon_struct_type.types.len);
}
/// Returns the already-existing field with the same name, if any. /// Returns the already-existing field with the same name, if any.
pub fn addFieldName( pub fn addFieldName(
ip: *InternPool, ip: *InternPool,

File diff suppressed because it is too large Load Diff

View File

@ -246,7 +246,7 @@ const UnpackValueBits = struct {
.error_union_type, .error_union_type,
.simple_type, .simple_type,
.struct_type, .struct_type,
.anon_struct_type, .tuple_type,
.union_type, .union_type,
.opaque_type, .opaque_type,
.enum_type, .enum_type,

View File

@ -320,33 +320,20 @@ pub fn print(ty: Type, writer: anytype, pt: Zcu.PerThread) @TypeOf(writer).Error
}, },
.struct_type => { .struct_type => {
const name = ip.loadStructType(ty.toIntern()).name; const name = ip.loadStructType(ty.toIntern()).name;
if (name == .empty) { try writer.print("{}", .{name.fmt(ip)});
try writer.writeAll("@TypeOf(.{})");
} else {
try writer.print("{}", .{name.fmt(ip)});
}
}, },
.anon_struct_type => |anon_struct| { .tuple_type => |tuple| {
if (anon_struct.types.len == 0) { if (tuple.types.len == 0) {
return writer.writeAll("@TypeOf(.{})"); return writer.writeAll("@TypeOf(.{})");
} }
try writer.writeAll("struct{"); try writer.writeAll("struct {");
for (anon_struct.types.get(ip), anon_struct.values.get(ip), 0..) |field_ty, val, i| { for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, val, i| {
if (i != 0) try writer.writeAll(", "); try writer.writeAll(if (i == 0) " " else ", ");
if (val != .none) { if (val != .none) try writer.writeAll("comptime ");
try writer.writeAll("comptime ");
}
if (anon_struct.names.len != 0) {
try writer.print("{}: ", .{anon_struct.names.get(ip)[i].fmt(&zcu.intern_pool)});
}
try print(Type.fromInterned(field_ty), writer, pt); try print(Type.fromInterned(field_ty), writer, pt);
if (val != .none) try writer.print(" = {}", .{Value.fromInterned(val).fmtValue(pt)});
if (val != .none) {
try writer.print(" = {}", .{Value.fromInterned(val).fmtValue(pt)});
}
} }
try writer.writeAll("}"); try writer.writeAll(" }");
}, },
.union_type => { .union_type => {
@ -489,8 +476,7 @@ pub fn hasRuntimeBitsInner(
) RuntimeBitsError!bool { ) RuntimeBitsError!bool {
const ip = &zcu.intern_pool; const ip = &zcu.intern_pool;
return switch (ty.toIntern()) { return switch (ty.toIntern()) {
// False because it is a comptime-only type. .empty_tuple_type => false,
.empty_struct_type => false,
else => switch (ip.indexToKey(ty.toIntern())) { else => switch (ip.indexToKey(ty.toIntern())) {
.int_type => |int_type| int_type.bits != 0, .int_type => |int_type| int_type.bits != 0,
.ptr_type => { .ptr_type => {
@ -593,7 +579,7 @@ pub fn hasRuntimeBitsInner(
return false; return false;
} }
}, },
.anon_struct_type => |tuple| { .tuple_type => |tuple| {
for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| { for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
if (val != .none) continue; // comptime field if (val != .none) continue; // comptime field
if (try Type.fromInterned(field_ty).hasRuntimeBitsInner( if (try Type.fromInterned(field_ty).hasRuntimeBitsInner(
@ -691,7 +677,7 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool {
.error_union_type, .error_union_type,
.error_set_type, .error_set_type,
.inferred_error_set_type, .inferred_error_set_type,
.anon_struct_type, .tuple_type,
.opaque_type, .opaque_type,
.anyframe_type, .anyframe_type,
// These are function bodies, not function pointers. // These are function bodies, not function pointers.
@ -966,7 +952,7 @@ pub fn abiAlignmentInner(
const ip = &zcu.intern_pool; const ip = &zcu.intern_pool;
switch (ty.toIntern()) { switch (ty.toIntern()) {
.empty_struct_type => return .{ .scalar = .@"1" }, .empty_tuple_type => return .{ .scalar = .@"1" },
else => switch (ip.indexToKey(ty.toIntern())) { else => switch (ip.indexToKey(ty.toIntern())) {
.int_type => |int_type| { .int_type => |int_type| {
if (int_type.bits == 0) return .{ .scalar = .@"1" }; if (int_type.bits == 0) return .{ .scalar = .@"1" };
@ -1109,7 +1095,7 @@ pub fn abiAlignmentInner(
return .{ .scalar = struct_type.flagsUnordered(ip).alignment }; return .{ .scalar = struct_type.flagsUnordered(ip).alignment };
}, },
.anon_struct_type => |tuple| { .tuple_type => |tuple| {
var big_align: Alignment = .@"1"; var big_align: Alignment = .@"1";
for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| { for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
if (val != .none) continue; // comptime field if (val != .none) continue; // comptime field
@ -1295,7 +1281,7 @@ pub fn abiSizeInner(
const ip = &zcu.intern_pool; const ip = &zcu.intern_pool;
switch (ty.toIntern()) { switch (ty.toIntern()) {
.empty_struct_type => return .{ .scalar = 0 }, .empty_tuple_type => return .{ .scalar = 0 },
else => switch (ip.indexToKey(ty.toIntern())) { else => switch (ip.indexToKey(ty.toIntern())) {
.int_type => |int_type| { .int_type => |int_type| {
@ -1498,7 +1484,7 @@ pub fn abiSizeInner(
}, },
} }
}, },
.anon_struct_type => |tuple| { .tuple_type => |tuple| {
switch (strat) { switch (strat) {
.sema => try ty.resolveLayout(strat.pt(zcu, tid)), .sema => try ty.resolveLayout(strat.pt(zcu, tid)),
.lazy, .eager => {}, .lazy, .eager => {},
@ -1831,8 +1817,7 @@ pub fn bitSizeInner(
return (try ty.abiSizeInner(strat_lazy, zcu, tid)).scalar * 8; return (try ty.abiSizeInner(strat_lazy, zcu, tid)).scalar * 8;
}, },
.anon_struct_type => { .tuple_type => {
if (strat == .sema) try ty.resolveFields(strat.pt(zcu, tid));
return (try ty.abiSizeInner(strat_lazy, zcu, tid)).scalar * 8; return (try ty.abiSizeInner(strat_lazy, zcu, tid)).scalar * 8;
}, },
@ -2176,7 +2161,7 @@ pub fn containerLayout(ty: Type, zcu: *const Zcu) std.builtin.Type.ContainerLayo
const ip = &zcu.intern_pool; const ip = &zcu.intern_pool;
return switch (ip.indexToKey(ty.toIntern())) { return switch (ip.indexToKey(ty.toIntern())) {
.struct_type => ip.loadStructType(ty.toIntern()).layout, .struct_type => ip.loadStructType(ty.toIntern()).layout,
.anon_struct_type => .auto, .tuple_type => .auto,
.union_type => ip.loadUnionType(ty.toIntern()).flagsUnordered(ip).layout, .union_type => ip.loadUnionType(ty.toIntern()).flagsUnordered(ip).layout,
else => unreachable, else => unreachable,
}; };
@ -2295,7 +2280,7 @@ pub fn arrayLenIncludingSentinel(ty: Type, zcu: *const Zcu) u64 {
pub fn vectorLen(ty: Type, zcu: *const Zcu) u32 { pub fn vectorLen(ty: Type, zcu: *const Zcu) u32 {
return switch (zcu.intern_pool.indexToKey(ty.toIntern())) { return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
.vector_type => |vector_type| vector_type.len, .vector_type => |vector_type| vector_type.len,
.anon_struct_type => |tuple| @intCast(tuple.types.len), .tuple_type => |tuple| @intCast(tuple.types.len),
else => unreachable, else => unreachable,
}; };
} }
@ -2305,7 +2290,7 @@ pub fn sentinel(ty: Type, zcu: *const Zcu) ?Value {
return switch (zcu.intern_pool.indexToKey(ty.toIntern())) { return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
.vector_type, .vector_type,
.struct_type, .struct_type,
.anon_struct_type, .tuple_type,
=> null, => null,
.array_type => |t| if (t.sentinel != .none) Value.fromInterned(t.sentinel) else null, .array_type => |t| if (t.sentinel != .none) Value.fromInterned(t.sentinel) else null,
@ -2386,7 +2371,7 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType {
return .{ .signedness = .unsigned, .bits = zcu.errorSetBits() }; return .{ .signedness = .unsigned, .bits = zcu.errorSetBits() };
}, },
.anon_struct_type => unreachable, .tuple_type => unreachable,
.ptr_type => unreachable, .ptr_type => unreachable,
.anyframe_type => unreachable, .anyframe_type => unreachable,
@ -2556,7 +2541,7 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value {
var ty = starting_type; var ty = starting_type;
const ip = &zcu.intern_pool; const ip = &zcu.intern_pool;
while (true) switch (ty.toIntern()) { while (true) switch (ty.toIntern()) {
.empty_struct_type => return Value.empty_struct, .empty_tuple_type => return Value.empty_tuple,
else => switch (ip.indexToKey(ty.toIntern())) { else => switch (ip.indexToKey(ty.toIntern())) {
.int_type => |int_type| { .int_type => |int_type| {
@ -2660,7 +2645,7 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value {
} })); } }));
}, },
.anon_struct_type => |tuple| { .tuple_type => |tuple| {
for (tuple.values.get(ip)) |val| { for (tuple.values.get(ip)) |val| {
if (val == .none) return null; if (val == .none) return null;
} }
@ -2783,7 +2768,7 @@ pub fn comptimeOnlyInner(
) SemaError!bool { ) SemaError!bool {
const ip = &zcu.intern_pool; const ip = &zcu.intern_pool;
return switch (ty.toIntern()) { return switch (ty.toIntern()) {
.empty_struct_type => false, .empty_tuple_type => false,
else => switch (ip.indexToKey(ty.toIntern())) { else => switch (ip.indexToKey(ty.toIntern())) {
.int_type => false, .int_type => false,
@ -2891,7 +2876,7 @@ pub fn comptimeOnlyInner(
}; };
}, },
.anon_struct_type => |tuple| { .tuple_type => |tuple| {
for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| { for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
const have_comptime_val = val != .none; const have_comptime_val = val != .none;
if (!have_comptime_val and try Type.fromInterned(field_ty).comptimeOnlyInner(strat, zcu, tid)) return true; if (!have_comptime_val and try Type.fromInterned(field_ty).comptimeOnlyInner(strat, zcu, tid)) return true;
@ -3022,7 +3007,7 @@ pub fn getNamespace(ty: Type, zcu: *Zcu) InternPool.OptionalNamespaceIndex {
const ip = &zcu.intern_pool; const ip = &zcu.intern_pool;
return switch (ip.indexToKey(ty.toIntern())) { return switch (ip.indexToKey(ty.toIntern())) {
.opaque_type => ip.loadOpaqueType(ty.toIntern()).namespace.toOptional(), .opaque_type => ip.loadOpaqueType(ty.toIntern()).namespace.toOptional(),
.struct_type => ip.loadStructType(ty.toIntern()).namespace, .struct_type => ip.loadStructType(ty.toIntern()).namespace.toOptional(),
.union_type => ip.loadUnionType(ty.toIntern()).namespace.toOptional(), .union_type => ip.loadUnionType(ty.toIntern()).namespace.toOptional(),
.enum_type => ip.loadEnumType(ty.toIntern()).namespace.toOptional(), .enum_type => ip.loadEnumType(ty.toIntern()).namespace.toOptional(),
else => .none, else => .none,
@ -3181,7 +3166,7 @@ pub fn structFieldName(ty: Type, index: usize, zcu: *const Zcu) InternPool.Optio
const ip = &zcu.intern_pool; const ip = &zcu.intern_pool;
return switch (ip.indexToKey(ty.toIntern())) { return switch (ip.indexToKey(ty.toIntern())) {
.struct_type => ip.loadStructType(ty.toIntern()).fieldName(ip, index), .struct_type => ip.loadStructType(ty.toIntern()).fieldName(ip, index),
.anon_struct_type => |anon_struct| anon_struct.fieldName(ip, index), .tuple_type => .none,
else => unreachable, else => unreachable,
}; };
} }
@ -3190,7 +3175,7 @@ pub fn structFieldCount(ty: Type, zcu: *const Zcu) u32 {
const ip = &zcu.intern_pool; const ip = &zcu.intern_pool;
return switch (ip.indexToKey(ty.toIntern())) { return switch (ip.indexToKey(ty.toIntern())) {
.struct_type => ip.loadStructType(ty.toIntern()).field_types.len, .struct_type => ip.loadStructType(ty.toIntern()).field_types.len,
.anon_struct_type => |anon_struct| anon_struct.types.len, .tuple_type => |tuple| tuple.types.len,
else => unreachable, else => unreachable,
}; };
} }
@ -3204,7 +3189,7 @@ pub fn fieldType(ty: Type, index: usize, zcu: *const Zcu) Type {
const union_obj = ip.loadUnionType(ty.toIntern()); const union_obj = ip.loadUnionType(ty.toIntern());
return Type.fromInterned(union_obj.field_types.get(ip)[index]); return Type.fromInterned(union_obj.field_types.get(ip)[index]);
}, },
.anon_struct_type => |anon_struct| Type.fromInterned(anon_struct.types.get(ip)[index]), .tuple_type => |tuple| Type.fromInterned(tuple.types.get(ip)[index]),
else => unreachable, else => unreachable,
}; };
} }
@ -3238,8 +3223,8 @@ pub fn fieldAlignmentInner(
const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[index]); const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[index]);
return field_ty.structFieldAlignmentInner(explicit_align, struct_type.layout, strat, zcu, tid); return field_ty.structFieldAlignmentInner(explicit_align, struct_type.layout, strat, zcu, tid);
}, },
.anon_struct_type => |anon_struct| { .tuple_type => |tuple| {
return (try Type.fromInterned(anon_struct.types.get(ip)[index]).abiAlignmentInner( return (try Type.fromInterned(tuple.types.get(ip)[index]).abiAlignmentInner(
strat.toLazy(), strat.toLazy(),
zcu, zcu,
tid, tid,
@ -3361,8 +3346,8 @@ pub fn structFieldDefaultValue(ty: Type, index: usize, zcu: *const Zcu) Value {
if (val == .none) return Value.@"unreachable"; if (val == .none) return Value.@"unreachable";
return Value.fromInterned(val); return Value.fromInterned(val);
}, },
.anon_struct_type => |anon_struct| { .tuple_type => |tuple| {
const val = anon_struct.values.get(ip)[index]; const val = tuple.values.get(ip)[index];
// TODO: avoid using `unreachable` to indicate this. // TODO: avoid using `unreachable` to indicate this.
if (val == .none) return Value.@"unreachable"; if (val == .none) return Value.@"unreachable";
return Value.fromInterned(val); return Value.fromInterned(val);
@ -3384,7 +3369,7 @@ pub fn structFieldValueComptime(ty: Type, pt: Zcu.PerThread, index: usize) !?Val
return Type.fromInterned(struct_type.field_types.get(ip)[index]).onePossibleValue(pt); return Type.fromInterned(struct_type.field_types.get(ip)[index]).onePossibleValue(pt);
} }
}, },
.anon_struct_type => |tuple| { .tuple_type => |tuple| {
const val = tuple.values.get(ip)[index]; const val = tuple.values.get(ip)[index];
if (val == .none) { if (val == .none) {
return Type.fromInterned(tuple.types.get(ip)[index]).onePossibleValue(pt); return Type.fromInterned(tuple.types.get(ip)[index]).onePossibleValue(pt);
@ -3400,7 +3385,7 @@ pub fn structFieldIsComptime(ty: Type, index: usize, zcu: *const Zcu) bool {
const ip = &zcu.intern_pool; const ip = &zcu.intern_pool;
return switch (ip.indexToKey(ty.toIntern())) { return switch (ip.indexToKey(ty.toIntern())) {
.struct_type => ip.loadStructType(ty.toIntern()).fieldIsComptime(ip, index), .struct_type => ip.loadStructType(ty.toIntern()).fieldIsComptime(ip, index),
.anon_struct_type => |anon_struct| anon_struct.values.get(ip)[index] != .none, .tuple_type => |tuple| tuple.values.get(ip)[index] != .none,
else => unreachable, else => unreachable,
}; };
} }
@ -3425,7 +3410,7 @@ pub fn structFieldOffset(
return struct_type.offsets.get(ip)[index]; return struct_type.offsets.get(ip)[index];
}, },
.anon_struct_type => |tuple| { .tuple_type => |tuple| {
var offset: u64 = 0; var offset: u64 = 0;
var big_align: Alignment = .none; var big_align: Alignment = .none;
@ -3472,7 +3457,6 @@ pub fn srcLocOrNull(ty: Type, zcu: *Zcu) ?Zcu.LazySrcLoc {
.declared => |d| d.zir_index, .declared => |d| d.zir_index,
.reified => |r| r.zir_index, .reified => |r| r.zir_index,
.generated_tag => |gt| ip.loadUnionType(gt.union_type).zir_index, .generated_tag => |gt| ip.loadUnionType(gt.union_type).zir_index,
.empty_struct => return null,
}, },
else => return null, else => return null,
}, },
@ -3491,49 +3475,7 @@ pub fn isGenericPoison(ty: Type) bool {
pub fn isTuple(ty: Type, zcu: *const Zcu) bool { pub fn isTuple(ty: Type, zcu: *const Zcu) bool {
const ip = &zcu.intern_pool; const ip = &zcu.intern_pool;
return switch (ip.indexToKey(ty.toIntern())) { return switch (ip.indexToKey(ty.toIntern())) {
.struct_type => { .tuple_type => true,
const struct_type = ip.loadStructType(ty.toIntern());
if (struct_type.layout == .@"packed") return false;
if (struct_type.cau == .none) return false;
return struct_type.flagsUnordered(ip).is_tuple;
},
.anon_struct_type => |anon_struct| anon_struct.names.len == 0,
else => false,
};
}
pub fn isAnonStruct(ty: Type, zcu: *const Zcu) bool {
if (ty.toIntern() == .empty_struct_type) return true;
return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
.anon_struct_type => |anon_struct_type| anon_struct_type.names.len > 0,
else => false,
};
}
pub fn isTupleOrAnonStruct(ty: Type, zcu: *const Zcu) bool {
const ip = &zcu.intern_pool;
return switch (ip.indexToKey(ty.toIntern())) {
.struct_type => {
const struct_type = ip.loadStructType(ty.toIntern());
if (struct_type.layout == .@"packed") return false;
if (struct_type.cau == .none) return false;
return struct_type.flagsUnordered(ip).is_tuple;
},
.anon_struct_type => true,
else => false,
};
}
pub fn isSimpleTuple(ty: Type, zcu: *const Zcu) bool {
return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
.anon_struct_type => |anon_struct_type| anon_struct_type.names.len == 0,
else => false,
};
}
pub fn isSimpleTupleOrAnonStruct(ty: Type, zcu: *const Zcu) bool {
return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
.anon_struct_type => true,
else => false, else => false,
}; };
} }
@ -3564,7 +3506,7 @@ pub fn toUnsigned(ty: Type, pt: Zcu.PerThread) !Type {
pub fn typeDeclInst(ty: Type, zcu: *const Zcu) ?InternPool.TrackedInst.Index { pub fn typeDeclInst(ty: Type, zcu: *const Zcu) ?InternPool.TrackedInst.Index {
const ip = &zcu.intern_pool; const ip = &zcu.intern_pool;
return switch (ip.indexToKey(ty.toIntern())) { return switch (ip.indexToKey(ty.toIntern())) {
.struct_type => ip.loadStructType(ty.toIntern()).zir_index.unwrap(), .struct_type => ip.loadStructType(ty.toIntern()).zir_index,
.union_type => ip.loadUnionType(ty.toIntern()).zir_index, .union_type => ip.loadUnionType(ty.toIntern()).zir_index,
.enum_type => ip.loadEnumType(ty.toIntern()).zir_index.unwrap(), .enum_type => ip.loadEnumType(ty.toIntern()).zir_index.unwrap(),
.opaque_type => ip.loadOpaqueType(ty.toIntern()).zir_index, .opaque_type => ip.loadOpaqueType(ty.toIntern()).zir_index,
@ -3575,12 +3517,11 @@ pub fn typeDeclInst(ty: Type, zcu: *const Zcu) ?InternPool.TrackedInst.Index {
pub fn typeDeclInstAllowGeneratedTag(ty: Type, zcu: *const Zcu) ?InternPool.TrackedInst.Index { pub fn typeDeclInstAllowGeneratedTag(ty: Type, zcu: *const Zcu) ?InternPool.TrackedInst.Index {
const ip = &zcu.intern_pool; const ip = &zcu.intern_pool;
return switch (ip.indexToKey(ty.toIntern())) { return switch (ip.indexToKey(ty.toIntern())) {
.struct_type => ip.loadStructType(ty.toIntern()).zir_index.unwrap(), .struct_type => ip.loadStructType(ty.toIntern()).zir_index,
.union_type => ip.loadUnionType(ty.toIntern()).zir_index, .union_type => ip.loadUnionType(ty.toIntern()).zir_index,
.enum_type => |e| switch (e) { .enum_type => |e| switch (e) {
.declared, .reified => ip.loadEnumType(ty.toIntern()).zir_index.unwrap().?, .declared, .reified => ip.loadEnumType(ty.toIntern()).zir_index.unwrap().?,
.generated_tag => |gt| ip.loadUnionType(gt.union_type).zir_index, .generated_tag => |gt| ip.loadUnionType(gt.union_type).zir_index,
.empty_struct => unreachable,
}, },
.opaque_type => ip.loadOpaqueType(ty.toIntern()).zir_index, .opaque_type => ip.loadOpaqueType(ty.toIntern()).zir_index,
else => null, else => null,
@ -3588,13 +3529,16 @@ pub fn typeDeclInstAllowGeneratedTag(ty: Type, zcu: *const Zcu) ?InternPool.Trac
} }
pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 { pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 {
// Note that changes to ZIR instruction tracking only need to update this code
// if a newly-tracked instruction can be a type's owner `zir_index`.
comptime assert(Zir.inst_tracking_version == 0);
const ip = &zcu.intern_pool; const ip = &zcu.intern_pool;
const tracked = switch (ip.indexToKey(ty.toIntern())) { const tracked = switch (ip.indexToKey(ty.toIntern())) {
.struct_type, .union_type, .opaque_type, .enum_type => |info| switch (info) { .struct_type, .union_type, .opaque_type, .enum_type => |info| switch (info) {
.declared => |d| d.zir_index, .declared => |d| d.zir_index,
.reified => |r| r.zir_index, .reified => |r| r.zir_index,
.generated_tag => |gt| ip.loadUnionType(gt.union_type).zir_index, .generated_tag => |gt| ip.loadUnionType(gt.union_type).zir_index,
.empty_struct => return null,
}, },
else => return null, else => return null,
}; };
@ -3603,13 +3547,17 @@ pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 {
assert(file.zir_loaded); assert(file.zir_loaded);
const zir = file.zir; const zir = file.zir;
const inst = zir.instructions.get(@intFromEnum(info.inst)); const inst = zir.instructions.get(@intFromEnum(info.inst));
assert(inst.tag == .extended); return switch (inst.tag) {
return switch (inst.data.extended.opcode) { .struct_init, .struct_init_ref => zir.extraData(Zir.Inst.StructInit, inst.data.pl_node.payload_index).data.abs_line,
.struct_decl => zir.extraData(Zir.Inst.StructDecl, inst.data.extended.operand).data.src_line, .struct_init_anon => zir.extraData(Zir.Inst.StructInitAnon, inst.data.pl_node.payload_index).data.abs_line,
.union_decl => zir.extraData(Zir.Inst.UnionDecl, inst.data.extended.operand).data.src_line, .extended => switch (inst.data.extended.opcode) {
.enum_decl => zir.extraData(Zir.Inst.EnumDecl, inst.data.extended.operand).data.src_line, .struct_decl => zir.extraData(Zir.Inst.StructDecl, inst.data.extended.operand).data.src_line,
.opaque_decl => zir.extraData(Zir.Inst.OpaqueDecl, inst.data.extended.operand).data.src_line, .union_decl => zir.extraData(Zir.Inst.UnionDecl, inst.data.extended.operand).data.src_line,
.reify => zir.extraData(Zir.Inst.Reify, inst.data.extended.operand).data.src_line, .enum_decl => zir.extraData(Zir.Inst.EnumDecl, inst.data.extended.operand).data.src_line,
.opaque_decl => zir.extraData(Zir.Inst.OpaqueDecl, inst.data.extended.operand).data.src_line,
.reify => zir.extraData(Zir.Inst.Reify, inst.data.extended.operand).data.src_line,
else => unreachable,
},
else => unreachable, else => unreachable,
}; };
} }
@ -3697,8 +3645,8 @@ pub fn resolveLayout(ty: Type, pt: Zcu.PerThread) SemaError!void {
const ip = &zcu.intern_pool; const ip = &zcu.intern_pool;
switch (ty.zigTypeTag(zcu)) { switch (ty.zigTypeTag(zcu)) {
.@"struct" => switch (ip.indexToKey(ty.toIntern())) { .@"struct" => switch (ip.indexToKey(ty.toIntern())) {
.anon_struct_type => |anon_struct_type| for (0..anon_struct_type.types.len) |i| { .tuple_type => |tuple_type| for (0..tuple_type.types.len) |i| {
const field_ty = Type.fromInterned(anon_struct_type.types.get(ip)[i]); const field_ty = Type.fromInterned(tuple_type.types.get(ip)[i]);
try field_ty.resolveLayout(pt); try field_ty.resolveLayout(pt);
}, },
.struct_type => return ty.resolveStructInner(pt, .layout), .struct_type => return ty.resolveStructInner(pt, .layout),
@ -3796,7 +3744,7 @@ pub fn resolveFields(ty: Type, pt: Zcu.PerThread) SemaError!void {
.optional_noreturn_type, .optional_noreturn_type,
.anyerror_void_error_union_type, .anyerror_void_error_union_type,
.generic_poison_type, .generic_poison_type,
.empty_struct_type, .empty_tuple_type,
=> {}, => {},
.undef => unreachable, .undef => unreachable,
@ -3813,7 +3761,7 @@ pub fn resolveFields(ty: Type, pt: Zcu.PerThread) SemaError!void {
.null_value => unreachable, .null_value => unreachable,
.bool_true => unreachable, .bool_true => unreachable,
.bool_false => unreachable, .bool_false => unreachable,
.empty_struct => unreachable, .empty_tuple => unreachable,
.generic_poison => unreachable, .generic_poison => unreachable,
else => switch (ty_ip.unwrap(ip).getTag(ip)) { else => switch (ty_ip.unwrap(ip).getTag(ip)) {
@ -3868,8 +3816,8 @@ pub fn resolveFully(ty: Type, pt: Zcu.PerThread) SemaError!void {
}, },
.@"struct" => switch (ip.indexToKey(ty.toIntern())) { .@"struct" => switch (ip.indexToKey(ty.toIntern())) {
.anon_struct_type => |anon_struct_type| for (0..anon_struct_type.types.len) |i| { .tuple_type => |tuple_type| for (0..tuple_type.types.len) |i| {
const field_ty = Type.fromInterned(anon_struct_type.types.get(ip)[i]); const field_ty = Type.fromInterned(tuple_type.types.get(ip)[i]);
try field_ty.resolveFully(pt); try field_ty.resolveFully(pt);
}, },
.struct_type => return ty.resolveStructInner(pt, .full), .struct_type => return ty.resolveStructInner(pt, .full),
@ -3903,7 +3851,7 @@ fn resolveStructInner(
const gpa = zcu.gpa; const gpa = zcu.gpa;
const struct_obj = zcu.typeToStruct(ty).?; const struct_obj = zcu.typeToStruct(ty).?;
const owner = InternPool.AnalUnit.wrap(.{ .cau = struct_obj.cau.unwrap() orelse return }); const owner = InternPool.AnalUnit.wrap(.{ .cau = struct_obj.cau });
if (zcu.failed_analysis.contains(owner) or zcu.transitive_failed_analysis.contains(owner)) { if (zcu.failed_analysis.contains(owner) or zcu.transitive_failed_analysis.contains(owner)) {
return error.AnalysisFail; return error.AnalysisFail;
@ -3915,7 +3863,7 @@ fn resolveStructInner(
var comptime_err_ret_trace = std.ArrayList(Zcu.LazySrcLoc).init(gpa); var comptime_err_ret_trace = std.ArrayList(Zcu.LazySrcLoc).init(gpa);
defer comptime_err_ret_trace.deinit(); defer comptime_err_ret_trace.deinit();
const zir = zcu.namespacePtr(struct_obj.namespace.unwrap().?).fileScope(zcu).zir; const zir = zcu.namespacePtr(struct_obj.namespace).fileScope(zcu).zir;
var sema: Sema = .{ var sema: Sema = .{
.pt = pt, .pt = pt,
.gpa = gpa, .gpa = gpa,
@ -4196,7 +4144,7 @@ pub const single_const_pointer_to_comptime_int: Type = .{
.ip_index = .single_const_pointer_to_comptime_int_type, .ip_index = .single_const_pointer_to_comptime_int_type,
}; };
pub const slice_const_u8_sentinel_0: Type = .{ .ip_index = .slice_const_u8_sentinel_0_type }; pub const slice_const_u8_sentinel_0: Type = .{ .ip_index = .slice_const_u8_sentinel_0_type };
pub const empty_struct_literal: Type = .{ .ip_index = .empty_struct_type }; pub const empty_tuple_type: Type = .{ .ip_index = .empty_tuple_type };
pub const generic_poison: Type = .{ .ip_index = .generic_poison_type }; pub const generic_poison: Type = .{ .ip_index = .generic_poison_type };

View File

@ -3704,7 +3704,7 @@ pub const @"unreachable": Value = .{ .ip_index = .unreachable_value };
pub const generic_poison: Value = .{ .ip_index = .generic_poison }; pub const generic_poison: Value = .{ .ip_index = .generic_poison };
pub const generic_poison_type: Value = .{ .ip_index = .generic_poison_type }; pub const generic_poison_type: Value = .{ .ip_index = .generic_poison_type };
pub const empty_struct: Value = .{ .ip_index = .empty_struct }; pub const empty_tuple: Value = .{ .ip_index = .empty_tuple };
pub fn makeBool(x: bool) Value { pub fn makeBool(x: bool) Value {
return if (x) Value.true else Value.false; return if (x) Value.true else Value.false;

View File

@ -1497,6 +1497,20 @@ pub const SrcLoc = struct {
} }
} else unreachable; } else unreachable;
}, },
.tuple_field_type, .tuple_field_init => |field_info| {
const tree = try src_loc.file_scope.getTree(gpa);
const node = src_loc.relativeToNodeIndex(0);
var buf: [2]Ast.Node.Index = undefined;
const container_decl = tree.fullContainerDecl(&buf, node) orelse
return tree.nodeToSpan(node);
const field = tree.fullContainerField(container_decl.ast.members[field_info.elem_index]).?;
return tree.nodeToSpan(switch (src_loc.lazy) {
.tuple_field_type => field.ast.type_expr,
.tuple_field_init => field.ast.value_expr,
else => unreachable,
});
},
.init_elem => |init_elem| { .init_elem => |init_elem| {
const tree = try src_loc.file_scope.getTree(gpa); const tree = try src_loc.file_scope.getTree(gpa);
const init_node = src_loc.relativeToNodeIndex(init_elem.init_node_offset); const init_node = src_loc.relativeToNodeIndex(init_elem.init_node_offset);
@ -1939,6 +1953,12 @@ pub const LazySrcLoc = struct {
container_field_type: u32, container_field_type: u32,
/// Like `continer_field_name`, but points at the field's alignment. /// Like `continer_field_name`, but points at the field's alignment.
container_field_align: u32, container_field_align: u32,
/// The source location points to the type of the field at the given index
/// of the tuple type declaration at `tuple_decl_node_offset`.
tuple_field_type: TupleField,
/// The source location points to the default init of the field at the given index
/// of the tuple type declaration at `tuple_decl_node_offset`.
tuple_field_init: TupleField,
/// The source location points to the given element/field of a struct or /// The source location points to the given element/field of a struct or
/// array initialization expression. /// array initialization expression.
init_elem: struct { init_elem: struct {
@ -2016,13 +2036,20 @@ pub const LazySrcLoc = struct {
index: u31, index: u31,
}; };
const ArrayCat = struct { pub const ArrayCat = struct {
/// Points to the array concat AST node. /// Points to the array concat AST node.
array_cat_offset: i32, array_cat_offset: i32,
/// The index of the element the source location points to. /// The index of the element the source location points to.
elem_index: u32, elem_index: u32,
}; };
pub const TupleField = struct {
/// Points to the AST node of the tuple type decaration.
tuple_decl_node_offset: i32,
/// The index of the tuple field the source location points to.
elem_index: u32,
};
pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease; pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease;
noinline fn nodeOffsetDebug(node_offset: i32) Offset { noinline fn nodeOffsetDebug(node_offset: i32) Offset {
@ -2052,6 +2079,8 @@ pub const LazySrcLoc = struct {
/// Returns `null` if the ZIR instruction has been lost across incremental updates. /// Returns `null` if the ZIR instruction has been lost across incremental updates.
pub fn resolveBaseNode(base_node_inst: InternPool.TrackedInst.Index, zcu: *Zcu) ?struct { *File, Ast.Node.Index } { pub fn resolveBaseNode(base_node_inst: InternPool.TrackedInst.Index, zcu: *Zcu) ?struct { *File, Ast.Node.Index } {
comptime assert(Zir.inst_tracking_version == 0);
const ip = &zcu.intern_pool; const ip = &zcu.intern_pool;
const file_index, const zir_inst = inst: { const file_index, const zir_inst = inst: {
const info = base_node_inst.resolveFull(ip) orelse return null; const info = base_node_inst.resolveFull(ip) orelse return null;
@ -2064,6 +2093,8 @@ pub const LazySrcLoc = struct {
const inst = zir.instructions.get(@intFromEnum(zir_inst)); const inst = zir.instructions.get(@intFromEnum(zir_inst));
const base_node: Ast.Node.Index = switch (inst.tag) { const base_node: Ast.Node.Index = switch (inst.tag) {
.declaration => inst.data.declaration.src_node, .declaration => inst.data.declaration.src_node,
.struct_init, .struct_init_ref => zir.extraData(Zir.Inst.StructInit, inst.data.pl_node.payload_index).data.abs_node,
.struct_init_anon => zir.extraData(Zir.Inst.StructInitAnon, inst.data.pl_node.payload_index).data.abs_node,
.extended => switch (inst.data.extended.opcode) { .extended => switch (inst.data.extended.opcode) {
.struct_decl => zir.extraData(Zir.Inst.StructDecl, inst.data.extended.operand).data.src_node, .struct_decl => zir.extraData(Zir.Inst.StructDecl, inst.data.extended.operand).data.src_node,
.union_decl => zir.extraData(Zir.Inst.UnionDecl, inst.data.extended.operand).data.src_node, .union_decl => zir.extraData(Zir.Inst.UnionDecl, inst.data.extended.operand).data.src_node,
@ -3215,7 +3246,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
// If this type has a `Cau` for resolution, it's automatically referenced. // If this type has a `Cau` for resolution, it's automatically referenced.
const resolution_cau: InternPool.Cau.Index.Optional = switch (ip.indexToKey(ty)) { const resolution_cau: InternPool.Cau.Index.Optional = switch (ip.indexToKey(ty)) {
.struct_type => ip.loadStructType(ty).cau, .struct_type => ip.loadStructType(ty).cau.toOptional(),
.union_type => ip.loadUnionType(ty).cau.toOptional(), .union_type => ip.loadUnionType(ty).cau.toOptional(),
.enum_type => ip.loadEnumType(ty).cau, .enum_type => ip.loadEnumType(ty).cau,
.opaque_type => .none, .opaque_type => .none,

View File

@ -985,7 +985,6 @@ fn createFileRootStruct(
.fields_len = fields_len, .fields_len = fields_len,
.known_non_opv = small.known_non_opv, .known_non_opv = small.known_non_opv,
.requires_comptime = if (small.known_comptime_only) .yes else .unknown, .requires_comptime = if (small.known_comptime_only) .yes else .unknown,
.is_tuple = small.is_tuple,
.any_comptime_fields = small.any_comptime_fields, .any_comptime_fields = small.any_comptime_fields,
.any_default_inits = small.any_default_inits, .any_default_inits = small.any_default_inits,
.inits_resolved = false, .inits_resolved = false,
@ -3191,7 +3190,7 @@ pub fn ensureTypeUpToDate(pt: Zcu.PerThread, ty: InternPool.Index, already_updat
.struct_type => |key| { .struct_type => |key| {
const struct_obj = ip.loadStructType(ty); const struct_obj = ip.loadStructType(ty);
const outdated = already_updating or o: { const outdated = already_updating or o: {
const anal_unit = AnalUnit.wrap(.{ .cau = struct_obj.cau.unwrap().? }); const anal_unit = AnalUnit.wrap(.{ .cau = struct_obj.cau });
const o = zcu.outdated.swapRemove(anal_unit) or const o = zcu.outdated.swapRemove(anal_unit) or
zcu.potentially_outdated.swapRemove(anal_unit); zcu.potentially_outdated.swapRemove(anal_unit);
if (o) { if (o) {
@ -3252,7 +3251,6 @@ fn recreateStructType(
const key = switch (full_key) { const key = switch (full_key) {
.reified => unreachable, // never outdated .reified => unreachable, // never outdated
.empty_struct => unreachable, // never outdated
.generated_tag => unreachable, // not a struct .generated_tag => unreachable, // not a struct
.declared => |d| d, .declared => |d| d,
}; };
@ -3283,16 +3281,13 @@ fn recreateStructType(
if (captures_len != key.captures.owned.len) return error.AnalysisFail; if (captures_len != key.captures.owned.len) return error.AnalysisFail;
// The old type will be unused, so drop its dependency information. // The old type will be unused, so drop its dependency information.
ip.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .cau = struct_obj.cau.unwrap().? })); ip.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .cau = struct_obj.cau }));
const namespace_index = struct_obj.namespace.unwrap().?;
const wip_ty = switch (try ip.getStructType(gpa, pt.tid, .{ const wip_ty = switch (try ip.getStructType(gpa, pt.tid, .{
.layout = small.layout, .layout = small.layout,
.fields_len = fields_len, .fields_len = fields_len,
.known_non_opv = small.known_non_opv, .known_non_opv = small.known_non_opv,
.requires_comptime = if (small.known_comptime_only) .yes else .unknown, .requires_comptime = if (small.known_comptime_only) .yes else .unknown,
.is_tuple = small.is_tuple,
.any_comptime_fields = small.any_comptime_fields, .any_comptime_fields = small.any_comptime_fields,
.any_default_inits = small.any_default_inits, .any_default_inits = small.any_default_inits,
.inits_resolved = false, .inits_resolved = false,
@ -3308,17 +3303,17 @@ fn recreateStructType(
errdefer wip_ty.cancel(ip, pt.tid); errdefer wip_ty.cancel(ip, pt.tid);
wip_ty.setName(ip, struct_obj.name); wip_ty.setName(ip, struct_obj.name);
const new_cau_index = try ip.createTypeCau(gpa, pt.tid, key.zir_index, namespace_index, wip_ty.index); const new_cau_index = try ip.createTypeCau(gpa, pt.tid, key.zir_index, struct_obj.namespace, wip_ty.index);
try ip.addDependency( try ip.addDependency(
gpa, gpa,
AnalUnit.wrap(.{ .cau = new_cau_index }), AnalUnit.wrap(.{ .cau = new_cau_index }),
.{ .src_hash = key.zir_index }, .{ .src_hash = key.zir_index },
); );
zcu.namespacePtr(namespace_index).owner_type = wip_ty.index; zcu.namespacePtr(struct_obj.namespace).owner_type = wip_ty.index;
// No need to re-scan the namespace -- `zirStructDecl` will ultimately do that if the type is still alive. // No need to re-scan the namespace -- `zirStructDecl` will ultimately do that if the type is still alive.
try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
const new_ty = wip_ty.finish(ip, new_cau_index.toOptional(), namespace_index); const new_ty = wip_ty.finish(ip, new_cau_index.toOptional(), struct_obj.namespace);
if (inst_info.inst == .main_struct_inst) { if (inst_info.inst == .main_struct_inst) {
// This is the root type of a file! Update the reference. // This is the root type of a file! Update the reference.
zcu.setFileRootType(inst_info.file, new_ty); zcu.setFileRootType(inst_info.file, new_ty);
@ -3337,7 +3332,6 @@ fn recreateUnionType(
const key = switch (full_key) { const key = switch (full_key) {
.reified => unreachable, // never outdated .reified => unreachable, // never outdated
.empty_struct => unreachable, // never outdated
.generated_tag => unreachable, // not a union .generated_tag => unreachable, // not a union
.declared => |d| d, .declared => |d| d,
}; };
@ -3429,9 +3423,7 @@ fn recreateEnumType(
const ip = &zcu.intern_pool; const ip = &zcu.intern_pool;
const key = switch (full_key) { const key = switch (full_key) {
.reified => unreachable, // never outdated .reified, .generated_tag => unreachable, // never outdated
.empty_struct => unreachable, // never outdated
.generated_tag => unreachable, // never outdated
.declared => |d| d, .declared => |d| d,
}; };
@ -3575,7 +3567,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace
}; };
const key = switch (full_key) { const key = switch (full_key) {
.reified, .empty_struct, .generated_tag => { .reified, .generated_tag => {
// Namespace always empty, so up-to-date. // Namespace always empty, so up-to-date.
namespace.generation = zcu.generation; namespace.generation = zcu.generation;
return; return;

View File

@ -3114,7 +3114,7 @@ fn binOpImmediate(
const reg = try self.register_manager.allocReg(track_inst, gp); const reg = try self.register_manager.allocReg(track_inst, gp);
if (track_inst) |inst| { if (track_inst) |inst| {
const mcv = .{ .register = reg }; const mcv: MCValue = .{ .register = reg };
log.debug("binOpRegister move lhs %{d} to register: {} -> {}", .{ inst, lhs, mcv }); log.debug("binOpRegister move lhs %{d} to register: {} -> {}", .{ inst, lhs, mcv });
branch.inst_table.putAssumeCapacity(inst, mcv); branch.inst_table.putAssumeCapacity(inst, mcv);
@ -3252,7 +3252,7 @@ fn binOpRegister(
const reg = try self.register_manager.allocReg(track_inst, gp); const reg = try self.register_manager.allocReg(track_inst, gp);
if (track_inst) |inst| { if (track_inst) |inst| {
const mcv = .{ .register = reg }; const mcv: MCValue = .{ .register = reg };
log.debug("binOpRegister move lhs %{d} to register: {} -> {}", .{ inst, lhs, mcv }); log.debug("binOpRegister move lhs %{d} to register: {} -> {}", .{ inst, lhs, mcv });
branch.inst_table.putAssumeCapacity(inst, mcv); branch.inst_table.putAssumeCapacity(inst, mcv);
@ -3276,7 +3276,7 @@ fn binOpRegister(
const reg = try self.register_manager.allocReg(track_inst, gp); const reg = try self.register_manager.allocReg(track_inst, gp);
if (track_inst) |inst| { if (track_inst) |inst| {
const mcv = .{ .register = reg }; const mcv: MCValue = .{ .register = reg };
log.debug("binOpRegister move rhs %{d} to register: {} -> {}", .{ inst, rhs, mcv }); log.debug("binOpRegister move rhs %{d} to register: {} -> {}", .{ inst, rhs, mcv });
branch.inst_table.putAssumeCapacity(inst, mcv); branch.inst_table.putAssumeCapacity(inst, mcv);
@ -3650,7 +3650,6 @@ fn genLoad(self: *Self, value_reg: Register, addr_reg: Register, comptime off_ty
assert(off_type == Register or off_type == i13); assert(off_type == Register or off_type == i13);
const is_imm = (off_type == i13); const is_imm = (off_type == i13);
const rs2_or_imm = if (is_imm) .{ .imm = off } else .{ .rs2 = off };
switch (abi_size) { switch (abi_size) {
1, 2, 4, 8 => { 1, 2, 4, 8 => {
@ -3669,7 +3668,7 @@ fn genLoad(self: *Self, value_reg: Register, addr_reg: Register, comptime off_ty
.is_imm = is_imm, .is_imm = is_imm,
.rd = value_reg, .rd = value_reg,
.rs1 = addr_reg, .rs1 = addr_reg,
.rs2_or_imm = rs2_or_imm, .rs2_or_imm = if (is_imm) .{ .imm = off } else .{ .rs2 = off },
}, },
}, },
}); });
@ -4037,7 +4036,6 @@ fn genStore(self: *Self, value_reg: Register, addr_reg: Register, comptime off_t
assert(off_type == Register or off_type == i13); assert(off_type == Register or off_type == i13);
const is_imm = (off_type == i13); const is_imm = (off_type == i13);
const rs2_or_imm = if (is_imm) .{ .imm = off } else .{ .rs2 = off };
switch (abi_size) { switch (abi_size) {
1, 2, 4, 8 => { 1, 2, 4, 8 => {
@ -4056,7 +4054,7 @@ fn genStore(self: *Self, value_reg: Register, addr_reg: Register, comptime off_t
.is_imm = is_imm, .is_imm = is_imm,
.rd = value_reg, .rd = value_reg,
.rs1 = addr_reg, .rs1 = addr_reg,
.rs2_or_imm = rs2_or_imm, .rs2_or_imm = if (is_imm) .{ .imm = off } else .{ .rs2 = off },
}, },
}, },
}); });

View File

@ -3259,7 +3259,7 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
.error_union_type, .error_union_type,
.simple_type, .simple_type,
.struct_type, .struct_type,
.anon_struct_type, .tuple_type,
.union_type, .union_type,
.opaque_type, .opaque_type,
.enum_type, .enum_type,
@ -3273,7 +3273,7 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
.undefined, .undefined,
.void, .void,
.null, .null,
.empty_struct, .empty_tuple,
.@"unreachable", .@"unreachable",
.generic_poison, .generic_poison,
=> unreachable, // non-runtime values => unreachable, // non-runtime values
@ -3708,7 +3708,7 @@ fn airCmpLtErrorsLen(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const operand = try func.resolveInst(un_op); const operand = try func.resolveInst(un_op);
const sym_index = try func.bin_file.getGlobalSymbol("__zig_errors_len", null); const sym_index = try func.bin_file.getGlobalSymbol("__zig_errors_len", null);
const errors_len = .{ .memory = @intFromEnum(sym_index) }; const errors_len: WValue = .{ .memory = @intFromEnum(sym_index) };
try func.emitWValue(operand); try func.emitWValue(operand);
const pt = func.pt; const pt = func.pt;

View File

@ -13683,7 +13683,7 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void {
const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const operand = try self.resolveInst(un_op); const operand = try self.resolveInst(un_op);
const ty = self.typeOf(un_op); const ty = self.typeOf(un_op);
const result = switch (try self.isNullPtr(inst, ty, operand)) { const result: MCValue = switch (try self.isNullPtr(inst, ty, operand)) {
.eflags => |cc| .{ .eflags = cc.negate() }, .eflags => |cc| .{ .eflags = cc.negate() },
else => unreachable, else => unreachable,
}; };

View File

@ -216,7 +216,7 @@ pub fn generateSymbol(
.error_union_type, .error_union_type,
.simple_type, .simple_type,
.struct_type, .struct_type,
.anon_struct_type, .tuple_type,
.union_type, .union_type,
.opaque_type, .opaque_type,
.enum_type, .enum_type,
@ -230,7 +230,7 @@ pub fn generateSymbol(
.undefined, .undefined,
.void, .void,
.null, .null,
.empty_struct, .empty_tuple,
.@"unreachable", .@"unreachable",
.generic_poison, .generic_poison,
=> unreachable, // non-runtime values => unreachable, // non-runtime values
@ -456,7 +456,7 @@ pub fn generateSymbol(
if (padding > 0) try code.appendNTimes(0, padding); if (padding > 0) try code.appendNTimes(0, padding);
} }
}, },
.anon_struct_type => |tuple| { .tuple_type => |tuple| {
const struct_begin = code.items.len; const struct_begin = code.items.len;
for ( for (
tuple.types.get(ip), tuple.types.get(ip),

View File

@ -891,7 +891,7 @@ pub const DeclGen = struct {
.error_union_type, .error_union_type,
.simple_type, .simple_type,
.struct_type, .struct_type,
.anon_struct_type, .tuple_type,
.union_type, .union_type,
.opaque_type, .opaque_type,
.enum_type, .enum_type,
@ -908,7 +908,7 @@ pub const DeclGen = struct {
.undefined => unreachable, .undefined => unreachable,
.void => unreachable, .void => unreachable,
.null => unreachable, .null => unreachable,
.empty_struct => unreachable, .empty_tuple => unreachable,
.@"unreachable" => unreachable, .@"unreachable" => unreachable,
.generic_poison => unreachable, .generic_poison => unreachable,
@ -1194,7 +1194,7 @@ pub const DeclGen = struct {
try writer.writeByte('}'); try writer.writeByte('}');
} }
}, },
.anon_struct_type => |tuple| { .tuple_type => |tuple| {
if (!location.isInitializer()) { if (!location.isInitializer()) {
try writer.writeByte('('); try writer.writeByte('(');
try dg.renderCType(writer, ctype); try dg.renderCType(writer, ctype);
@ -1605,7 +1605,7 @@ pub const DeclGen = struct {
}), }),
} }
}, },
.anon_struct_type => |anon_struct_info| { .tuple_type => |tuple_info| {
if (!location.isInitializer()) { if (!location.isInitializer()) {
try writer.writeByte('('); try writer.writeByte('(');
try dg.renderCType(writer, ctype); try dg.renderCType(writer, ctype);
@ -1614,9 +1614,9 @@ pub const DeclGen = struct {
try writer.writeByte('{'); try writer.writeByte('{');
var need_comma = false; var need_comma = false;
for (0..anon_struct_info.types.len) |field_index| { for (0..tuple_info.types.len) |field_index| {
if (anon_struct_info.values.get(ip)[field_index] != .none) continue; if (tuple_info.values.get(ip)[field_index] != .none) continue;
const field_ty = Type.fromInterned(anon_struct_info.types.get(ip)[field_index]); const field_ty = Type.fromInterned(tuple_info.types.get(ip)[field_index]);
if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue; if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
if (need_comma) try writer.writeByte(','); if (need_comma) try writer.writeByte(',');
@ -5411,9 +5411,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
const input_val = try f.resolveInst(input); const input_val = try f.resolveInst(input);
try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "r" else constraint, null)}); try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "r" else constraint, null)});
try f.writeCValue(writer, if (asmInputNeedsLocal(f, constraint, input_val)) local: { try f.writeCValue(writer, if (asmInputNeedsLocal(f, constraint, input_val)) local: {
const input_local = .{ .local = locals_index }; const input_local_idx = locals_index;
locals_index += 1; locals_index += 1;
break :local input_local; break :local .{ .local = input_local_idx };
} else input_val, .Other); } else input_val, .Other);
try writer.writeByte(')'); try writer.writeByte(')');
} }
@ -5651,15 +5651,12 @@ fn fieldLocation(
.begin, .begin,
}; };
}, },
.anon_struct_type => |anon_struct_info| return if (!container_ty.hasRuntimeBitsIgnoreComptime(zcu)) .tuple_type => return if (!container_ty.hasRuntimeBitsIgnoreComptime(zcu))
.begin .begin
else if (!field_ptr_ty.childType(zcu).hasRuntimeBitsIgnoreComptime(zcu)) else if (!field_ptr_ty.childType(zcu).hasRuntimeBitsIgnoreComptime(zcu))
.{ .byte_offset = container_ty.structFieldOffset(field_index, zcu) } .{ .byte_offset = container_ty.structFieldOffset(field_index, zcu) }
else else
.{ .field = if (anon_struct_info.fieldName(ip, field_index).unwrap()) |field_name| .{ .field = .{ .field = field_index } },
.{ .identifier = field_name.toSlice(ip) }
else
.{ .field = field_index } },
.union_type => { .union_type => {
const loaded_union = ip.loadUnionType(container_ty.toIntern()); const loaded_union = ip.loadUnionType(container_ty.toIntern());
switch (loaded_union.flagsUnordered(ip).layout) { switch (loaded_union.flagsUnordered(ip).layout) {
@ -5892,10 +5889,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
}, },
} }
}, },
.anon_struct_type => |anon_struct_info| if (anon_struct_info.fieldName(ip, extra.field_index).unwrap()) |field_name| .tuple_type => .{ .field = extra.field_index },
.{ .identifier = field_name.toSlice(ip) }
else
.{ .field = extra.field_index },
.union_type => field_name: { .union_type => field_name: {
const loaded_union = ip.loadUnionType(struct_ty.toIntern()); const loaded_union = ip.loadUnionType(struct_ty.toIntern());
switch (loaded_union.flagsUnordered(ip).layout) { switch (loaded_union.flagsUnordered(ip).layout) {
@ -7366,16 +7360,13 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
}, },
} }
}, },
.anon_struct_type => |anon_struct_info| for (0..anon_struct_info.types.len) |field_index| { .tuple_type => |tuple_info| for (0..tuple_info.types.len) |field_index| {
if (anon_struct_info.values.get(ip)[field_index] != .none) continue; if (tuple_info.values.get(ip)[field_index] != .none) continue;
const field_ty = Type.fromInterned(anon_struct_info.types.get(ip)[field_index]); const field_ty = Type.fromInterned(tuple_info.types.get(ip)[field_index]);
if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue; if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
const a = try Assignment.start(f, writer, try f.ctypeFromType(field_ty, .complete)); const a = try Assignment.start(f, writer, try f.ctypeFromType(field_ty, .complete));
try f.writeCValueMember(writer, local, if (anon_struct_info.fieldName(ip, field_index).unwrap()) |field_name| try f.writeCValueMember(writer, local, .{ .field = field_index });
.{ .identifier = field_name.toSlice(ip) }
else
.{ .field = field_index });
try a.assign(f, writer); try a.assign(f, writer);
try f.writeCValue(writer, resolved_elements[field_index], .Other); try f.writeCValue(writer, resolved_elements[field_index], .Other);
try a.end(f, writer); try a.end(f, writer);

View File

@ -1350,7 +1350,7 @@ pub const Pool = struct {
.i0_type, .i0_type,
.anyopaque_type, .anyopaque_type,
.void_type, .void_type,
.empty_struct_type, .empty_tuple_type,
.type_type, .type_type,
.comptime_int_type, .comptime_int_type,
.comptime_float_type, .comptime_float_type,
@ -1450,7 +1450,7 @@ pub const Pool = struct {
.null_value, .null_value,
.bool_true, .bool_true,
.bool_false, .bool_false,
.empty_struct, .empty_tuple,
.generic_poison, .generic_poison,
.none, .none,
=> unreachable, => unreachable,
@ -1730,16 +1730,16 @@ pub const Pool = struct {
), ),
} }
}, },
.anon_struct_type => |anon_struct_info| { .tuple_type => |tuple_info| {
const scratch_top = scratch.items.len; const scratch_top = scratch.items.len;
defer scratch.shrinkRetainingCapacity(scratch_top); defer scratch.shrinkRetainingCapacity(scratch_top);
try scratch.ensureUnusedCapacity(allocator, anon_struct_info.types.len * try scratch.ensureUnusedCapacity(allocator, tuple_info.types.len *
@typeInfo(Field).@"struct".fields.len); @typeInfo(Field).@"struct".fields.len);
var hasher = Hasher.init; var hasher = Hasher.init;
for (0..anon_struct_info.types.len) |field_index| { for (0..tuple_info.types.len) |field_index| {
if (anon_struct_info.values.get(ip)[field_index] != .none) continue; if (tuple_info.values.get(ip)[field_index] != .none) continue;
const field_type = Type.fromInterned( const field_type = Type.fromInterned(
anon_struct_info.types.get(ip)[field_index], tuple_info.types.get(ip)[field_index],
); );
const field_ctype = try pool.fromType( const field_ctype = try pool.fromType(
allocator, allocator,
@ -1750,11 +1750,7 @@ pub const Pool = struct {
kind.noParameter(), kind.noParameter(),
); );
if (field_ctype.index == .void) continue; if (field_ctype.index == .void) continue;
const field_name = if (anon_struct_info.fieldName(ip, @intCast(field_index)) const field_name = try pool.fmt(allocator, "f{d}", .{field_index});
.unwrap()) |field_name|
try pool.string(allocator, field_name.toSlice(ip))
else
try pool.fmt(allocator, "f{d}", .{field_index});
pool.addHashedExtraAssumeCapacityTo(scratch, &hasher, Field, .{ pool.addHashedExtraAssumeCapacityTo(scratch, &hasher, Field, .{
.name = field_name.index, .name = field_name.index,
.ctype = field_ctype.index, .ctype = field_ctype.index,

View File

@ -2563,7 +2563,7 @@ pub const Object = struct {
} }
switch (ip.indexToKey(ty.toIntern())) { switch (ip.indexToKey(ty.toIntern())) {
.anon_struct_type => |tuple| { .tuple_type => |tuple| {
var fields: std.ArrayListUnmanaged(Builder.Metadata) = .empty; var fields: std.ArrayListUnmanaged(Builder.Metadata) = .empty;
defer fields.deinit(gpa); defer fields.deinit(gpa);
@ -2582,11 +2582,8 @@ pub const Object = struct {
const field_offset = field_align.forward(offset); const field_offset = field_align.forward(offset);
offset = field_offset + field_size; offset = field_offset + field_size;
const field_name = if (tuple.names.len != 0) var name_buf: [32]u8 = undefined;
tuple.names.get(ip)[i].toSlice(ip) const field_name = std.fmt.bufPrint(&name_buf, "{d}", .{i}) catch unreachable;
else
try std.fmt.allocPrintZ(gpa, "{d}", .{i});
defer if (tuple.names.len == 0) gpa.free(field_name);
fields.appendAssumeCapacity(try o.builder.debugMemberType( fields.appendAssumeCapacity(try o.builder.debugMemberType(
try o.builder.metadataString(field_name), try o.builder.metadataString(field_name),
@ -3426,7 +3423,7 @@ pub const Object = struct {
.adhoc_inferred_error_set_type, .adhoc_inferred_error_set_type,
=> try o.errorIntType(), => try o.errorIntType(),
.generic_poison_type, .generic_poison_type,
.empty_struct_type, .empty_tuple_type,
=> unreachable, => unreachable,
// values, not types // values, not types
.undef, .undef,
@ -3443,7 +3440,7 @@ pub const Object = struct {
.null_value, .null_value,
.bool_true, .bool_true,
.bool_false, .bool_false,
.empty_struct, .empty_tuple,
.generic_poison, .generic_poison,
.none, .none,
=> unreachable, => unreachable,
@ -3610,13 +3607,13 @@ pub const Object = struct {
); );
return ty; return ty;
}, },
.anon_struct_type => |anon_struct_type| { .tuple_type => |tuple_type| {
var llvm_field_types: std.ArrayListUnmanaged(Builder.Type) = .empty; var llvm_field_types: std.ArrayListUnmanaged(Builder.Type) = .empty;
defer llvm_field_types.deinit(o.gpa); defer llvm_field_types.deinit(o.gpa);
// Although we can estimate how much capacity to add, these cannot be // Although we can estimate how much capacity to add, these cannot be
// relied upon because of the recursive calls to lowerType below. // relied upon because of the recursive calls to lowerType below.
try llvm_field_types.ensureUnusedCapacity(o.gpa, anon_struct_type.types.len); try llvm_field_types.ensureUnusedCapacity(o.gpa, tuple_type.types.len);
try o.struct_field_map.ensureUnusedCapacity(o.gpa, anon_struct_type.types.len); try o.struct_field_map.ensureUnusedCapacity(o.gpa, tuple_type.types.len);
comptime assert(struct_layout_version == 2); comptime assert(struct_layout_version == 2);
var offset: u64 = 0; var offset: u64 = 0;
@ -3625,8 +3622,8 @@ pub const Object = struct {
const struct_size = t.abiSize(zcu); const struct_size = t.abiSize(zcu);
for ( for (
anon_struct_type.types.get(ip), tuple_type.types.get(ip),
anon_struct_type.values.get(ip), tuple_type.values.get(ip),
0.., 0..,
) |field_ty, field_val, field_index| { ) |field_ty, field_val, field_index| {
if (field_val != .none) continue; if (field_val != .none) continue;
@ -3979,7 +3976,7 @@ pub const Object = struct {
.error_union_type, .error_union_type,
.simple_type, .simple_type,
.struct_type, .struct_type,
.anon_struct_type, .tuple_type,
.union_type, .union_type,
.opaque_type, .opaque_type,
.enum_type, .enum_type,
@ -3993,7 +3990,7 @@ pub const Object = struct {
.undefined => unreachable, // non-runtime value .undefined => unreachable, // non-runtime value
.void => unreachable, // non-runtime value .void => unreachable, // non-runtime value
.null => unreachable, // non-runtime value .null => unreachable, // non-runtime value
.empty_struct => unreachable, // non-runtime value .empty_tuple => unreachable, // non-runtime value
.@"unreachable" => unreachable, // non-runtime value .@"unreachable" => unreachable, // non-runtime value
.generic_poison => unreachable, // non-runtime value .generic_poison => unreachable, // non-runtime value
@ -4232,7 +4229,7 @@ pub const Object = struct {
), ),
} }
}, },
.anon_struct_type => |tuple| { .tuple_type => |tuple| {
const struct_ty = try o.lowerType(ty); const struct_ty = try o.lowerType(ty);
const llvm_len = struct_ty.aggregateLen(&o.builder); const llvm_len = struct_ty.aggregateLen(&o.builder);
@ -12516,7 +12513,7 @@ fn isByRef(ty: Type, zcu: *Zcu) bool {
.array, .frame => return ty.hasRuntimeBits(zcu), .array, .frame => return ty.hasRuntimeBits(zcu),
.@"struct" => { .@"struct" => {
const struct_type = switch (ip.indexToKey(ty.toIntern())) { const struct_type = switch (ip.indexToKey(ty.toIntern())) {
.anon_struct_type => |tuple| { .tuple_type => |tuple| {
var count: usize = 0; var count: usize = 0;
for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, field_val| { for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, field_val| {
if (field_val != .none or !Type.fromInterned(field_ty).hasRuntimeBits(zcu)) continue; if (field_val != .none or !Type.fromInterned(field_ty).hasRuntimeBits(zcu)) continue;

View File

@ -731,13 +731,15 @@ const NavGen = struct {
.direct => { .direct => {
const result_ty_id = try self.resolveType(Type.bool, .direct); const result_ty_id = try self.resolveType(Type.bool, .direct);
const result_id = self.spv.allocId(); const result_id = self.spv.allocId();
const operands = .{
.id_result_type = result_ty_id,
.id_result = result_id,
};
switch (value) { switch (value) {
true => try section.emit(self.spv.gpa, .OpConstantTrue, operands), inline else => |val_ct| try section.emit(
false => try section.emit(self.spv.gpa, .OpConstantFalse, operands), self.spv.gpa,
if (val_ct) .OpConstantTrue else .OpConstantFalse,
.{
.id_result_type = result_ty_id,
.id_result = result_id,
},
),
} }
return result_id; return result_id;
}, },
@ -915,7 +917,7 @@ const NavGen = struct {
.error_union_type, .error_union_type,
.simple_type, .simple_type,
.struct_type, .struct_type,
.anon_struct_type, .tuple_type,
.union_type, .union_type,
.opaque_type, .opaque_type,
.enum_type, .enum_type,
@ -937,7 +939,7 @@ const NavGen = struct {
.undefined, .undefined,
.void, .void,
.null, .null,
.empty_struct, .empty_tuple,
.@"unreachable", .@"unreachable",
.generic_poison, .generic_poison,
=> unreachable, // non-runtime values => unreachable, // non-runtime values
@ -1125,7 +1127,7 @@ const NavGen = struct {
return try self.constructStruct(ty, types.items, constituents.items); return try self.constructStruct(ty, types.items, constituents.items);
}, },
.anon_struct_type => unreachable, // TODO .tuple_type => unreachable, // TODO
else => unreachable, else => unreachable,
}, },
.un => |un| { .un => |un| {
@ -1718,7 +1720,7 @@ const NavGen = struct {
}, },
.@"struct" => { .@"struct" => {
const struct_type = switch (ip.indexToKey(ty.toIntern())) { const struct_type = switch (ip.indexToKey(ty.toIntern())) {
.anon_struct_type => |tuple| { .tuple_type => |tuple| {
const member_types = try self.gpa.alloc(IdRef, tuple.values.len); const member_types = try self.gpa.alloc(IdRef, tuple.values.len);
defer self.gpa.free(member_types); defer self.gpa.free(member_types);
@ -2831,18 +2833,12 @@ const NavGen = struct {
} }
}, },
.vulkan => { .vulkan => {
const op_result_ty = blk: { // Operations return a struct{T, T}
// Operations return a struct{T, T} // where T is maybe vectorized.
// where T is maybe vectorized. const op_result_ty: Type = .fromInterned(try ip.getTupleType(zcu.gpa, pt.tid, .{
const types = [2]InternPool.Index{ arith_op_ty.toIntern(), arith_op_ty.toIntern() }; .types = &.{ arith_op_ty.toIntern(), arith_op_ty.toIntern() },
const values = [2]InternPool.Index{ .none, .none }; .values = &.{ .none, .none },
const index = try ip.getAnonStructType(zcu.gpa, pt.tid, .{ }));
.types = &types,
.values = &values,
.names = &.{},
});
break :blk Type.fromInterned(index);
};
const op_result_ty_id = try self.resolveType(op_result_ty, .direct); const op_result_ty_id = try self.resolveType(op_result_ty, .direct);
const opcode: Opcode = switch (op) { const opcode: Opcode = switch (op) {
@ -4867,7 +4863,7 @@ const NavGen = struct {
var index: usize = 0; var index: usize = 0;
switch (ip.indexToKey(result_ty.toIntern())) { switch (ip.indexToKey(result_ty.toIntern())) {
.anon_struct_type => |tuple| { .tuple_type => |tuple| {
for (tuple.types.get(ip), elements, 0..) |field_ty, element, i| { for (tuple.types.get(ip), elements, 0..) |field_ty, element, i| {
if ((try result_ty.structFieldValueComptime(pt, i)) != null) continue; if ((try result_ty.structFieldValueComptime(pt, i)) != null) continue;
assert(Type.fromInterned(field_ty).hasRuntimeBits(zcu)); assert(Type.fromInterned(field_ty).hasRuntimeBits(zcu));
@ -6216,15 +6212,20 @@ const NavGen = struct {
try self.extractField(Type.anyerror, operand_id, eu_layout.errorFieldIndex()); try self.extractField(Type.anyerror, operand_id, eu_layout.errorFieldIndex());
const result_id = self.spv.allocId(); const result_id = self.spv.allocId();
const operands = .{
.id_result_type = bool_ty_id,
.id_result = result_id,
.operand_1 = error_id,
.operand_2 = try self.constInt(Type.anyerror, 0, .direct),
};
switch (pred) { switch (pred) {
.is_err => try self.func.body.emit(self.spv.gpa, .OpINotEqual, operands), inline else => |pred_ct| try self.func.body.emit(
.is_non_err => try self.func.body.emit(self.spv.gpa, .OpIEqual, operands), self.spv.gpa,
switch (pred_ct) {
.is_err => .OpINotEqual,
.is_non_err => .OpIEqual,
},
.{
.id_result_type = bool_ty_id,
.id_result = result_id,
.operand_1 = error_id,
.operand_2 = try self.constInt(Type.anyerror, 0, .direct),
},
),
} }
return result_id; return result_id;
} }

View File

@ -2599,16 +2599,15 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
.anyframe_type, .anyframe_type,
.error_union_type, .error_union_type,
.simple_type, .simple_type,
.anon_struct_type, .tuple_type,
.func_type, .func_type,
.error_set_type, .error_set_type,
.inferred_error_set_type, .inferred_error_set_type,
=> .decl_alias, => .decl_alias,
.struct_type => tag: { .struct_type => tag: {
const loaded_struct = ip.loadStructType(nav_val.toIntern()); const loaded_struct = ip.loadStructType(nav_val.toIntern());
if (loaded_struct.zir_index == .none) break :tag .decl_alias;
const type_inst_info = loaded_struct.zir_index.unwrap().?.resolveFull(ip).?; const type_inst_info = loaded_struct.zir_index.resolveFull(ip).?;
if (type_inst_info.file != inst_info.file) break :tag .decl_alias; if (type_inst_info.file != inst_info.file) break :tag .decl_alias;
const value_inst = value_inst: { const value_inst = value_inst: {
@ -3349,7 +3348,7 @@ fn updateType(
.union_type, .union_type,
.opaque_type, .opaque_type,
=> unreachable, => unreachable,
.anon_struct_type => |anon_struct_type| if (anon_struct_type.types.len == 0) { .tuple_type => |tuple_type| if (tuple_type.types.len == 0) {
try wip_nav.abbrevCode(.namespace_struct_type); try wip_nav.abbrevCode(.namespace_struct_type);
try wip_nav.strp(name); try wip_nav.strp(name);
try diw.writeByte(@intFromBool(false)); try diw.writeByte(@intFromBool(false));
@ -3359,15 +3358,15 @@ fn updateType(
try uleb128(diw, ty.abiSize(zcu)); try uleb128(diw, ty.abiSize(zcu));
try uleb128(diw, ty.abiAlignment(zcu).toByteUnits().?); try uleb128(diw, ty.abiAlignment(zcu).toByteUnits().?);
var field_byte_offset: u64 = 0; var field_byte_offset: u64 = 0;
for (0..anon_struct_type.types.len) |field_index| { for (0..tuple_type.types.len) |field_index| {
const comptime_value = anon_struct_type.values.get(ip)[field_index]; const comptime_value = tuple_type.values.get(ip)[field_index];
try wip_nav.abbrevCode(if (comptime_value != .none) .struct_field_comptime else .struct_field); try wip_nav.abbrevCode(if (comptime_value != .none) .struct_field_comptime else .struct_field);
if (anon_struct_type.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else { {
const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index}); var name_buf: [32]u8 = undefined;
defer dwarf.gpa.free(field_name); const field_name = std.fmt.bufPrint(&name_buf, "{d}", .{field_index}) catch unreachable;
try wip_nav.strp(field_name); try wip_nav.strp(field_name);
} }
const field_type = Type.fromInterned(anon_struct_type.types.get(ip)[field_index]); const field_type = Type.fromInterned(tuple_type.types.get(ip)[field_index]);
try wip_nav.refType(field_type); try wip_nav.refType(field_type);
if (comptime_value != .none) try wip_nav.blockValue( if (comptime_value != .none) try wip_nav.blockValue(
src_loc, src_loc,
@ -3595,16 +3594,26 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items); try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
try wip_nav.flush(ty_src_loc); try wip_nav.flush(ty_src_loc);
} else { } else {
const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst)); {
assert(decl_inst.tag == .extended); // Note that changes to ZIR instruction tracking only need to update this code
if (switch (decl_inst.data.extended.opcode) { // if a newly-tracked instruction can be a type's owner `zir_index`.
.struct_decl => @as(Zir.Inst.StructDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy, comptime assert(Zir.inst_tracking_version == 0);
.enum_decl => @as(Zir.Inst.EnumDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
.union_decl => @as(Zir.Inst.UnionDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy, const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst));
.opaque_decl => @as(Zir.Inst.OpaqueDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy, const name_strat: Zir.Inst.NameStrategy = switch (decl_inst.tag) {
.reify => @as(Zir.Inst.NameStrategy, @enumFromInt(decl_inst.data.extended.small)), .struct_init, .struct_init_ref, .struct_init_anon => .anon,
else => unreachable, .extended => switch (decl_inst.data.extended.opcode) {
} == .parent) return; .struct_decl => @as(Zir.Inst.StructDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
.enum_decl => @as(Zir.Inst.EnumDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
.union_decl => @as(Zir.Inst.UnionDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
.opaque_decl => @as(Zir.Inst.OpaqueDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
.reify => @as(Zir.Inst.NameStrategy, @enumFromInt(decl_inst.data.extended.small)),
else => unreachable,
},
else => unreachable,
};
if (name_strat == .parent) return;
}
const unit = try dwarf.getUnit(file.mod); const unit = try dwarf.getUnit(file.mod);
const type_gop = try dwarf.types.getOrPut(dwarf.gpa, type_index); const type_gop = try dwarf.types.getOrPut(dwarf.gpa, type_index);

View File

@ -931,7 +931,7 @@ fn addNavExports(
break; break;
} }
} }
const sym = .{ const sym: aout.Sym = .{
.value = atom.offset.?, .value = atom.offset.?,
.type = atom.type.toGlobal(), .type = atom.type.toGlobal(),
.name = try gpa.dupe(u8, exp_name), .name = try gpa.dupe(u8, exp_name),

View File

@ -34,7 +34,7 @@ const Zcu = @import("Zcu.zig");
const mingw = @import("mingw.zig"); const mingw = @import("mingw.zig");
const dev = @import("dev.zig"); const dev = @import("dev.zig");
pub const std_options = .{ pub const std_options: std.Options = .{
.wasiCwd = wasi_cwd, .wasiCwd = wasi_cwd,
.logFn = log, .logFn = log,
.enable_segfault_handler = false, .enable_segfault_handler = false,

View File

@ -74,7 +74,7 @@ pub fn print(
.error_union_type, .error_union_type,
.simple_type, .simple_type,
.struct_type, .struct_type,
.anon_struct_type, .tuple_type,
.union_type, .union_type,
.opaque_type, .opaque_type,
.enum_type, .enum_type,
@ -85,7 +85,7 @@ pub fn print(
.undef => try writer.writeAll("undefined"), .undef => try writer.writeAll("undefined"),
.simple_value => |simple_value| switch (simple_value) { .simple_value => |simple_value| switch (simple_value) {
.void => try writer.writeAll("{}"), .void => try writer.writeAll("{}"),
.empty_struct => try writer.writeAll(".{}"), .empty_tuple => try writer.writeAll(".{}"),
.generic_poison => try writer.writeAll("(generic poison)"), .generic_poison => try writer.writeAll("(generic poison)"),
else => try writer.writeAll(@tagName(simple_value)), else => try writer.writeAll(@tagName(simple_value)),
}, },

View File

@ -563,6 +563,8 @@ const Writer = struct {
.enum_decl => try self.writeEnumDecl(stream, extended), .enum_decl => try self.writeEnumDecl(stream, extended),
.opaque_decl => try self.writeOpaqueDecl(stream, extended), .opaque_decl => try self.writeOpaqueDecl(stream, extended),
.tuple_decl => try self.writeTupleDecl(stream, extended),
.await_nosuspend, .await_nosuspend,
.c_undef, .c_undef,
.c_include, .c_include,
@ -1421,7 +1423,6 @@ const Writer = struct {
try self.writeFlag(stream, "known_non_opv, ", small.known_non_opv); 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, "known_comptime_only, ", small.known_comptime_only);
try self.writeFlag(stream, "tuple, ", small.is_tuple);
try stream.print("{s}, ", .{@tagName(small.name_strategy)}); try stream.print("{s}, ", .{@tagName(small.name_strategy)});
@ -1506,11 +1507,8 @@ const Writer = struct {
const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0; const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0;
cur_bit_bag >>= 1; cur_bit_bag >>= 1;
var field_name_index: Zir.NullTerminatedString = .empty; const field_name_index: Zir.NullTerminatedString = @enumFromInt(self.code.extra[extra_index]);
if (!small.is_tuple) { extra_index += 1;
field_name_index = @enumFromInt(self.code.extra[extra_index]);
extra_index += 1;
}
const doc_comment_index: Zir.NullTerminatedString = @enumFromInt(self.code.extra[extra_index]); const doc_comment_index: Zir.NullTerminatedString = @enumFromInt(self.code.extra[extra_index]);
extra_index += 1; extra_index += 1;
@ -1948,6 +1946,32 @@ const Writer = struct {
try self.writeSrcNode(stream, 0); try self.writeSrcNode(stream, 0);
} }
fn writeTupleDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
const fields_len = extended.small;
assert(fields_len != 0);
const extra = self.code.extraData(Zir.Inst.TupleDecl, extended.operand);
var extra_index = extra.end;
try stream.writeAll("{ ");
for (0..fields_len) |field_idx| {
if (field_idx != 0) try stream.writeAll(", ");
const field_ty, const field_init = self.code.extra[extra_index..][0..2].*;
extra_index += 2;
try stream.print("@\"{d}\": ", .{field_idx});
try self.writeInstRef(stream, @enumFromInt(field_ty));
try stream.writeAll(" = ");
try self.writeInstRef(stream, @enumFromInt(field_init));
}
try stream.writeAll(" }) ");
try self.writeSrcNode(stream, extra.data.src_node);
}
fn writeErrorSetDecl( fn writeErrorSetDecl(
self: *Writer, self: *Writer,
stream: anytype, stream: anytype,

View File

@ -2314,8 +2314,11 @@ fn transStringLiteralInitializer(
while (i < num_inits) : (i += 1) { while (i < num_inits) : (i += 1) {
init_list[i] = try transCreateCharLitNode(c, false, stmt.getCodeUnit(i)); init_list[i] = try transCreateCharLitNode(c, false, stmt.getCodeUnit(i));
} }
const init_args = .{ .len = num_inits, .elem_type = elem_type }; const init_args: ast.Payload.Array.ArrayTypeInfo = .{ .len = num_inits, .elem_type = elem_type };
const init_array_type = try if (array_type.tag() == .array_type) Tag.array_type.create(c.arena, init_args) else Tag.null_sentinel_array_type.create(c.arena, init_args); const init_array_type = if (array_type.tag() == .array_type)
try Tag.array_type.create(c.arena, init_args)
else
try Tag.null_sentinel_array_type.create(c.arena, init_args);
break :blk try Tag.array_init.create(c.arena, .{ break :blk try Tag.array_init.create(c.arena, .{
.cond = init_array_type, .cond = init_array_type,
.cases = init_list, .cases = init_list,
@ -3910,7 +3913,7 @@ fn transCreateCompoundAssign(
if ((is_mod or is_div) and is_signed) { if ((is_mod or is_div) and is_signed) {
if (requires_cast) rhs_node = try transCCast(c, scope, loc, lhs_qt, rhs_qt, rhs_node); if (requires_cast) rhs_node = try transCCast(c, scope, loc, lhs_qt, rhs_qt, rhs_node);
const operands = .{ .lhs = lhs_node, .rhs = rhs_node }; const operands: @FieldType(ast.Payload.BinOp, "data") = .{ .lhs = lhs_node, .rhs = rhs_node };
const builtin = if (is_mod) const builtin = if (is_mod)
try Tag.signed_remainder.create(c.arena, operands) try Tag.signed_remainder.create(c.arena, operands)
else else
@ -3949,7 +3952,7 @@ fn transCreateCompoundAssign(
if (is_ptr_op_signed) rhs_node = try usizeCastForWrappingPtrArithmetic(c.arena, rhs_node); if (is_ptr_op_signed) rhs_node = try usizeCastForWrappingPtrArithmetic(c.arena, rhs_node);
if ((is_mod or is_div) and is_signed) { if ((is_mod or is_div) and is_signed) {
if (requires_cast) rhs_node = try transCCast(c, scope, loc, lhs_qt, rhs_qt, rhs_node); if (requires_cast) rhs_node = try transCCast(c, scope, loc, lhs_qt, rhs_qt, rhs_node);
const operands = .{ .lhs = ref_node, .rhs = rhs_node }; const operands: @FieldType(ast.Payload.BinOp, "data") = .{ .lhs = ref_node, .rhs = rhs_node };
const builtin = if (is_mod) const builtin = if (is_mod)
try Tag.signed_remainder.create(c.arena, operands) try Tag.signed_remainder.create(c.arena, operands)
else else
@ -4777,7 +4780,7 @@ fn transType(c: *Context, scope: *Scope, ty: *const clang.Type, source_loc: clan
const is_const = is_fn_proto or child_qt.isConstQualified(); const is_const = is_fn_proto or child_qt.isConstQualified();
const is_volatile = child_qt.isVolatileQualified(); const is_volatile = child_qt.isVolatileQualified();
const elem_type = try transQualType(c, scope, child_qt, source_loc); const elem_type = try transQualType(c, scope, child_qt, source_loc);
const ptr_info = .{ const ptr_info: @FieldType(ast.Payload.Pointer, "data") = .{
.is_const = is_const, .is_const = is_const,
.is_volatile = is_volatile, .is_volatile = is_volatile,
.elem_type = elem_type, .elem_type = elem_type,

View File

@ -26,7 +26,6 @@ test {
_ = @import("behavior/duplicated_test_names.zig"); _ = @import("behavior/duplicated_test_names.zig");
_ = @import("behavior/defer.zig"); _ = @import("behavior/defer.zig");
_ = @import("behavior/destructure.zig"); _ = @import("behavior/destructure.zig");
_ = @import("behavior/empty_tuple_fields.zig");
_ = @import("behavior/empty_union.zig"); _ = @import("behavior/empty_union.zig");
_ = @import("behavior/enum.zig"); _ = @import("behavior/enum.zig");
_ = @import("behavior/error.zig"); _ = @import("behavior/error.zig");

View File

@ -596,7 +596,7 @@ test "type coercion of anon struct literal to array" {
var x2: U = .{ .a = 42 }; var x2: U = .{ .a = 42 };
_ = &x2; _ = &x2;
const t2 = .{ x2, .{ .b = true }, .{ .c = "hello" } }; const t2 = .{ x2, U{ .b = true }, U{ .c = "hello" } };
const arr2: [3]U = t2; const arr2: [3]U = t2;
try expect(arr2[0].a == 42); try expect(arr2[0].a == 42);
try expect(arr2[1].b == true); try expect(arr2[1].b == true);
@ -607,40 +607,6 @@ test "type coercion of anon struct literal to array" {
try comptime S.doTheTest(); try comptime S.doTheTest();
} }
test "type coercion of pointer to anon struct literal to pointer to array" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
const S = struct {
const U = union {
a: u32,
b: bool,
c: []const u8,
};
fn doTheTest() !void {
var x1: u8 = 42;
_ = &x1;
const t1 = &.{ x1, 56, 54 };
const arr1: *const [3]u8 = t1;
try expect(arr1[0] == 42);
try expect(arr1[1] == 56);
try expect(arr1[2] == 54);
var x2: U = .{ .a = 42 };
_ = &x2;
const t2 = &.{ x2, .{ .b = true }, .{ .c = "hello" } };
const arr2: *const [3]U = t2;
try expect(arr2[0].a == 42);
try expect(arr2[1].b == true);
try expect(mem.eql(u8, arr2[2].c, "hello"));
}
};
try S.doTheTest();
try comptime S.doTheTest();
}
test "array with comptime-only element type" { test "array with comptime-only element type" {
const a = [_]type{ u32, i32 }; const a = [_]type{ u32, i32 };
try testing.expect(a[0] == u32); try testing.expect(a[0] == u32);

View File

@ -2600,32 +2600,6 @@ test "result type is preserved into comptime block" {
try expect(x == 123); try expect(x == 123);
} }
test "implicit cast from ptr to tuple to ptr to struct" {
if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
const ComptimeReason = union(enum) {
c_import: struct {
a: u32,
},
};
const Block = struct {
reason: ?*const ComptimeReason,
};
var a: u32 = 16;
_ = &a;
var reason = .{ .c_import = .{ .a = a } };
var block = Block{
.reason = &reason,
};
_ = &block;
try expect(block.reason.?.c_import.a == 16);
}
test "bitcast vector" { test "bitcast vector" {
if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO

View File

@ -1 +0,0 @@
struct {}

View File

@ -1 +0,0 @@
union {}

View File

@ -1,28 +0,0 @@
const std = @import("std");
const builtin = @import("builtin");
test "empty file level struct" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
const T = @import("empty_file_level_struct.zig");
const info = @typeInfo(T);
try std.testing.expectEqual(@as(usize, 1), info.@"struct".fields.len);
try std.testing.expectEqualStrings("0", info.@"struct".fields[0].name);
try std.testing.expect(@typeInfo(info.@"struct".fields[0].type) == .@"struct");
}
test "empty file level union" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
const T = @import("empty_file_level_union.zig");
const info = @typeInfo(T);
try std.testing.expectEqual(@as(usize, 1), info.@"struct".fields.len);
try std.testing.expectEqualStrings("0", info.@"struct".fields[0].name);
try std.testing.expect(@typeInfo(info.@"struct".fields[0].type) == .@"union");
}

View File

@ -1013,84 +1013,6 @@ test "struct with 0-length union array field" {
try expectEqual(@as(usize, 0), s.zero_length.len); try expectEqual(@as(usize, 0), s.zero_length.len);
} }
test "type coercion of anon struct literal to struct" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
const S = struct {
const S2 = struct {
A: u32,
B: []const u8,
C: void,
D: Foo = .{},
};
const Foo = struct {
field: i32 = 1234,
};
fn doTheTest() !void {
var y: u32 = 42;
_ = &y;
const t0 = .{ .A = 123, .B = "foo", .C = {} };
const t1 = .{ .A = y, .B = "foo", .C = {} };
const y0: S2 = t0;
const y1: S2 = t1;
try expect(y0.A == 123);
try expect(std.mem.eql(u8, y0.B, "foo"));
try expect(y0.C == {});
try expect(y0.D.field == 1234);
try expect(y1.A == y);
try expect(std.mem.eql(u8, y1.B, "foo"));
try expect(y1.C == {});
try expect(y1.D.field == 1234);
}
};
try S.doTheTest();
try comptime S.doTheTest();
}
test "type coercion of pointer to anon struct literal to pointer to struct" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
const S = struct {
const S2 = struct {
A: u32,
B: []const u8,
C: void,
D: Foo = .{},
};
const Foo = struct {
field: i32 = 1234,
};
fn doTheTest() !void {
var y: u32 = 42;
_ = &y;
const t0 = &.{ .A = 123, .B = "foo", .C = {} };
const t1 = &.{ .A = y, .B = "foo", .C = {} };
const y0: *const S2 = t0;
const y1: *const S2 = t1;
try expect(y0.A == 123);
try expect(std.mem.eql(u8, y0.B, "foo"));
try expect(y0.C == {});
try expect(y0.D.field == 1234);
try expect(y1.A == y);
try expect(std.mem.eql(u8, y1.B, "foo"));
try expect(y1.C == {});
try expect(y1.D.field == 1234);
}
};
try S.doTheTest();
try comptime S.doTheTest();
}
test "packed struct with undefined initializers" { test "packed struct with undefined initializers" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
@ -2183,3 +2105,20 @@ test "extern struct @FieldType" {
comptime assert(@FieldType(S, "b") == f64); comptime assert(@FieldType(S, "b") == f64);
comptime assert(@FieldType(S, "c") == *S); comptime assert(@FieldType(S, "c") == *S);
} }
test "anonymous struct equivalence" {
const S = struct {
fn anonStructType(comptime x: anytype) type {
const val = .{ .a = "hello", .b = x };
return @TypeOf(val);
}
};
const A = S.anonStructType(123);
const B = S.anonStructType(123);
const C = S.anonStructType(456);
comptime assert(A == B);
comptime assert(A != C);
comptime assert(B != C);
}

View File

@ -150,7 +150,7 @@ test "array-like initializer for tuple types" {
.type = u8, .type = u8,
.default_value = null, .default_value = null,
.is_comptime = false, .is_comptime = false,
.alignment = @alignOf(i32), .alignment = @alignOf(u8),
}, },
}, },
}, },
@ -566,16 +566,28 @@ test "comptime fields in tuple can be initialized" {
_ = &a; _ = &a;
} }
test "tuple default values" { test "empty struct in tuple" {
const T = struct { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
usize, if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
usize = 123, if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
usize = 456, if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
};
const t: T = .{1}; const T = struct { struct {} };
const info = @typeInfo(T);
try expectEqual(1, t[0]); try std.testing.expectEqual(@as(usize, 1), info.@"struct".fields.len);
try expectEqual(123, t[1]); try std.testing.expectEqualStrings("0", info.@"struct".fields[0].name);
try expectEqual(456, t[2]); try std.testing.expect(@typeInfo(info.@"struct".fields[0].type) == .@"struct");
}
test "empty union in tuple" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
const T = struct { union {} };
const info = @typeInfo(T);
try std.testing.expectEqual(@as(usize, 1), info.@"struct".fields.len);
try std.testing.expectEqualStrings("0", info.@"struct".fields[0].name);
try std.testing.expect(@typeInfo(info.@"struct".fields[0].type) == .@"union");
} }

View File

@ -9,7 +9,7 @@ test "tuple declaration type info" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
{ {
const T = struct { comptime u32 align(2) = 1, []const u8 }; const T = struct { comptime u32 = 1, []const u8 };
const info = @typeInfo(T).@"struct"; const info = @typeInfo(T).@"struct";
try expect(info.layout == .auto); try expect(info.layout == .auto);
@ -22,7 +22,7 @@ test "tuple declaration type info" {
try expect(info.fields[0].type == u32); try expect(info.fields[0].type == u32);
try expect(@as(*const u32, @ptrCast(@alignCast(info.fields[0].default_value))).* == 1); try expect(@as(*const u32, @ptrCast(@alignCast(info.fields[0].default_value))).* == 1);
try expect(info.fields[0].is_comptime); try expect(info.fields[0].is_comptime);
try expect(info.fields[0].alignment == 2); try expect(info.fields[0].alignment == @alignOf(u32));
try expectEqualStrings(info.fields[1].name, "1"); try expectEqualStrings(info.fields[1].name, "1");
try expect(info.fields[1].type == []const u8); try expect(info.fields[1].type == []const u8);
@ -32,7 +32,7 @@ test "tuple declaration type info" {
} }
} }
test "Tuple declaration usage" { test "tuple declaration usage" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;

View File

@ -986,76 +986,6 @@ test "function call result coerces from tagged union to the tag" {
try comptime S.doTheTest(); try comptime S.doTheTest();
} }
test "cast from anonymous struct to union" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
const S = struct {
const U = union(enum) {
A: u32,
B: []const u8,
C: void,
};
fn doTheTest() !void {
var y: u32 = 42;
_ = &y;
const t0 = .{ .A = 123 };
const t1 = .{ .B = "foo" };
const t2 = .{ .C = {} };
const t3 = .{ .A = y };
const x0: U = t0;
var x1: U = t1;
_ = &x1;
const x2: U = t2;
var x3: U = t3;
_ = &x3;
try expect(x0.A == 123);
try expect(std.mem.eql(u8, x1.B, "foo"));
try expect(x2 == .C);
try expect(x3.A == y);
}
};
try S.doTheTest();
try comptime S.doTheTest();
}
test "cast from pointer to anonymous struct to pointer to union" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
const S = struct {
const U = union(enum) {
A: u32,
B: []const u8,
C: void,
};
fn doTheTest() !void {
var y: u32 = 42;
_ = &y;
const t0 = &.{ .A = 123 };
const t1 = &.{ .B = "foo" };
const t2 = &.{ .C = {} };
const t3 = &.{ .A = y };
const x0: *const U = t0;
var x1: *const U = t1;
_ = &x1;
const x2: *const U = t2;
var x3: *const U = t3;
_ = &x3;
try expect(x0.A == 123);
try expect(std.mem.eql(u8, x1.B, "foo"));
try expect(x2.* == .C);
try expect(x3.A == y);
}
};
try S.doTheTest();
try comptime S.doTheTest();
}
test "switching on non exhaustive union" { test "switching on non exhaustive union" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO

View File

@ -1,7 +1,8 @@
export fn foo() void { export fn foo() void {
const S = struct { a: u32 }; const S = struct { a: u32 };
const sentinel: S = .{ .a = 1 };
var arr = [_]S{ .{ .a = 1 }, .{ .a = 2 } }; var arr = [_]S{ .{ .a = 1 }, .{ .a = 2 } };
const s = arr[0..1 :.{ .a = 1 }]; const s = arr[0..1 :sentinel];
_ = s; _ = s;
} }
@ -9,5 +10,5 @@ export fn foo() void {
// backend=stage2 // backend=stage2
// target=native // target=native
// //
// :4:26: error: non-scalar sentinel type 'tmp.foo.S' // :5:25: error: non-scalar sentinel type 'tmp.foo.S'
// :2:15: note: struct declared here // :2:15: note: struct declared here

View File

@ -18,4 +18,5 @@ pub export fn entry2() void {
// //
// :3:6: error: no field or member function named 'copy' in '[]const u8' // :3:6: error: no field or member function named 'copy' in '[]const u8'
// :9:8: error: no field or member function named 'bar' in '@TypeOf(.{})' // :9:8: error: no field or member function named 'bar' in '@TypeOf(.{})'
// :12:18: error: no field or member function named 'bar' in 'struct{comptime foo: comptime_int = 1}' // :12:18: error: no field or member function named 'bar' in 'tmp.entry2__struct_170'
// :12:6: note: struct declared here

View File

@ -0,0 +1,11 @@
const T = struct { x: u32 };
export fn foo() void {
const a = .{ .x = 123 };
_ = @as(T, a);
}
// error
//
// :4:16: error: expected type 'tmp.T', found 'tmp.foo__struct_159'
// :3:16: note: struct declared here
// :1:11: note: struct declared here

View File

@ -10,6 +10,6 @@ pub export fn entry() void {
// backend=stage2 // backend=stage2
// target=native // target=native
// //
// :4:28: error: type 'anyerror!tmp.entry.Foo' cannot be destructured // :4:28: error: type 'anyerror!struct { u8, u8 }' cannot be destructured
// :4:26: note: result destructured here // :4:26: note: result destructured here
// :4:28: note: consider using 'try', 'catch', or 'if' // :4:28: note: consider using 'try', 'catch', or 'if'

View File

@ -0,0 +1,6 @@
u32,
comptime u8 = 123,
// error
//
// :1:1: error: file cannot be a tuple

View File

@ -10,11 +10,6 @@ export fn badTupleField() void {
_ = .{ &x, &y }; _ = .{ &x, &y };
_ = @TypeOf(x, y); _ = @TypeOf(x, y);
} }
export fn badNestedField() void {
const x = .{ .foo = "hi", .bar = .{ 0, 1 } };
const y = .{ .foo = "hello", .bar = .{ 2, "hi" } };
_ = @TypeOf(x, y);
}
export fn incompatiblePointers() void { export fn incompatiblePointers() void {
const x: []const u8 = "foo"; const x: []const u8 = "foo";
const y: [*:0]const u8 = "bar"; const y: [*:0]const u8 = "bar";
@ -39,14 +34,9 @@ export fn incompatiblePointers4() void {
// :11:9: note: incompatible types: 'u32' and '*const [5:0]u8' // :11:9: note: incompatible types: 'u32' and '*const [5:0]u8'
// :11:17: note: type 'u32' here // :11:17: note: type 'u32' here
// :11:20: note: type '*const [5:0]u8' here // :11:20: note: type '*const [5:0]u8' here
// :16:9: error: struct field 'bar' has conflicting types // :16:9: error: incompatible types: '[]const u8' and '[*:0]const u8'
// :16:9: note: struct field '1' has conflicting types // :16:17: note: type '[]const u8' here
// :16:9: note: incompatible types: 'comptime_int' and '*const [2:0]u8' // :16:20: note: type '[*:0]const u8' here
// :16:17: note: type 'comptime_int' here // :23:9: error: incompatible types: '[]const u8' and '[*]const u8'
// :16:20: note: type '*const [2:0]u8' here // :23:23: note: type '[]const u8' here
// :21:9: error: incompatible types: '[]const u8' and '[*:0]const u8' // :23:26: note: type '[*]const u8' here
// :21:17: note: type '[]const u8' here
// :21:20: note: type '[*:0]const u8' here
// :28:9: error: incompatible types: '[]const u8' and '[*]const u8'
// :28:23: note: type '[]const u8' here
// :28:26: note: type '[*]const u8' here

View File

@ -29,7 +29,5 @@ export fn h() void {
// :9:16: error: missing struct field: x // :9:16: error: missing struct field: x
// :1:11: note: struct declared here // :1:11: note: struct declared here
// :18:16: error: missing tuple field with index 1 // :18:16: error: missing tuple field with index 1
// :16:11: note: struct declared here
// :22:16: error: missing tuple field with index 0 // :22:16: error: missing tuple field with index 0
// :22:16: note: missing tuple field with index 1 // :22:16: note: missing tuple field with index 1
// :16:11: note: struct declared here

View File

@ -21,6 +21,6 @@ comptime {
// :14:5: note: also here // :14:5: note: also here
// //
// Compile Log Output: // Compile Log Output:
// @as(struct{@Vector(3, u8), @Vector(3, u1)}, .{ .{ 2, 144, undefined }, .{ 0, 1, undefined } }) // @as(struct { @Vector(3, u8), @Vector(3, u1) }, .{ .{ 2, 144, undefined }, .{ 0, 1, undefined } })
// @as(struct{@Vector(3, u8), @Vector(3, u1)}, .{ .{ 1, 255, undefined }, .{ 0, 1, undefined } }) // @as(struct { @Vector(3, u8), @Vector(3, u1) }, .{ .{ 1, 255, undefined }, .{ 0, 1, undefined } })
// @as(struct{@Vector(3, u8), @Vector(3, u1)}, .{ .{ 1, 64, undefined }, .{ 0, 1, undefined } }) // @as(struct { @Vector(3, u8), @Vector(3, u1) }, .{ .{ 1, 64, undefined }, .{ 0, 1, undefined } })

View File

@ -72,6 +72,5 @@ pub export fn entry6() void {
// :18:14: error: missing tuple field with index 1 // :18:14: error: missing tuple field with index 1
// :25:14: error: missing tuple field with index 1 // :25:14: error: missing tuple field with index 1
// :43:14: error: expected at most 2 tuple fields; found 3 // :43:14: error: expected at most 2 tuple fields; found 3
// :50:30: error: index '2' out of bounds of tuple 'struct{comptime comptime_int = 123, u32}' // :50:30: error: index '2' out of bounds of tuple 'struct { comptime comptime_int = 123, u32 }'
// :63:37: error: missing tuple field with index 3 // :63:37: error: missing tuple field with index 3
// :58:32: note: struct declared here

View File

@ -7,4 +7,4 @@ export fn entry() void {
// backend=stage2 // backend=stage2
// target=native // target=native
// //
// :3:11: error: expected type '@TypeOf(.{})', found 'struct{comptime comptime_int = 1, comptime comptime_int = 2, comptime comptime_int = 3}' // :3:11: error: expected type '@TypeOf(.{})', found 'struct { comptime comptime_int = 1, comptime comptime_int = 2, comptime comptime_int = 3 }'

View File

@ -440,7 +440,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
cases.add("std.log per scope log level override", cases.add("std.log per scope log level override",
\\const std = @import("std"); \\const std = @import("std");
\\ \\
\\pub const std_options = .{ \\pub const std_options: std.Options = .{
\\ .log_level = .debug, \\ .log_level = .debug,
\\ \\
\\ .log_scope_levels = &.{ \\ .log_scope_levels = &.{
@ -497,7 +497,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
cases.add("std.heap.LoggingAllocator logs to std.log", cases.add("std.heap.LoggingAllocator logs to std.log",
\\const std = @import("std"); \\const std = @import("std");
\\ \\
\\pub const std_options = .{ \\pub const std_options: std.Options = .{
\\ .log_level = .debug, \\ .log_level = .debug,
\\ .logFn = log, \\ .logFn = log,
\\}; \\};

View File

@ -1532,18 +1532,18 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void {
, ,
&.{ &.{
\\(lldb) frame variable --show-types -- list0 list0.len list0.capacity list0[0] list0[1] list0[2] list0.0 list0.1 list0.2 \\(lldb) frame variable --show-types -- list0 list0.len list0.capacity list0[0] list0[1] list0[2] list0.0 list0.1 list0.2
\\(std.multi_array_list.MultiArrayList(main.Elem0)) list0 = len=3 capacity=8 { \\(std.multi_array_list.MultiArrayList(struct { u32, u8, u16 })) list0 = len=3 capacity=8 {
\\ (root.main.Elem0) [0] = { \\ (std.struct { u32, u8, u16 }) [0] = {
\\ (u32) .@"0" = 1 \\ (u32) .@"0" = 1
\\ (u8) .@"1" = 2 \\ (u8) .@"1" = 2
\\ (u16) .@"2" = 3 \\ (u16) .@"2" = 3
\\ } \\ }
\\ (root.main.Elem0) [1] = { \\ (std.struct { u32, u8, u16 }) [1] = {
\\ (u32) .@"0" = 4 \\ (u32) .@"0" = 4
\\ (u8) .@"1" = 5 \\ (u8) .@"1" = 5
\\ (u16) .@"2" = 6 \\ (u16) .@"2" = 6
\\ } \\ }
\\ (root.main.Elem0) [2] = { \\ (std.struct { u32, u8, u16 }) [2] = {
\\ (u32) .@"0" = 7 \\ (u32) .@"0" = 7
\\ (u8) .@"1" = 8 \\ (u8) .@"1" = 8
\\ (u16) .@"2" = 9 \\ (u16) .@"2" = 9
@ -1551,17 +1551,17 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void {
\\} \\}
\\(usize) list0.len = 3 \\(usize) list0.len = 3
\\(usize) list0.capacity = 8 \\(usize) list0.capacity = 8
\\(root.main.Elem0) list0[0] = { \\(std.struct { u32, u8, u16 }) list0[0] = {
\\ (u32) .@"0" = 1 \\ (u32) .@"0" = 1
\\ (u8) .@"1" = 2 \\ (u8) .@"1" = 2
\\ (u16) .@"2" = 3 \\ (u16) .@"2" = 3
\\} \\}
\\(root.main.Elem0) list0[1] = { \\(std.struct { u32, u8, u16 }) list0[1] = {
\\ (u32) .@"0" = 4 \\ (u32) .@"0" = 4
\\ (u8) .@"1" = 5 \\ (u8) .@"1" = 5
\\ (u16) .@"2" = 6 \\ (u16) .@"2" = 6
\\} \\}
\\(root.main.Elem0) list0[2] = { \\(std.struct { u32, u8, u16 }) list0[2] = {
\\ (u32) .@"0" = 7 \\ (u32) .@"0" = 7
\\ (u8) .@"1" = 8 \\ (u8) .@"1" = 8
\\ (u16) .@"2" = 9 \\ (u16) .@"2" = 9
@ -1582,18 +1582,18 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void {
\\ (u16) [2] = 9 \\ (u16) [2] = 9
\\} \\}
\\(lldb) frame variable --show-types -- slice0 slice0.len slice0.capacity slice0[0] slice0[1] slice0[2] slice0.0 slice0.1 slice0.2 \\(lldb) frame variable --show-types -- slice0 slice0.len slice0.capacity slice0[0] slice0[1] slice0[2] slice0.0 slice0.1 slice0.2
\\(std.multi_array_list.MultiArrayList(main.Elem0).Slice) slice0 = len=3 capacity=8 { \\(std.multi_array_list.MultiArrayList(struct { u32, u8, u16 }).Slice) slice0 = len=3 capacity=8 {
\\ (root.main.Elem0) [0] = { \\ (std.struct { u32, u8, u16 }) [0] = {
\\ (u32) .@"0" = 1 \\ (u32) .@"0" = 1
\\ (u8) .@"1" = 2 \\ (u8) .@"1" = 2
\\ (u16) .@"2" = 3 \\ (u16) .@"2" = 3
\\ } \\ }
\\ (root.main.Elem0) [1] = { \\ (std.struct { u32, u8, u16 }) [1] = {
\\ (u32) .@"0" = 4 \\ (u32) .@"0" = 4
\\ (u8) .@"1" = 5 \\ (u8) .@"1" = 5
\\ (u16) .@"2" = 6 \\ (u16) .@"2" = 6
\\ } \\ }
\\ (root.main.Elem0) [2] = { \\ (std.struct { u32, u8, u16 }) [2] = {
\\ (u32) .@"0" = 7 \\ (u32) .@"0" = 7
\\ (u8) .@"1" = 8 \\ (u8) .@"1" = 8
\\ (u16) .@"2" = 9 \\ (u16) .@"2" = 9
@ -1601,17 +1601,17 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void {
\\} \\}
\\(usize) slice0.len = 3 \\(usize) slice0.len = 3
\\(usize) slice0.capacity = 8 \\(usize) slice0.capacity = 8
\\(root.main.Elem0) slice0[0] = { \\(std.struct { u32, u8, u16 }) slice0[0] = {
\\ (u32) .@"0" = 1 \\ (u32) .@"0" = 1
\\ (u8) .@"1" = 2 \\ (u8) .@"1" = 2
\\ (u16) .@"2" = 3 \\ (u16) .@"2" = 3
\\} \\}
\\(root.main.Elem0) slice0[1] = { \\(std.struct { u32, u8, u16 }) slice0[1] = {
\\ (u32) .@"0" = 4 \\ (u32) .@"0" = 4
\\ (u8) .@"1" = 5 \\ (u8) .@"1" = 5
\\ (u16) .@"2" = 6 \\ (u16) .@"2" = 6
\\} \\}
\\(root.main.Elem0) slice0[2] = { \\(std.struct { u32, u8, u16 }) slice0[2] = {
\\ (u32) .@"0" = 7 \\ (u32) .@"0" = 7
\\ (u8) .@"1" = 8 \\ (u8) .@"1" = 8
\\ (u16) .@"2" = 9 \\ (u16) .@"2" = 9

View File

@ -1,7 +1,7 @@
const std = @import("std"); const std = @import("std");
const build_options = @import("build_options"); const build_options = @import("build_options");
pub const std_options = .{ pub const std_options: std.Options = .{
.keep_sigpipe = build_options.keep_sigpipe, .keep_sigpipe = build_options.keep_sigpipe,
}; };

View File

@ -1,6 +1,6 @@
const std = @import("std"); const std = @import("std");
pub const std_options = .{ pub const std_options: std.Options = .{
.logFn = log, .logFn = log,
}; };