authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-01-23 09:59:32+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-03-10 10:26:07+00:00
log3086c7977bee8cfe41c385d3ba389971b9a28380
treef44098abd363cdb96722c1887e69c5d1033658e2
parent6e49697ef576e86799c8365492082fdee9d216a9
signaturelock-open Commit is signed but in an unrecognized format.

type resolution progress


27 files changed, 3033 insertions(+), 2957 deletions(-)

lib/std/zig.zig+9
......@@ -837,6 +837,10 @@ pub const SimpleComptimeReason = enum(u32) {
837837 tuple_field_types,
838838 enum_field_names,
839839 enum_field_values,
840 union_enum_tag_type,
841 enum_int_tag_type,
842 packed_struct_backing_int_type,
843 packed_union_backing_int_type,
840844
841845 // Evaluating at comptime because decl/field name must be comptime-known.
842846 decl_name,
......@@ -925,6 +929,11 @@ pub const SimpleComptimeReason = enum(u32) {
925929 .enum_field_names => "enum field names must be comptime-known",
926930 .enum_field_values => "enum field values must be comptime-known",
927931
932 .union_enum_tag_type => "enum tag type of union must be comptime-known",
933 .enum_int_tag_type => "integer tag type of enum must be comptime-known",
934 .packed_struct_backing_int_type => "packed struct backing integer type must be comptime-known",
935 .packed_union_backing_int_type => "packed struct backing integer type must be comptime-known",
936
928937 .decl_name => "declaration name must be comptime-known",
929938 .field_name => "field name must be comptime-known",
930939 .tuple_field_index => "tuple field index must be comptime-known",
lib/std/zig/AstGen.zig+69-54
......@@ -4922,24 +4922,14 @@ fn structDeclInner(
49224922
49234923 astgen.advanceSourceCursorToNode(node);
49244924
4925 const backing_int_type_ref: Zir.Inst.Ref = ty: {
4926 const backing_int_node = maybe_backing_int_node.unwrap() orelse break :ty .none;
4927 if (layout != .@"packed") return astgen.failNode(
4928 backing_int_node,
4929 "non-packed struct does not support backing integer type",
4930 .{},
4931 );
4932 break :ty try typeExpr(gz, scope, backing_int_node);
4933 };
4934
49354925 const decl_inst = try gz.reserveInstructionIndex();
49364926
4937 if (container_decl.ast.members.len == 0 and backing_int_type_ref == .none) {
4927 if (container_decl.ast.members.len == 0 and maybe_backing_int_node == .none) {
49384928 try gz.setStruct(decl_inst, .{
49394929 .src_node = node,
49404930 .name_strat = name_strat,
49414931 .layout = layout,
4942 .backing_int_type = .none,
4932 .backing_int_type_body_len = null,
49434933 .decls_len = 0,
49444934 .fields_len = 0,
49454935 .any_field_aligns = false,
......@@ -4993,6 +4983,22 @@ fn structDeclInner(
49934983 );
49944984 if (field_comptime_bits) |bits| @memset(bits.get(astgen), 0);
49954985
4986 // Before any field bodies comes the backing int type, if specified.
4987 const backing_int_type_body_len: ?u32 = if (maybe_backing_int_node.unwrap()) |backing_int_node| len: {
4988 if (layout != .@"packed") return astgen.failNode(
4989 backing_int_node,
4990 "non-packed struct does not support backing integer type",
4991 .{},
4992 );
4993 const type_ref = try typeExpr(&block_scope, &namespace.base, backing_int_node);
4994 if (!block_scope.endsWithNoReturn()) {
4995 _ = try block_scope.addBreak(.break_inline, decl_inst, type_ref);
4996 }
4997 const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
4998 block_scope.instructions.items.len = block_scope.instructions_top;
4999 break :len body_len;
5000 } else null;
5001
49965002 const old_hasher = astgen.src_hasher;
49975003 defer astgen.src_hasher = old_hasher;
49985004 astgen.src_hasher = .init(.{});
......@@ -5076,7 +5082,7 @@ fn structDeclInner(
50765082 .src_node = node,
50775083 .name_strat = name_strat,
50785084 .layout = layout,
5079 .backing_int_type = backing_int_type_ref,
5085 .backing_int_type_body_len = backing_int_type_body_len,
50805086 .decls_len = scan_result.decls_len,
50815087 .fields_len = scan_result.fields_len,
50825088 .any_field_aligns = scan_result.any_field_aligns,
......@@ -5220,11 +5226,6 @@ fn unionDeclInner(
52205226
52215227 astgen.advanceSourceCursorToNode(node);
52225228
5223 const arg_type_ref: Zir.Inst.Ref = ref: {
5224 const arg_node = opt_arg_node.unwrap() orelse break :ref .none;
5225 break :ref try typeExpr(gz, scope, arg_node);
5226 };
5227
52285229 const decl_inst = try gz.reserveInstructionIndex();
52295230
52305231 var namespace: Scope.Namespace = .{
......@@ -5262,6 +5263,17 @@ fn unionDeclInner(
52625263 const field_align_body_lens = try scratch.addOptionalSlice(scan_result.any_field_aligns, scan_result.fields_len);
52635264 const field_value_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, scan_result.fields_len);
52645265
5266 // Before any field bodies comes the tag/backing type, if specified.
5267 const arg_type_body_len: ?u32 = if (opt_arg_node.unwrap()) |arg_node| len: {
5268 const type_ref = try typeExpr(&block_scope, &namespace.base, arg_node);
5269 if (!block_scope.endsWithNoReturn()) {
5270 _ = try block_scope.addBreak(.break_inline, decl_inst, type_ref);
5271 }
5272 const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
5273 block_scope.instructions.items.len = block_scope.instructions_top;
5274 break :len body_len;
5275 } else null;
5276
52655277 const old_hasher = astgen.src_hasher;
52665278 defer astgen.src_hasher = old_hasher;
52675279 astgen.src_hasher = .init(.{});
......@@ -5358,7 +5370,7 @@ fn unionDeclInner(
53585370 .@"extern" => .@"extern",
53595371 .@"packed" => if (opt_arg_node != .none) .packed_explicit else .@"packed",
53605372 },
5361 .arg_type = arg_type_ref,
5373 .arg_type_body_len = arg_type_body_len,
53625374 .decls_len = scan_result.decls_len,
53635375 .fields_len = scan_result.fields_len,
53645376 .any_field_aligns = scan_result.any_field_aligns,
......@@ -5420,11 +5432,6 @@ fn containerDecl(
54205432
54215433 astgen.advanceSourceCursorToNode(node);
54225434
5423 const tag_type_ref: Zir.Inst.Ref = ref: {
5424 const arg_node = container_decl.ast.arg.unwrap() orelse break :ref .none;
5425 break :ref try typeExpr(gz, scope, arg_node);
5426 };
5427
54285435 const decl_inst = try gz.reserveInstructionIndex();
54295436
54305437 var namespace: Scope.Namespace = .{
......@@ -5461,6 +5468,17 @@ fn containerDecl(
54615468 const field_names = try scratch.addSlice(fields_len);
54625469 const field_value_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, fields_len);
54635470
5471 // Before any field bodies comes the tag type, if specified.
5472 const tag_type_body_len: ?u32 = if (container_decl.ast.arg.unwrap()) |tag_type_node| len: {
5473 const type_ref = try typeExpr(&block_scope, &namespace.base, tag_type_node);
5474 if (!block_scope.endsWithNoReturn()) {
5475 _ = try block_scope.addBreak(.break_inline, decl_inst, type_ref);
5476 }
5477 const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
5478 block_scope.instructions.items.len = block_scope.instructions_top;
5479 break :len body_len;
5480 } else null;
5481
54645482 const old_hasher = astgen.src_hasher;
54655483 defer astgen.src_hasher = old_hasher;
54665484 astgen.src_hasher = .init(.{});
......@@ -5508,7 +5526,7 @@ fn containerDecl(
55085526 field_names.get(astgen)[field_idx] = @intFromEnum(try astgen.identAsString(member.ast.main_token));
55095527
55105528 if (member.ast.value_expr.unwrap()) |value_node| {
5511 if (tag_type_ref == .none) {
5529 if (tag_type_body_len == null) {
55125530 return astgen.failNodeNotes(node, "explicitly valued enum missing integer tag type", .{}, &.{
55135531 try astgen.errNoteNode(value_node, "tag value specified here", .{}),
55145532 });
......@@ -5535,7 +5553,7 @@ fn containerDecl(
55355553 try gz.setEnum(decl_inst, .{
55365554 .src_node = node,
55375555 .name_strat = name_strat,
5538 .tag_type = tag_type_ref,
5556 .tag_type_body_len = tag_type_body_len,
55395557 .nonexhaustive = scan_result.has_underscore_field,
55405558 .decls_len = scan_result.decls_len,
55415559 .fields_len = fields_len,
......@@ -12406,7 +12424,7 @@ const GenZir = struct {
1240612424 src_node: Ast.Node.Index,
1240712425 name_strat: Zir.Inst.NameStrategy,
1240812426 layout: std.builtin.Type.ContainerLayout,
12409 backing_int_type: Zir.Inst.Ref,
12427 backing_int_type_body_len: ?u32,
1241012428 decls_len: u32,
1241112429 fields_len: u32,
1241212430 any_field_aligns: bool,
......@@ -12430,7 +12448,7 @@ const GenZir = struct {
1243012448 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);
1243112449
1243212450 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len +
12433 4 + // `captures_len`, `decls_len`, `fields_len`, `backing_int_type`
12451 4 + // `captures_len`, `decls_len`, `fields_len`, `backing_int_type_body_len`
1243412452 captures_len * 2 + // `capture`, `capture_name`
1243512453 args.remaining.len);
1243612454
......@@ -12446,7 +12464,7 @@ const GenZir = struct {
1244612464 if (captures_len != 0) astgen.extra.appendAssumeCapacity(captures_len);
1244712465 if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len);
1244812466 if (args.fields_len != 0) astgen.extra.appendAssumeCapacity(args.fields_len);
12449 if (args.backing_int_type != .none) astgen.extra.appendAssumeCapacity(@intFromEnum(args.backing_int_type));
12467 if (args.backing_int_type_body_len) |n| astgen.extra.appendAssumeCapacity(n);
1245012468 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures));
1245112469 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names));
1245212470 astgen.extra.appendSliceAssumeCapacity(args.remaining);
......@@ -12461,7 +12479,7 @@ const GenZir = struct {
1246112479 .has_fields_len = args.fields_len != 0,
1246212480 .name_strategy = args.name_strat,
1246312481 .layout = args.layout,
12464 .has_backing_int_type = args.backing_int_type != .none,
12482 .has_backing_int_type = args.backing_int_type_body_len != null,
1246512483 .any_field_aligns = args.any_field_aligns,
1246612484 .any_field_defaults = args.any_field_defaults,
1246712485 .any_comptime_fields = args.any_comptime_fields,
......@@ -12475,7 +12493,7 @@ const GenZir = struct {
1247512493 src_node: Ast.Node.Index,
1247612494 name_strat: Zir.Inst.NameStrategy,
1247712495 kind: Zir.Inst.UnionDecl.Kind,
12478 arg_type: Zir.Inst.Ref,
12496 arg_type_body_len: ?u32,
1247912497 decls_len: u32,
1248012498 fields_len: u32,
1248112499 any_field_aligns: bool,
......@@ -12497,7 +12515,7 @@ const GenZir = struct {
1249712515 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);
1249812516
1249912517 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.UnionDecl).@"struct".fields.len +
12500 4 + // `captures_len`, `decls_len`, `fields_len`, `backing_int_type`
12518 4 + // `captures_len`, `decls_len`, `fields_len`, `arg_type_body_len`
1250112519 captures_len * 2 + // `capture`, `capture_name`
1250212520 args.remaining.len);
1250312521
......@@ -12514,10 +12532,9 @@ const GenZir = struct {
1251412532 if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len);
1251512533 if (args.fields_len != 0) astgen.extra.appendAssumeCapacity(args.fields_len);
1251612534 if (args.kind.hasArgType()) {
12517 assert(args.arg_type != .none);
12518 astgen.extra.appendAssumeCapacity(@intFromEnum(args.arg_type));
12535 astgen.extra.appendAssumeCapacity(args.arg_type_body_len.?);
1251912536 } else {
12520 assert(args.arg_type == .none);
12537 assert(args.arg_type_body_len == null);
1252112538 }
1252212539 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures));
1252312540 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names));
......@@ -12525,28 +12542,26 @@ const GenZir = struct {
1252512542
1252612543 astgen.instructions.set(@intFromEnum(inst), .{
1252712544 .tag = .extended,
12528 .data = .{
12529 .extended = .{
12530 .opcode = .union_decl,
12531 .small = @bitCast(Zir.Inst.UnionDecl.Small{
12532 .has_captures_len = captures_len != 0,
12533 .has_decls_len = args.decls_len != 0,
12534 .has_fields_len = args.fields_len != 0,
12535 .name_strategy = args.name_strat,
12536 .kind = args.kind,
12537 .any_field_aligns = args.any_field_aligns,
12538 .any_field_values = args.any_field_values,
12539 }),
12540 .operand = payload_index,
12541 },
12542 },
12545 .data = .{ .extended = .{
12546 .opcode = .union_decl,
12547 .small = @bitCast(Zir.Inst.UnionDecl.Small{
12548 .has_captures_len = captures_len != 0,
12549 .has_decls_len = args.decls_len != 0,
12550 .has_fields_len = args.fields_len != 0,
12551 .name_strategy = args.name_strat,
12552 .kind = args.kind,
12553 .any_field_aligns = args.any_field_aligns,
12554 .any_field_values = args.any_field_values,
12555 }),
12556 .operand = payload_index,
12557 } },
1254312558 });
1254412559 }
1254512560
1254612561 fn setEnum(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
1254712562 src_node: Ast.Node.Index,
1254812563 name_strat: Zir.Inst.NameStrategy,
12549 tag_type: Zir.Inst.Ref,
12564 tag_type_body_len: ?u32,
1255012565 nonexhaustive: bool,
1255112566 decls_len: u32,
1255212567 fields_len: u32,
......@@ -12568,7 +12583,7 @@ const GenZir = struct {
1256812583 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);
1256912584
1257012585 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.EnumDecl).@"struct".fields.len +
12571 4 + // `captures_len`, `decls_len`, `fields_len`, `tag_type`
12586 4 + // `captures_len`, `decls_len`, `fields_len`, `tag_type_body_len`
1257212587 captures_len * 2 + // `capture`, `capture_name`
1257312588 args.remaining.len);
1257412589
......@@ -12584,7 +12599,7 @@ const GenZir = struct {
1258412599 if (captures_len != 0) astgen.extra.appendAssumeCapacity(captures_len);
1258512600 if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len);
1258612601 if (args.fields_len != 0) astgen.extra.appendAssumeCapacity(args.fields_len);
12587 if (args.tag_type != .none) astgen.extra.appendAssumeCapacity(@intFromEnum(args.tag_type));
12602 if (args.tag_type_body_len) |n| astgen.extra.appendAssumeCapacity(n);
1258812603 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures));
1258912604 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names));
1259012605 astgen.extra.appendSliceAssumeCapacity(args.remaining);
......@@ -12598,7 +12613,7 @@ const GenZir = struct {
1259812613 .has_decls_len = args.decls_len != 0,
1259912614 .has_fields_len = args.fields_len != 0,
1260012615 .name_strategy = args.name_strat,
12601 .has_tag_type = args.tag_type != .none,
12616 .has_tag_type = args.tag_type_body_len != null,
1260212617 .nonexhaustive = args.nonexhaustive,
1260312618 .any_field_values = args.any_field_values,
1260412619 }),
lib/std/zig/Zir.zig+42-36
......@@ -3465,7 +3465,7 @@ pub const Inst = struct {
34653465 /// 0. captures_len: u32 // if `has_captures_len`
34663466 /// 1. decls_len: u32, // if `has_decls_len`
34673467 /// 2. fields_len: u32, // if `has_fields_len`
3468 /// 3. backing_int_type: Ref // if `has_backing_int`
3468 /// 3. backing_int_body_len: u32 // if `has_backing_int`
34693469 /// 4. capture: Capture // for every `captures_len`
34703470 /// 5. capture_name: NullTerminatedString // for every `captures_len`
34713471 /// 6. decl: Index, // for every `decls_len`; points to a `declaration` instruction
......@@ -3475,7 +3475,8 @@ pub const Inst = struct {
34753475 /// 10. field_default_body_len: u32 // for every `fields_len` if `any_field_defaults`
34763476 /// 11. field_comptime_bits: u32 // one bit per `fields_len` if `any_comptime_fields`
34773477 /// // LSB is first field, minimum number of `u32` needed
3478 /// 12. body_inst: Inst.Index // type body, then align body, then default body, for each field
3478 /// 12. backing_int_body_inst: Inst.Index // for each `backing_int_body_len`
3479 /// 13. body_inst: Inst.Index // type body, then align body, then default body, for each field
34793480 pub const StructDecl = struct {
34803481 // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.
34813482 // This hash contains the source of all fields, and any specified attributes (`extern`, backing type, etc).
......@@ -3622,13 +3623,14 @@ pub const Inst = struct {
36223623 /// 0. captures_len: u32, // if has_captures_len
36233624 /// 1. decls_len: u32, // if has_decls_len
36243625 /// 2. fields_len: u32, // if has_fields_len
3625 /// 3. tag_type: Ref, // if has_tag_type
3626 /// 3. tag_type_body_len: u32, // if has_tag_type
36263627 /// 4. capture: Capture // for every `captures_len`
36273628 /// 5. capture_name: NullTerminatedString // for every `captures_len`
36283629 /// 6. decl: Index, // for every `decls_len`; points to a `declaration` instruction
36293630 /// 7. field_name: NullTerminatedString // for every `fields_len`
36303631 /// 8. field_value_body_len: u32 // for every `fields_len` if `any_field_values`
3631 /// 9. body_inst: Inst.Index // value body for each field
3632 /// 9. tag_type_body_inst: Inst.Index // for each `tag_type_body_len`
3633 /// 10. body_inst: Inst.Index // value body for each field
36323634 pub const EnumDecl = struct {
36333635 // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.
36343636 // This hash contains the source of all fields, and the backing type if specified.
......@@ -3656,7 +3658,7 @@ pub const Inst = struct {
36563658 /// 0. captures_len: u32 // if `has_captures_len`
36573659 /// 1. decls_len: u32, // if `has_decls_len`
36583660 /// 2. fields_len: u32, // if `has_fields_len`
3659 /// 3. arg_type: Ref, // if `kind.hasArgType()`
3661 /// 3. arg_type_body_len: u32, // if `kind.hasArgType()`
36603662 /// 4. capture: Capture // for every `captures_len`
36613663 /// 5. capture_name: NullTerminatedString // for every `captures_len`
36623664 /// 6. decl: Index, // for every `decls_len`; points to a `declaration` instruction
......@@ -3664,7 +3666,8 @@ pub const Inst = struct {
36643666 /// 8. field_type_body_len: u32 // for every `fields_len`
36653667 /// 9 . field_align_body_len: u32 // for every `fields_len` if `any_field_aligns`
36663668 /// 10. field_value_body_len: u32 // for every `fields_len` if `any_field_values`
3667 /// 11. body_inst: Inst.Index // type body, then align body, then value body, for each field
3669 /// 11. arg_type_body_inst: Inst.Index // for each `arg_type_body_len`
3670 /// 12. body_inst: Inst.Index // type body, then align body, then value body, for each field
36683671 pub const UnionDecl = struct {
36693672 // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.
36703673 // This hash contains the source of all fields, and any specified attributes (`extern` etc).
......@@ -5235,18 +5238,6 @@ pub fn assertTrackable(zir: Zir, inst_idx: Zir.Inst.Index) void {
52355238 }
52365239}
52375240
5238/// MLUGG TODO: maybe delete these two?
5239pub fn typeCapturesLen(zir: Zir, type_decl: Inst.Index) u32 {
5240 const inst = zir.instructions.get(@intFromEnum(type_decl));
5241 assert(inst.tag == .extended);
5242 return switch (inst.data.extended.opcode) {
5243 .struct_decl => @intCast(zir.getStructDecl(type_decl).captures.len),
5244 .union_decl => @intCast(zir.getUnionDecl(type_decl).captures.len),
5245 .enum_decl => @intCast(zir.getEnumDecl(type_decl).captures.len),
5246 .opaque_decl => @intCast(zir.getOpaqueDecl(type_decl).captures.len),
5247 else => unreachable,
5248 };
5249}
52505241pub fn typeDecls(zir: Zir, type_decl: Inst.Index) []const Zir.Inst.Index {
52515242 const inst = zir.instructions.get(@intFromEnum(type_decl));
52525243 assert(inst.tag == .extended);
......@@ -5281,11 +5272,11 @@ pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDe
52815272 extra_index += 1;
52825273 break :blk fields_len;
52835274 } else 0;
5284 const backing_int_type: Inst.Ref = if (small.has_backing_int_type) ty: {
5285 const ty = zir.extra[extra_index];
5275 const backing_int_type_body_len: u32 = if (small.has_backing_int_type) len: {
5276 const body_len = zir.extra[extra_index];
52865277 extra_index += 1;
5287 break :ty @enumFromInt(ty);
5288 } else .none;
5278 break :len body_len;
5279 } else 0;
52895280 const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]);
52905281 extra_index += captures_len;
52915282 const capture_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..captures_len]);
......@@ -5312,6 +5303,11 @@ pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDe
53125303 extra_index += bits_len;
53135304 break :bits bits;
53145305 } else null;
5306 const backing_int_type_body: ?[]const Zir.Inst.Index = switch (backing_int_type_body_len) {
5307 0 => null,
5308 else => |n| zir.bodySlice(extra_index, n),
5309 };
5310 extra_index += backing_int_type_body_len;
53155311 const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]);
53165312 return .{
53175313 .src_line = extra.data.src_line,
......@@ -5321,7 +5317,7 @@ pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDe
53215317 .capture_names = capture_names,
53225318 .decls = decls,
53235319 .layout = small.layout,
5324 .backing_int_type = backing_int_type,
5320 .backing_int_type_body = backing_int_type_body,
53255321 .field_names = field_names,
53265322 .field_type_body_lens = field_type_body_lens,
53275323 .field_align_body_lens = field_align_body_lens,
......@@ -5341,7 +5337,7 @@ pub const UnwrappedStructDecl = struct {
53415337 decls: []const Inst.Index,
53425338
53435339 layout: std.builtin.Type.ContainerLayout,
5344 backing_int_type: Inst.Ref,
5340 backing_int_type_body: ?[]const Inst.Index,
53455341
53465342 field_names: []const NullTerminatedString,
53475343 field_type_body_lens: []const u32,
......@@ -5427,11 +5423,11 @@ pub fn getUnionDecl(zir: *const Zir, union_decl: Inst.Index) UnwrappedUnionDecl
54275423 extra_index += 1;
54285424 break :blk fields_len;
54295425 } else 0;
5430 const arg_type: Inst.Ref = if (small.kind.hasArgType()) ty: {
5431 const ty = zir.extra[extra_index];
5426 const arg_type_body_len: u32 = if (small.kind.hasArgType()) len: {
5427 const body_len = zir.extra[extra_index];
54325428 extra_index += 1;
5433 break :ty @enumFromInt(ty);
5434 } else .none;
5429 break :len body_len;
5430 } else 0;
54355431 const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]);
54365432 extra_index += captures_len;
54375433 const capture_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..captures_len]);
......@@ -5452,6 +5448,11 @@ pub fn getUnionDecl(zir: *const Zir, union_decl: Inst.Index) UnwrappedUnionDecl
54525448 extra_index += fields_len;
54535449 break :lens @ptrCast(lens);
54545450 } else null;
5451 const arg_type_body: ?[]const Zir.Inst.Index = switch (arg_type_body_len) {
5452 0 => null,
5453 else => |n| zir.bodySlice(extra_index, n),
5454 };
5455 extra_index += arg_type_body_len;
54555456 const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]);
54565457 return .{
54575458 .src_line = extra.data.src_line,
......@@ -5461,7 +5462,7 @@ pub fn getUnionDecl(zir: *const Zir, union_decl: Inst.Index) UnwrappedUnionDecl
54615462 .capture_names = capture_names,
54625463 .decls = decls,
54635464 .kind = small.kind,
5464 .arg_type = arg_type,
5465 .arg_type_body = arg_type_body,
54655466 .field_names = field_names,
54665467 .field_type_body_lens = field_type_body_lens,
54675468 .field_align_body_lens = field_align_body_lens,
......@@ -5480,7 +5481,7 @@ pub const UnwrappedUnionDecl = struct {
54805481 decls: []const Inst.Index,
54815482
54825483 kind: Inst.UnionDecl.Kind,
5483 arg_type: Inst.Ref,
5484 arg_type_body: ?[]const Inst.Index,
54845485
54855486 field_names: []const NullTerminatedString,
54865487 field_type_body_lens: []const u32,
......@@ -5556,11 +5557,11 @@ pub fn getEnumDecl(zir: *const Zir, enum_decl: Inst.Index) UnwrappedEnumDecl {
55565557 extra_index += 1;
55575558 break :blk fields_len;
55585559 } else 0;
5559 const tag_type: Inst.Ref = if (small.has_tag_type) ty: {
5560 const ty = zir.extra[extra_index];
5560 const tag_type_body_len: u32 = if (small.has_tag_type) len: {
5561 const body_len = zir.extra[extra_index];
55615562 extra_index += 1;
5562 break :ty @enumFromInt(ty);
5563 } else .none;
5563 break :len body_len;
5564 } else 0;
55645565 const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]);
55655566 extra_index += captures_len;
55665567 const capture_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..captures_len]);
......@@ -5574,6 +5575,11 @@ pub fn getEnumDecl(zir: *const Zir, enum_decl: Inst.Index) UnwrappedEnumDecl {
55745575 extra_index += fields_len;
55755576 break :lens @ptrCast(lens);
55765577 } else null;
5578 const tag_type_body: ?[]const Zir.Inst.Index = switch (tag_type_body_len) {
5579 0 => null,
5580 else => |n| zir.bodySlice(extra_index, n),
5581 };
5582 extra_index += tag_type_body_len;
55775583 const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]);
55785584 return .{
55795585 .src_line = extra.data.src_line,
......@@ -5582,7 +5588,7 @@ pub fn getEnumDecl(zir: *const Zir, enum_decl: Inst.Index) UnwrappedEnumDecl {
55825588 .captures = captures,
55835589 .capture_names = capture_names,
55845590 .decls = decls,
5585 .tag_type = tag_type,
5591 .tag_type_body = tag_type_body,
55865592 .nonexhaustive = small.nonexhaustive,
55875593 .field_names = field_names,
55885594 .field_value_body_lens = field_value_body_lens,
......@@ -5599,7 +5605,7 @@ pub const UnwrappedEnumDecl = struct {
55995605
56005606 decls: []const Inst.Index,
56015607
5602 tag_type: Inst.Ref,
5608 tag_type_body: ?[]const Inst.Index,
56035609 nonexhaustive: bool,
56045610
56055611 field_names: []const NullTerminatedString,
src/Compilation.zig+6-6
......@@ -3713,7 +3713,7 @@ const Header = extern struct {
37133713 nav_val_deps_len: u32,
37143714 nav_ty_deps_len: u32,
37153715 type_layout_deps_len: u32,
3716 type_inits_deps_len: u32,
3716 struct_defaults_deps_len: u32,
37173717 func_ies_deps_len: u32,
37183718 zon_file_deps_len: u32,
37193719 embed_file_deps_len: u32,
......@@ -3763,7 +3763,7 @@ pub fn saveState(comp: *Compilation) !void {
37633763 .nav_val_deps_len = @intCast(ip.nav_val_deps.count()),
37643764 .nav_ty_deps_len = @intCast(ip.nav_ty_deps.count()),
37653765 .type_layout_deps_len = @intCast(ip.type_layout_deps.count()),
3766 .type_inits_deps_len = @intCast(ip.type_inits_deps.count()),
3766 .struct_defaults_deps_len = @intCast(ip.struct_defaults_deps.count()),
37673767 .func_ies_deps_len = @intCast(ip.func_ies_deps.count()),
37683768 .zon_file_deps_len = @intCast(ip.zon_file_deps.count()),
37693769 .embed_file_deps_len = @intCast(ip.embed_file_deps.count()),
......@@ -3800,8 +3800,8 @@ pub fn saveState(comp: *Compilation) !void {
38003800 addBuf(&bufs, @ptrCast(ip.nav_ty_deps.values()));
38013801 addBuf(&bufs, @ptrCast(ip.type_layout_deps.keys()));
38023802 addBuf(&bufs, @ptrCast(ip.type_layout_deps.values()));
3803 addBuf(&bufs, @ptrCast(ip.type_inits_deps.keys()));
3804 addBuf(&bufs, @ptrCast(ip.type_inits_deps.values()));
3803 addBuf(&bufs, @ptrCast(ip.struct_defaults_deps.keys()));
3804 addBuf(&bufs, @ptrCast(ip.struct_defaults_deps.values()));
38053805 addBuf(&bufs, @ptrCast(ip.func_ies_deps.keys()));
38063806 addBuf(&bufs, @ptrCast(ip.func_ies_deps.values()));
38073807 addBuf(&bufs, @ptrCast(ip.zon_file_deps.keys()));
......@@ -4481,7 +4481,7 @@ pub fn addModuleErrorMsg(
44814481 const root_name: ?[]const u8 = switch (ref.referencer.unwrap()) {
44824482 .@"comptime" => "comptime",
44834483 .nav_val, .nav_ty => |nav| ip.getNav(nav).name.toSlice(ip),
4484 .type_layout, .type_inits => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
4484 .type_layout, .struct_defaults => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
44854485 .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),
44864486 .memoized_state => null,
44874487 };
......@@ -5251,7 +5251,7 @@ fn processOneJob(tid: Zcu.PerThread.Id, comp: *Compilation, job: Job) JobError!v
52515251 .nav_ty => |nav| pt.ensureNavTypeUpToDate(nav),
52525252 .nav_val => |nav| pt.ensureNavValUpToDate(nav),
52535253 .type_layout => |ty| pt.ensureTypeLayoutUpToDate(.fromInterned(ty)),
5254 .type_inits => |ty| pt.ensureTypeInitsUpToDate(.fromInterned(ty)),
5254 .struct_defaults => |ty| pt.ensureStructDefaultsUpToDate(.fromInterned(ty)),
52555255 .memoized_state => |stage| pt.ensureMemoizedStateUpToDate(stage),
52565256 .func => |func| pt.ensureFuncBodyUpToDate(func),
52575257 };
src/IncrementalDebugServer.zig+3-3
......@@ -307,7 +307,7 @@ fn handleCommand(zcu: *Zcu, w: *Io.Writer, cmd_str: []const u8, arg_str: []const
307307 switch (dependee) {
308308 .src_hash, .namespace, .namespace_name, .zon_file, .embed_file => try w.print("{f}", .{zcu.fmtDependee(dependee)}),
309309 .nav_val, .nav_ty => |nav| try w.print("{t} {d}", .{ dependee, @intFromEnum(nav) }),
310 .type_layout, .type_inits, .func_ies => |ip_index| try w.print("{t} {d}", .{ dependee, @intFromEnum(ip_index) }),
310 .type_layout, .struct_defaults, .func_ies => |ip_index| try w.print("{t} {d}", .{ dependee, @intFromEnum(ip_index) }),
311311 .memoized_state => |stage| try w.print("memoized_state {s}", .{@tagName(stage)}),
312312 }
313313 try w.writeByte('\n');
......@@ -374,8 +374,8 @@ fn parseAnalUnit(str: []const u8) ?AnalUnit {
374374 return .wrap(.{ .nav_ty = @enumFromInt(parseIndex(idx_str) orelse return null) });
375375 } else if (std.mem.eql(u8, kind, "type_layout")) {
376376 return .wrap(.{ .type_layout = @enumFromInt(parseIndex(idx_str) orelse return null) });
377 } else if (std.mem.eql(u8, kind, "type_inits")) {
378 return .wrap(.{ .type_inits = @enumFromInt(parseIndex(idx_str) orelse return null) });
377 } else if (std.mem.eql(u8, kind, "struct_defaults")) {
378 return .wrap(.{ .struct_defaults = @enumFromInt(parseIndex(idx_str) orelse return null) });
379379 } else if (std.mem.eql(u8, kind, "func")) {
380380 return .wrap(.{ .func = @enumFromInt(parseIndex(idx_str) orelse return null) });
381381 } else if (std.mem.eql(u8, kind, "memoized_state")) {
src/InternPool.zig+865-425
......@@ -50,12 +50,12 @@ nav_ty_deps: std.AutoArrayHashMapUnmanaged(Nav.Index, DepEntry.Index),
5050/// Dependencies on a function's inferred error set. Key is the function body, not the IES.
5151/// Value is index into `dep_entries` of the first dependency on this function's IES.
5252func_ies_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index),
53/// Dependencies on the resolved layout of a `struct` or `union` type.
53/// Dependencies on the resolved layout of a `struct`, `union`, or `enum` type.
5454/// Value is index into `dep_entries` of the first dependency on this type's layout.
5555type_layout_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index),
56/// Dependencies on the resolved initializers of a `struct` or `enum` type.
56/// Dependencies on the resolved default field values of a `struct` type.
5757/// Value is index into `dep_entries` of the first dependency on this type's inits.
58type_inits_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index),
58struct_defaults_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index),
5959/// Dependencies on a ZON file. Triggered by `@import` of ZON.
6060/// Value is index into `dep_entries` of the first dependency on this ZON file.
6161zon_file_deps: std.AutoArrayHashMapUnmanaged(FileIndex, DepEntry.Index),
......@@ -110,7 +110,7 @@ pub const empty: InternPool = .{
110110 .nav_ty_deps = .empty,
111111 .func_ies_deps = .empty,
112112 .type_layout_deps = .empty,
113 .type_inits_deps = .empty,
113 .struct_defaults_deps = .empty,
114114 .zon_file_deps = .empty,
115115 .embed_file_deps = .empty,
116116 .namespace_deps = .empty,
......@@ -422,7 +422,7 @@ pub const AnalUnit = packed struct(u64) {
422422 nav_val,
423423 nav_ty,
424424 type_layout,
425 type_inits,
425 struct_defaults,
426426 func,
427427 memoized_state,
428428 };
......@@ -434,11 +434,10 @@ pub const AnalUnit = packed struct(u64) {
434434 nav_val: Nav.Index,
435435 /// This `AnalUnit` resolves the type of the given `Nav`.
436436 nav_ty: Nav.Index,
437 /// This `AnalUnit` resolves the layout of the given `struct` or `union` type.
437 /// This `AnalUnit` resolves the layout of the given `struct`, `union`, or `enum` type.
438438 type_layout: InternPool.Index,
439 /// This `AnalUnit` resolves the field inits of the given `struct` or `enum` type.
440 /// The type may be a union's auto-generated tag enum, if the union has explicit field values.
441 type_inits: InternPool.Index,
439 /// This `AnalUnit` resolves the default field values of the given `struct` type.
440 struct_defaults: InternPool.Index,
442441 /// This `AnalUnit` analyzes the body of the given runtime function.
443442 func: InternPool.Index,
444443 /// This `AnalUnit` resolves all state which is memoized in fields on `Zcu`.
......@@ -852,7 +851,7 @@ pub const Dependee = union(enum) {
852851 /// Index is the function, not its IES.
853852 func_ies: Index,
854853 type_layout: Index,
855 type_inits: Index,
854 struct_defaults: Index,
856855 zon_file: FileIndex,
857856 embed_file: Zcu.EmbedFile.Index,
858857 namespace: TrackedInst.Index,
......@@ -906,7 +905,7 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI
906905 .nav_ty => |x| ip.nav_ty_deps.get(x),
907906 .func_ies => |x| ip.func_ies_deps.get(x),
908907 .type_layout => |x| ip.type_layout_deps.get(x),
909 .type_inits => |x| ip.type_inits_deps.get(x),
908 .struct_defaults => |x| ip.struct_defaults_deps.get(x),
910909 .zon_file => |x| ip.zon_file_deps.get(x),
911910 .embed_file => |x| ip.embed_file_deps.get(x),
912911 .namespace => |x| ip.namespace_deps.get(x),
......@@ -981,7 +980,7 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend
981980 .nav_ty => ip.nav_ty_deps,
982981 .func_ies => ip.func_ies_deps,
983982 .type_layout => ip.type_layout_deps,
984 .type_inits => ip.type_inits_deps,
983 .struct_defaults => ip.struct_defaults_deps,
985984 .zon_file => ip.zon_file_deps,
986985 .embed_file => ip.embed_file_deps,
987986 .namespace => ip.namespace_deps,
......@@ -2248,10 +2247,6 @@ pub const Key = union(enum) {
22482247 pub const Declared = struct {
22492248 /// A `struct_decl`, `union_decl`, `enum_decl`, or `opaque_decl` instruction.
22502249 zir_index: TrackedInst.Index,
2251 /// If the type declaration had an argument type (tag type or packed backing type), this
2252 /// is that type. Otherwise, this is `.none`. It is always `.none` for `opaque` types as
2253 /// `opaque(T)` does not exist.
2254 arg_ty: Index,
22552250 /// The captured values of this type. These values must be fully resolved per the language spec.
22562251 captures: union(enum) {
22572252 owned: CaptureValue.Slice,
......@@ -2745,7 +2740,6 @@ pub const Key = union(enum) {
27452740 switch (namespace_type) {
27462741 .declared => |declared| {
27472742 std.hash.autoHash(&hasher, declared.zir_index);
2748 std.hash.autoHash(&hasher, declared.arg_ty);
27492743 const captures = switch (declared.captures) {
27502744 .owned => |cvs| cvs.get(ip),
27512745 .external => |cvs| cvs,
......@@ -3155,7 +3149,6 @@ pub const Key = union(enum) {
31553149 .declared => |a_d| {
31563150 const b_d = b_info.declared;
31573151 if (a_d.zir_index != b_d.zir_index) return false;
3158 if (a_d.arg_ty != b_d.arg_ty) return false;
31593152 const a_captures = switch (a_d.captures) {
31603153 .owned => |s| s.get(ip),
31613154 .external => |cvs| cvs,
......@@ -3295,7 +3288,6 @@ pub const Key = union(enum) {
32953288 .void => .void_type,
32963289 .null => .null_type,
32973290 .false, .true => .bool_type,
3298 .empty_tuple => .empty_tuple_type,
32993291 .@"unreachable" => .noreturn_type,
33003292 },
33013293
......@@ -3308,6 +3300,7 @@ pub const LoadedStructType = struct {
33083300 /// Index of the `struct_decl` or `reify` ZIR instruction.
33093301 zir_index: TrackedInst.Index,
33103302 captures: CaptureValue.Slice,
3303 is_reified: bool,
33113304
33123305 // TODO: the non-fqn will be needed by the new dwarf structure
33133306 /// The name of this struct type.
......@@ -3319,10 +3312,9 @@ pub const LoadedStructType = struct {
33193312
33203313 layout: std.builtin.Type.ContainerLayout,
33213314 /// May be `undefined` if `layout != .@"packed"`.
3322 packed_backing_mode: PackedBackingMode,
3323 /// May be `undefined` if `layout != .@"packed",
3324 packed_backing_int_type: Index,
3315 packed_backing_mode: BackingTypeMode,
33253316
3317 // The remaining fields are only valid once the struct's layout is resolved.
33263318 field_name_map: MapIndex,
33273319 field_names: NullTerminatedString.Slice,
33283320 field_types: Index.Slice,
......@@ -3331,11 +3323,11 @@ pub const LoadedStructType = struct {
33313323 field_is_comptime_bits: ComptimeBits,
33323324 field_runtime_order: RuntimeOrder.Slice,
33333325 field_offsets: Offsets,
3334
3335 // These fields are only valid once the layout is resolved, and are never valid for `layout == .@"packed"`.
3326 packed_backing_int_type: Index,
33363327 has_no_possible_value: bool,
33373328 has_one_possible_value: bool,
33383329 comptime_only: bool,
3330 has_runtime_bits: bool,
33393331 size: u32,
33403332 alignment: Alignment,
33413333
......@@ -3478,6 +3470,7 @@ pub const LoadedUnionType = struct {
34783470 /// Index of the `union_decl` or `reify` ZIR instruction.
34793471 zir_index: TrackedInst.Index,
34803472 captures: CaptureValue.Slice,
3473 is_reified: bool,
34813474
34823475 // TODO: the non-fqn will be needed by the new dwarf structure
34833476 /// The name of this union type.
......@@ -3488,23 +3481,26 @@ pub const LoadedUnionType = struct {
34883481 namespace: NamespaceIndex,
34893482
34903483 layout: std.builtin.Type.ContainerLayout,
3491 runtime_tag: RuntimeTag,
3492 /// Even if `runtime_tag == .none`, this is populated with the union's "hypothetical" tag type.
3493 enum_tag_type: Index,
3484 enum_tag_mode: BackingTypeMode,
34943485 /// May be `undefined` if `layout != .@"packed"`.
3495 packed_backing_mode: PackedBackingMode,
3496 /// May be `undefined` if `layout != .@"packed",
3497 packed_backing_int_type: Index,
3486 packed_backing_mode: BackingTypeMode,
3487
3488 /// Only reified unions store field names; typically they should be loaded from `enum_tag_type`
3489 /// instead. Reified unions store them because type resolution needs them in order to validate
3490 /// or populate `enum_tag_type`.
3491 reified_field_names: NullTerminatedString.Slice,
34983492
3499 // Field names are not stored here, because fields are guaranteed to map one-to-one to the
3500 // fields of the enum tag type. If you need field names, load them from `enum_tag_type`.
3493 // The remaining fields are only valid once the union's layout is resolved.
35013494 field_types: Index.Slice,
35023495 field_aligns: Alignment.Slice,
3503
3504 // These fields are only valid once the layout is resolved, and are never valid for `layout == .@"packed"`.
3496 runtime_tag: RuntimeTag,
3497 /// Even if `runtime_tag == .none`, this is populated with the union's "hypothetical" tag type.
3498 enum_tag_type: Index,
3499 packed_backing_int_type: Index,
35053500 has_no_possible_value: bool,
35063501 has_one_possible_value: bool,
35073502 comptime_only: bool,
3503 has_runtime_bits: bool,
35083504 size: u32,
35093505 padding: u32,
35103506 alignment: Alignment,
......@@ -3523,6 +3519,7 @@ pub const LoadedEnumType = struct {
35233519 captures: CaptureValue.Slice,
35243520 /// If `zir_index` is `.none`, this is the union type for which this enum is the tag type.
35253521 owner_union: Index,
3522 is_reified: bool,
35263523
35273524 // TODO: the non-fqn will be needed by the new dwarf structure
35283525 /// The name of this enum type.
......@@ -3532,19 +3529,14 @@ pub const LoadedEnumType = struct {
35323529 name_nav: Nav.Index.Optional,
35333530 namespace: NamespaceIndex,
35343531
3535 /// An integer type which is used for the numerical value of the enum. Populated immediately, regardless
3536 /// of whether the integer tag type was explicitly provided or inferred by the compiler.
3537 int_tag_type: Index,
3538 int_tag_is_explicit: bool,
3532 int_tag_mode: BackingTypeMode,
35393533 nonexhaustive: bool,
35403534
3541 /// Uses `NullTerminatedString.Adapter` with `field_names`.
3535 // The remaining fields are only valid once the enum's layout is resolved.
3536 int_tag_type: Index,
35423537 field_name_map: MapIndex,
3543 /// If this is `.none`, the enum tag type is auto-generated and so the fields are auto-numbered.
3544 /// Otherwise, uses `Index.Adapter` with `field_values`.
3545 field_value_map: OptionalMapIndex,
35463538 field_names: NullTerminatedString.Slice,
3547 /// Empty if `field_value_map` is `.none`.
3539 field_value_map: OptionalMapIndex,
35483540 field_values: Index.Slice,
35493541
35503542 /// Look up field index based on field name.
......@@ -3596,7 +3588,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
35963588 const extra_items = extra_list.view().items(.@"0");
35973589 const item = unwrapped_index.getItem(ip);
35983590 // Exiting this `switch` means this is a `packed struct`.
3599 const backing_mode: PackedBackingMode, const any_defaults: bool = switch (item.tag) {
3591 const backing_mode: BackingTypeMode, const any_defaults: bool = switch (item.tag) {
36003592 .type_struct_packed_auto => .{ .auto, false },
36013593 .type_struct_packed_explicit => .{ .explicit, false },
36023594 .type_struct_packed_auto_defaults => .{ .auto, true },
......@@ -3667,6 +3659,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
36673659 return .{
36683660 .zir_index = extra.data.zir_index,
36693661 .captures = captures,
3662 .is_reified = extra.data.flags.any_captures == .reified,
36703663 .name = extra.data.name,
36713664 .name_nav = extra.data.name_nav,
36723665 .namespace = extra.data.namespace,
......@@ -3675,7 +3668,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
36753668 .@"extern" => .@"extern",
36763669 },
36773670 .packed_backing_mode = undefined,
3678 .packed_backing_int_type = undefined,
3671
36793672 .field_name_map = extra.data.field_name_map,
36803673 .field_names = field_names,
36813674 .field_types = field_types,
......@@ -3684,9 +3677,11 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
36843677 .field_is_comptime_bits = field_is_comptime_bits,
36853678 .field_runtime_order = field_runtime_order,
36863679 .field_offsets = field_offsets,
3680 .packed_backing_int_type = .none,
36873681 .has_no_possible_value = extra.data.flags.has_no_possible_value,
36883682 .has_one_possible_value = extra.data.flags.has_one_possible_value,
36893683 .comptime_only = extra.data.flags.comptime_only,
3684 .has_runtime_bits = extra.data.flags.has_runtime_bits,
36903685 .size = extra.data.size,
36913686 .alignment = extra.data.flags.alignment,
36923687 };
......@@ -3728,12 +3723,13 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
37283723 return .{
37293724 .zir_index = extra.data.zir_index,
37303725 .captures = captures,
3726 .is_reified = extra.data.captures_len == .reified,
37313727 .name = extra.data.name,
37323728 .name_nav = extra.data.name_nav,
37333729 .namespace = extra.data.namespace,
37343730 .layout = .@"packed",
37353731 .packed_backing_mode = backing_mode,
3736 .packed_backing_int_type = extra.data.backing_int_type,
3732
37373733 .field_name_map = extra.data.field_name_map,
37383734 .field_names = field_names,
37393735 .field_types = field_types,
......@@ -3742,9 +3738,11 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
37423738 .field_is_comptime_bits = .empty,
37433739 .field_runtime_order = .empty,
37443740 .field_offsets = .empty,
3741 .packed_backing_int_type = extra.data.backing_int_type,
37453742 .has_no_possible_value = undefined,
37463743 .has_one_possible_value = undefined,
37473744 .comptime_only = undefined,
3745 .has_runtime_bits = undefined,
37483746 .size = undefined,
37493747 .alignment = undefined,
37503748 };
......@@ -3756,7 +3754,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
37563754 const extra_items = extra_list.view().items(.@"0");
37573755 const item = unwrapped_index.getItem(ip);
37583756 // Exiting this `switch` means this is a `packed union`.
3759 const backing_mode: PackedBackingMode = switch (item.tag) {
3757 const backing_mode: BackingTypeMode = switch (item.tag) {
37603758 .type_union_packed_auto => .auto,
37613759 .type_union_packed_explicit => .explicit,
37623760 .type_union => {
......@@ -3779,6 +3777,12 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
37793777 },
37803778 };
37813779 extra_index += captures.len;
3780 const reified_field_names: NullTerminatedString.Slice = if (extra.data.flags.any_captures == .reified) .{
3781 .tid = unwrapped_index.tid,
3782 .start = extra_index,
3783 .len = extra.data.fields_len,
3784 } else .empty;
3785 extra_index += reified_field_names.len;
37823786 const field_types: Index.Slice = .{
37833787 .tid = unwrapped_index.tid,
37843788 .start = extra_index,
......@@ -3795,6 +3799,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
37953799 return .{
37963800 .zir_index = extra.data.zir_index,
37973801 .captures = captures,
3802 .is_reified = extra.data.flags.any_captures == .reified,
37983803 .name = extra.data.name,
37993804 .name_nav = extra.data.name_nav,
38003805 .namespace = extra.data.namespace,
......@@ -3803,14 +3808,17 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
38033808 .@"extern" => .@"extern",
38043809 },
38053810 .runtime_tag = extra.data.flags.runtime_tag,
3811 .enum_tag_mode = extra.data.flags.enum_tag_mode,
38063812 .enum_tag_type = extra.data.enum_tag_type,
38073813 .packed_backing_mode = undefined,
38083814 .packed_backing_int_type = undefined,
3815 .reified_field_names = reified_field_names,
38093816 .field_types = field_types,
38103817 .field_aligns = field_aligns,
38113818 .has_no_possible_value = extra.data.flags.has_no_possible_value,
38123819 .has_one_possible_value = extra.data.flags.has_one_possible_value,
38133820 .comptime_only = extra.data.flags.comptime_only,
3821 .has_runtime_bits = extra.data.flags.has_runtime_bits,
38143822 .size = extra.data.size,
38153823 .padding = extra.data.padding,
38163824 .alignment = extra.data.flags.alignment,
......@@ -3832,6 +3840,12 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
38323840 },
38333841 };
38343842 extra_index += captures.len;
3843 const reified_field_names: NullTerminatedString.Slice = if (extra.data.captures_len == .reified) .{
3844 .tid = unwrapped_index.tid,
3845 .start = extra_index,
3846 .len = extra.data.fields_len,
3847 } else .empty;
3848 extra_index += reified_field_names.len;
38353849 const field_types: Index.Slice = .{
38363850 .tid = unwrapped_index.tid,
38373851 .start = extra_index,
......@@ -3841,19 +3855,23 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
38413855 return .{
38423856 .zir_index = extra.data.zir_index,
38433857 .captures = captures,
3858 .is_reified = extra.data.captures_len == .reified,
38443859 .name = extra.data.name,
38453860 .name_nav = extra.data.name_nav,
38463861 .namespace = extra.data.namespace,
38473862 .layout = .@"packed",
38483863 .runtime_tag = .none,
3864 .enum_tag_mode = .auto,
38493865 .enum_tag_type = extra.data.enum_tag_type,
38503866 .packed_backing_mode = backing_mode,
38513867 .packed_backing_int_type = extra.data.backing_int_type,
3868 .reified_field_names = reified_field_names,
38523869 .field_types = field_types,
38533870 .field_aligns = .empty,
38543871 .has_no_possible_value = undefined,
38553872 .has_one_possible_value = undefined,
38563873 .comptime_only = undefined,
3874 .has_runtime_bits = undefined,
38573875 .size = undefined,
38583876 .padding = undefined,
38593877 .alignment = undefined,
......@@ -3917,12 +3935,13 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType {
39173935 return .{
39183936 .zir_index = zir_index,
39193937 .captures = captures,
3938 .is_reified = extra.data.captures_len == .reified,
39203939 .owner_union = owner_union,
39213940 .name = extra.data.name,
39223941 .name_nav = extra.data.name_nav,
39233942 .namespace = extra.data.namespace,
39243943 .int_tag_type = extra.data.int_tag_type,
3925 .int_tag_is_explicit = explicit_int_tag,
3944 .int_tag_mode = if (explicit_int_tag) .explicit else .auto,
39263945 .nonexhaustive = nonexhaustive,
39273946 .field_name_map = extra.data.field_name_map,
39283947 .field_value_map = field_value_map,
......@@ -4160,7 +4179,7 @@ pub const Index = enum(u32) {
41604179 };
41614180
41624181 /// Used for a map of `Index` values to the index within a list of `Index` values.
4163 pub const Adapter = struct {
4182 const Adapter = struct {
41644183 indexes: []const Index,
41654184
41664185 pub fn eql(ctx: @This(), a: Index, b_void: void, b_map_index: usize) bool {
......@@ -4365,7 +4384,7 @@ pub const Index = enum(u32) {
43654384 }) void {
43664385 _ = self;
43674386 const map_fields = @typeInfo(@typeInfo(@TypeOf(tag_to_encoding_map)).pointer.child).@"struct".fields;
4368 @setEvalBranchQuota(2_000);
4387 @setEvalBranchQuota(3_000);
43694388 inline for (@typeInfo(Tag).@"enum".fields, 0..) |tag, start| {
43704389 inline for (0..map_fields.len) |offset| {
43714390 if (comptime std.mem.eql(u8, tag.name, map_fields[(start + offset) % map_fields.len].name)) break;
......@@ -4797,7 +4816,11 @@ pub const static_keys: [static_len]Key = .{
47974816 .{ .simple_value = .null },
47984817 .{ .simple_value = .true },
47994818 .{ .simple_value = .false },
4800 .{ .simple_value = .empty_tuple },
4819
4820 .{ .aggregate = .{
4821 .ty = .empty_tuple_type,
4822 .storage = .{ .elems = &.{} },
4823 } },
48014824};
48024825
48034826/// How many items in the InternPool are statically known.
......@@ -5601,10 +5624,12 @@ pub const Tag = enum(u8) {
56015624 has_no_possible_value: bool,
56025625 /// Whether the struct is comptime-only. Always `false` until layout resolved.
56035626 comptime_only: bool,
5627 /// Whether the struct has runtime bits. Always `false` until layout resolved.
5628 has_runtime_bits: bool,
56045629 /// Alignment of the whole struct. Always `.none` until layout resolved.
56055630 alignment: Alignment,
56065631
5607 _: u17 = 0,
5632 _: u16 = 0,
56085633 };
56095634 };
56105635
......@@ -5625,21 +5650,25 @@ pub const Tag = enum(u8) {
56255650 name_nav: Nav.Index.Optional,
56265651 namespace: NamespaceIndex,
56275652
5628 /// The corresponding `PackedBackingMode` depends on the item's `Tag`.
5653 /// The corresponding `BackingTypeMode` depends on the item's `Tag`.
56295654 backing_int_type: Index,
56305655
56315656 fields_len: u32,
56325657 field_name_map: MapIndex,
56335658 };
56345659
5635 /// Field names are intentionally omitted---they are available in `enum_tag_type`.
5660 /// For declared unions, field names are intentionally omitted because they are available in
5661 /// `enum_tag_type`. However, reified unions do store field names, because they are needed by
5662 /// type resolution to create or validate the enum tag type (type resolution for declared unions
5663 /// instead fetches field names from ZIR).
56365664 ///
56375665 /// Trailing:
56385666 /// 0. type_hash: PackedU64 // if `any_captures == .reified`
56395667 /// 1. captures_len: u32 // if `any_captures == .true`
56405668 /// 2. capture: CaptureValue // if `any_captures == .true`; for each `captures_len`
5641 /// 3. field_type: Index // for each `fields_len`
5642 /// 4. field_align: Alignment // for each `fields_len` if `any_field_aligns`
5669 /// 3. reified_field_name: NullTerminatedString // if `any_captures == .reified`; for each `fields_len`
5670 /// 4. field_type: Index // for each `fields_len`
5671 /// 5. field_align: Alignment // for each `fields_len` if `any_field_aligns`
56435672 pub const TypeUnion = struct {
56445673 zir_index: TrackedInst.Index,
56455674
......@@ -5652,7 +5681,6 @@ pub const Tag = enum(u8) {
56525681 /// This could be provided through the tag type, but it is more convenient
56535682 /// to store it directly. This is also necessary for `dumpStatsFallible` to
56545683 /// work on unresolved types.
5655 /// MLUGG TODO: reconsider, because we resolve the tag type eagerly now.
56565684 fields_len: u32,
56575685
56585686 /// Always 0 until layout resolved.
......@@ -5669,7 +5697,7 @@ pub const Tag = enum(u8) {
56695697 ///
56705698 /// For `union(enum(E))` syntax, this is `false`, but the generated enum tag type is
56715699 /// considered to have an explicitly specified integer tag type.
5672 explicit_tag_type: bool,
5700 enum_tag_mode: BackingTypeMode,
56735701
56745702 /// `packed` layout is represented separately by `TypeStructPacked`.
56755703 layout: enum(u1) { auto, @"extern" },
......@@ -5685,19 +5713,25 @@ pub const Tag = enum(u8) {
56855713 has_no_possible_value: bool,
56865714 /// Whether the union is comptime-only. Always `false` until layout resolved.
56875715 comptime_only: bool,
5716 /// Whether the union has runtime bits. Always `false` until layout resolved.
5717 has_runtime_bits: bool,
56885718 /// Alignment of the whole union. Always `.none` until layout resolved.
56895719 alignment: Alignment,
56905720
5691 _: u16 = 0,
5721 _: u15 = 0,
56925722 };
56935723 };
56945724
5695 /// Field names are intentionally omitted---they are available in `enum_tag_type`.
5725 /// For declared unions, field names are intentionally omitted because they are available in
5726 /// `enum_tag_type`. However, reified unions do store field names, because they are needed by
5727 /// type resolution to create or validate the enum tag type (type resolution for declared unions
5728 /// instead fetches field names from ZIR).
56965729 ///
56975730 /// Trailing:
56985731 /// 0. type_hash: PackedU64 // if `captures_len == .reified`
56995732 /// 1. capture: CaptureValue // if `captures_len != .reified`; for each `captures_len`
5700 /// 2. field_type: Index // for each `fields_len`
5733 /// 2. reified_field_name: NullTerminatedString // if `captures_len == .reified`; for each `fields_len`
5734 /// 3. field_type: Index // for each `fields_len`
57015735 pub const TypeUnionPacked = struct {
57025736 zir_index: TrackedInst.Index,
57035737 captures_len: enum(u32) {
......@@ -5709,7 +5743,7 @@ pub const Tag = enum(u8) {
57095743 name_nav: Nav.Index.Optional,
57105744 namespace: NamespaceIndex,
57115745
5712 /// The corresponding `PackedBackingMode` depends on the item's `Tag`.
5746 /// The corresponding `BackingTypeMode` depends on the item's `Tag`.
57135747 backing_int_type: Index,
57145748 /// Although packed unions do not semantically have a tag type, the compiler still assigns
57155749 /// them a "hypothetical" tag type.
......@@ -5718,7 +5752,6 @@ pub const Tag = enum(u8) {
57185752 /// This could be provided through the tag type, but it is more convenient
57195753 /// to store it directly. This is also necessary for `dumpStatsFallible` to
57205754 /// work on unresolved types.
5721 /// MLUGG TODO: reconsider, because we resolve the tag type eagerly now.
57225755 fields_len: u32,
57235756 };
57245757
......@@ -5742,8 +5775,7 @@ pub const Tag = enum(u8) {
57425775 namespace: NamespaceIndex,
57435776
57445777 /// An integer type which is used for the numerical value of the enum. Whether this was
5745 /// user-provided or inferred by the compiler depends on the tag. Either way, the field
5746 /// is populated immediately (i.e. does not require any type resolution).
5778 /// user-provided or inferred by the compiler depends on the tag.
57475779 int_tag_type: Index,
57485780
57495781 fields_len: u32,
......@@ -5762,13 +5794,17 @@ pub const Tag = enum(u8) {
57625794 };
57635795};
57645796
5765/// Differentiates between user-provided and compiler-generated backing types for packed aggregates.
5766pub const PackedBackingMode = enum(u1) {
5767 /// The backing type was explicitly provided by the user, i.e. `packed struct(T)` or `packed union(T)`.
5768 /// Type resolution simply *validates* that type.
5797/// Differentiates between user-provided and compiler-generated backing types for packed and tagged types.
5798pub const BackingTypeMode = enum(u1) {
5799 /// The backing type was explicitly provided by the user. For instance:
5800 /// union(T)
5801 /// enum(T)
5802 /// packed struct(T)
5803 /// packed union(T)
5804 /// Type layout resolution will evaluate the user-provided expression and validate that type.
57695805 explicit,
5770 /// No backing type was explicitly provided by the user. Type layout resolution will populate the
5771 /// backing type based on the field types; before then it is invalid (probably `.none`).
5806 /// No backing type was explicitly provided by the user. Type layout resolution will populate
5807 /// an inferred/generated type.
57725808 auto,
57735809};
57745810
......@@ -5852,8 +5888,6 @@ pub const SimpleValue = enum(u32) {
58525888 void = @intFromEnum(Index.void_value),
58535889 /// This is untyped `null`.
58545890 null = @intFromEnum(Index.null_value),
5855 /// This is the untyped empty struct/array literal: `.{}`
5856 empty_tuple = @intFromEnum(Index.empty_tuple),
58575891 true = @intFromEnum(Index.bool_true),
58585892 false = @intFromEnum(Index.bool_false),
58595893 @"unreachable" = @intFromEnum(Index.unreachable_value),
......@@ -6395,7 +6429,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator, io: Io) void {
63956429 ip.nav_ty_deps.deinit(gpa);
63966430 ip.func_ies_deps.deinit(gpa);
63976431 ip.type_layout_deps.deinit(gpa);
6398 ip.type_inits_deps.deinit(gpa);
6432 ip.struct_defaults_deps.deinit(gpa);
63996433 ip.zon_file_deps.deinit(gpa);
64006434 ip.embed_file_deps.deinit(gpa);
64016435 ip.namespace_deps.deinit(gpa);
......@@ -6544,12 +6578,10 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
65446578 } },
65456579 .false => .{ .declared = .{
65466580 .zir_index = extra.data.zir_index,
6547 .arg_ty = .none,
65486581 .captures = .{ .owned = .empty },
65496582 } },
65506583 .true => .{ .declared = .{
65516584 .zir_index = extra.data.zir_index,
6552 .arg_ty = .none,
65536585 .captures = .{ .owned = .{
65546586 .tid = unwrapped_index.tid,
65556587 .start = extra.end + 1,
......@@ -6572,11 +6604,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
65726604 } },
65736605 _ => .{ .declared = .{
65746606 .zir_index = extra.data.zir_index,
6575 .arg_ty = switch (item.tag) {
6576 .type_struct_packed_auto, .type_struct_packed_auto_defaults => .none,
6577 .type_struct_packed_explicit, .type_struct_packed_explicit_defaults => extra.data.backing_int_type,
6578 else => unreachable,
6579 },
65806607 .captures = .{ .owned = .{
65816608 .tid = unwrapped_index.tid,
65826609 .start = extra.end,
......@@ -6595,12 +6622,10 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
65956622 } },
65966623 .false => .{ .declared = .{
65976624 .zir_index = extra.data.zir_index,
6598 .arg_ty = if (extra.data.flags.explicit_tag_type) extra.data.enum_tag_type else .none,
65996625 .captures = .{ .owned = .empty },
66006626 } },
66016627 .true => .{ .declared = .{
66026628 .zir_index = extra.data.zir_index,
6603 .arg_ty = if (extra.data.flags.explicit_tag_type) extra.data.enum_tag_type else .none,
66046629 .captures = .{ .owned = .{
66056630 .tid = unwrapped_index.tid,
66066631 .start = extra.end + 1,
......@@ -6619,11 +6644,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
66196644 } },
66206645 _ => .{ .declared = .{
66216646 .zir_index = extra.data.zir_index,
6622 .arg_ty = switch (item.tag) {
6623 .type_union_packed_auto => .none,
6624 .type_union_packed_explicit => extra.data.backing_int_type,
6625 else => unreachable,
6626 },
66276647 .captures = .{ .owned = .{
66286648 .tid = unwrapped_index.tid,
66296649 .start = extra.end,
......@@ -6645,11 +6665,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
66456665 } },
66466666 _ => .{ .declared = .{
66476667 .zir_index = @enumFromInt(extra_list.view().items(.@"0")[extra.end]),
6648 .arg_ty = switch (item.tag) {
6649 .type_enum_auto => .none,
6650 .type_enum_explicit, .type_enum_nonexhaustive => extra.data.int_tag_type,
6651 else => unreachable,
6652 },
66536668 .captures = .{ .owned = .{
66546669 .tid = unwrapped_index.tid,
66556670 .start = extra.end + 1,
......@@ -6662,7 +6677,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
66626677 const extra = extraDataTrail(unwrapped_index.getExtra(ip), Tag.TypeOpaque, data);
66636678 break :ns .{ .declared = .{
66646679 .zir_index = extra.data.zir_index,
6665 .arg_ty = .none,
66666680 .captures = .{ .owned = .{
66676681 .tid = unwrapped_index.tid,
66686682 .start = extra.end,
......@@ -6883,7 +6897,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
68836897 },
68846898 .type_array_small,
68856899 .type_vector,
6886 // MLUGG TODO: is this still possible? also, i hate .only_possible_value, it should die in a fire.
68876900 .type_struct_packed_auto,
68886901 .type_struct_packed_explicit,
68896902 => .{ .aggregate = .{
......@@ -6894,7 +6907,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
68946907 // There is only one possible value precisely due to the
68956908 // fact that this values slice is fully populated!
68966909 .type_struct,
6897 // MLUGG TODO: is this still possible? also, i hate .only_possible_value, it should die in a fire.
68986910 .type_struct_packed_auto_defaults,
68996911 .type_struct_packed_explicit_defaults,
69006912 => {
......@@ -7445,12 +7457,12 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
74457457 });
74467458 },
74477459
7448 .struct_type => unreachable, // use getStructType() instead
7449 .tuple_type => unreachable, // use getTupleType() instead
7450 .union_type => unreachable, // use getUnionType() instead
7451 .opaque_type => unreachable, // use getOpaqueType() instead
7460 .struct_type => unreachable, // instead use: getDeclaredStructType, getReifiedStructType
7461 .union_type => unreachable, // instead use: getDeclaredUnionType, getReifiedUnionType
7462 .enum_type => unreachable, // instead use: getDeclaredEnumType, getReifiedEnumType, getGeneratedEnumTagType
7463 .opaque_type => unreachable, // instead use: getDeclaredOpaqueType
74527464
7453 .enum_type => unreachable, // use getEnumType() instead
7465 .tuple_type => unreachable, // use getTupleType() instead
74547466 .func_type => unreachable, // use getFuncType() instead
74557467 .@"extern" => unreachable, // use getExtern() instead
74567468 .func => unreachable, // use getFuncInstance() or getFuncDecl() instead
......@@ -8072,43 +8084,180 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
80728084 return gop.put();
80738085}
80748086
8075pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct {
8087pub fn getDeclaredStructType(
8088 ip: *InternPool,
8089 gpa: Allocator,
8090 io: Io,
8091 tid: Zcu.PerThread.Id,
8092 ini: struct {
8093 zir_index: TrackedInst.Index,
8094 captures: []const CaptureValue,
8095
8096 // If the value of any of the following fields would change on an incremental update, then logic
8097 // in `Zcu.mapOldZirToNew` must detect that (these properties are all trivially known from ZIR)
8098 // and refuse to map the type declaration. This causes `zir_index` to change so that a new type
8099 // will be interned at a fresh index.
8100 //
8101 // In the future, it would be good to remove all of those fields from `ini`, and in fact just
8102 // have a single function `getDeclaredContainer` which is suitable for all container types.
8103 // However, this requires some major changes to how container types are represented in the
8104 // InternPool, so that it is possible for their backing storage to be "reallocated" as needed
8105 // during type resolution.
8106 fields_len: u32,
8107 layout: std.builtin.Type.ContainerLayout,
8108 any_comptime_fields: bool,
8109 any_field_defaults: bool,
8110 any_field_aligns: bool,
8111 packed_backing_mode: BackingTypeMode,
8112 },
8113) Allocator.Error!WipContainerType.Result {
8114 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .struct_type = .{ .declared = .{
8115 .zir_index = ini.zir_index,
8116 .captures = .{ .external = ini.captures },
8117 } } });
8118 defer gop.deinit();
8119 if (gop == .existing) return .{ .existing = gop.existing };
8120
8121 const local = ip.getLocal(tid);
8122 const items = local.getMutableItems(gpa, io);
8123 const extra = local.getMutableExtra(gpa, io);
8124 try items.ensureUnusedCapacity(1);
8125
8126 const field_name_map = try ip.addMap(gpa, io, tid, ini.fields_len);
8127 errdefer local.mutate.maps.len -= 1;
8128
8129 const is_extern = switch (ini.layout) {
8130 .auto => false,
8131 .@"extern" => true,
8132 .@"packed" => {
8133 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStructPacked).@"struct".fields.len +
8134 ini.captures.len + // capture
8135 ini.fields_len + // field_name
8136 ini.fields_len + // field_type
8137 (if (ini.any_field_defaults) ini.fields_len else 0)); // field_default
8138
8139 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStructPacked{
8140 .zir_index = ini.zir_index,
8141 .captures_len = @enumFromInt(ini.captures.len),
8142 .name = undefined, // set by `finish`
8143 .name_nav = undefined, // set by `finish`
8144 .namespace = undefined, // set by `finish`
8145 .backing_int_type = .none,
8146 .fields_len = ini.fields_len,
8147 .field_name_map = field_name_map,
8148 });
8149 extra.appendSliceAssumeCapacity(.{@ptrCast(ini.captures)}); // capture
8150 extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name
8151 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type
8152 if (ini.any_field_defaults) {
8153 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_default
8154 }
8155 items.appendAssumeCapacity(.{
8156 .tag = switch (ini.packed_backing_mode) {
8157 .auto => if (ini.any_field_defaults) .type_struct_packed_auto_defaults else .type_struct_packed_auto,
8158 .explicit => if (ini.any_field_defaults) .type_struct_packed_explicit_defaults else .type_struct_packed_explicit,
8159 },
8160 .data = extra_index,
8161 });
8162 return .{ .wip = .{
8163 .index = gop.put(),
8164 .tid = tid,
8165 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?,
8166 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name_nav").?,
8167 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?,
8168 .field_names = undefined,
8169 .field_types = undefined,
8170 .field_values = undefined,
8171 .field_aligns = undefined,
8172 .field_is_comptime_bits = undefined,
8173 } };
8174 },
8175 };
8176
8177 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStruct).@"struct".fields.len +
8178 1 + // captures_len
8179 ini.captures.len + // capture
8180 ini.fields_len + // field_name
8181 ini.fields_len + // field_type
8182 (if (ini.any_field_defaults) ini.fields_len else 0) + // field_default
8183 (if (ini.any_field_aligns) (ini.fields_len + 3) / 4 else 0) + // field_align
8184 (if (ini.any_comptime_fields) (ini.fields_len + 31) / 32 else 0) + // field_is_comptime_bits
8185 (if (!is_extern) ini.fields_len else 0) + // field_runtime_order
8186 ini.fields_len); // field_offset
8187
8188 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStruct{
8189 .zir_index = ini.zir_index,
8190 .name = undefined, // set by `finish`
8191 .name_nav = undefined, // set by `finish`
8192 .namespace = undefined, // set by `finish`
8193 .fields_len = ini.fields_len,
8194 .field_name_map = field_name_map,
8195 .size = 0,
8196 .flags = .{
8197 .any_captures = if (ini.captures.len != 0) .true else .false,
8198 .layout = if (is_extern) .@"extern" else .auto,
8199 .any_comptime_fields = ini.any_comptime_fields,
8200 .any_field_defaults = ini.any_field_defaults,
8201 .any_field_aligns = ini.any_field_aligns,
8202 .has_one_possible_value = false,
8203 .has_no_possible_value = false,
8204 .comptime_only = false,
8205 .has_runtime_bits = false,
8206 .alignment = .none,
8207 },
8208 });
8209 if (ini.captures.len != 0) {
8210 extra.appendAssumeCapacity(.{@intCast(ini.captures.len)}); // captures_len
8211 extra.appendSliceAssumeCapacity(.{@ptrCast(ini.captures)}); // capture
8212 }
8213 extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name
8214 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type
8215 if (ini.any_field_defaults) {
8216 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_default
8217 }
8218 if (ini.any_field_aligns) {
8219 extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 3) / 4); // field_align
8220 }
8221 if (ini.any_comptime_fields) {
8222 extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 31) / 32); // field_is_comptime_bits
8223 }
8224 if (!is_extern) {
8225 extra.appendNTimesAssumeCapacity(.{@intFromEnum(LoadedStructType.RuntimeOrder.unresolved)}, ini.fields_len); // field_runtime_order
8226 }
8227 extra.appendNTimesAssumeCapacity(.{0}, ini.fields_len); // field_offset
8228 items.appendAssumeCapacity(.{
8229 .tag = .type_struct,
8230 .data = extra_index,
8231 });
8232 return .{ .wip = .{
8233 .index = gop.put(),
8234 .tid = tid,
8235 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name").?,
8236 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name_nav").?,
8237 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?,
8238 .field_names = undefined,
8239 .field_types = undefined,
8240 .field_values = undefined,
8241 .field_aligns = undefined,
8242 .field_is_comptime_bits = undefined,
8243 } };
8244}
8245
8246pub fn getReifiedStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct {
8247 zir_index: TrackedInst.Index,
8248 type_hash: u64,
80768249 fields_len: u32,
80778250 layout: std.builtin.Type.ContainerLayout,
8078 /// The following only applies if `layout == .@"packed"`; this field is ignored otherwise.
8079 ///
8080 /// The explicitly specified backing integer type. `.none` means the backing integer is inferred
8081 /// by the compiler. Asserts that this is an integer type.
8082 explicit_packed_backing_type: Index,
80838251 any_comptime_fields: bool,
80848252 any_field_defaults: bool,
80858253 any_field_aligns: bool,
8086 key: union(enum) {
8087 declared: struct {
8088 zir_index: TrackedInst.Index,
8089 captures: []const CaptureValue,
8090 },
8091 reified: struct {
8092 zir_index: TrackedInst.Index,
8093 type_hash: u64,
8094 },
8095 },
8254 /// Explicitly specified backing int type. `.none` if not packed or if backing type is inferred.
8255 packed_backing_int_type: Index,
80968256}) Allocator.Error!WipContainerType.Result {
8097 const key: Key = .{ .struct_type = switch (ini.key) {
8098 .declared => |d| .{ .declared = .{
8099 .zir_index = d.zir_index,
8100 .arg_ty = switch (ini.layout) {
8101 .auto, .@"extern" => .none,
8102 .@"packed" => ini.explicit_packed_backing_type,
8103 },
8104 .captures = .{ .external = d.captures },
8105 } },
8106 .reified => |r| .{ .reified = .{
8107 .zir_index = r.zir_index,
8108 .type_hash = r.type_hash,
8109 } },
8110 } };
8111 var gop = try ip.getOrPutKey(gpa, io, tid, key);
8257 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .struct_type = .{ .reified = .{
8258 .zir_index = ini.zir_index,
8259 .type_hash = ini.type_hash,
8260 } } });
81128261 defer gop.deinit();
81138262 if (gop == .existing) return .{ .existing = gop.existing };
81148263
......@@ -8120,46 +8269,37 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread
81208269 const field_name_map = try ip.addMap(gpa, io, tid, ini.fields_len);
81218270 errdefer local.mutate.maps.len -= 1;
81228271
8123 const zir_index, const type_hash_captures_extra_len = switch (ini.key) {
8124 .declared => |d| .{ d.zir_index, d.captures.len + @intFromBool(ini.layout != .@"packed") },
8125 .reified => |r| .{ r.zir_index, 2 },
8126 };
8127
81288272 const is_extern = switch (ini.layout) {
81298273 .auto => false,
81308274 .@"extern" => true,
81318275 .@"packed" => {
81328276 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStructPacked).@"struct".fields.len +
8133 type_hash_captures_extra_len +
8277 2 + // type_hash
81348278 ini.fields_len + // field_name
81358279 ini.fields_len + // field_type
81368280 (if (ini.any_field_defaults) ini.fields_len else 0)); // field_default
81378281
81388282 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStructPacked{
8139 .zir_index = zir_index,
8140 .captures_len = switch (ini.key) {
8141 .declared => |d| @enumFromInt(d.captures.len),
8142 .reified => .reified,
8143 },
8283 .zir_index = ini.zir_index,
8284 .captures_len = .reified,
81448285 .name = undefined, // set by `finish`
81458286 .name_nav = undefined, // set by `finish`
81468287 .namespace = undefined, // set by `finish`
8147 .backing_int_type = ini.explicit_packed_backing_type,
8288 .backing_int_type = ini.packed_backing_int_type,
81488289 .fields_len = ini.fields_len,
81498290 .field_name_map = field_name_map,
81508291 });
8151 switch (ini.key) {
8152 .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}),
8153 .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)),
8154 }
8292 _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); // type_hash
81558293 const field_names_start = extra.mutate.len;
81568294 extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name
8295 const field_types_start = extra.mutate.len;
81578296 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type
8297 const field_defaults_start = extra.mutate.len;
81588298 if (ini.any_field_defaults) {
81598299 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_default
81608300 }
81618301 items.appendAssumeCapacity(.{
8162 .tag = switch (ini.explicit_packed_backing_type) {
8302 .tag = switch (ini.packed_backing_int_type) {
81638303 .none => if (ini.any_field_defaults) .type_struct_packed_auto_defaults else .type_struct_packed_auto,
81648304 else => if (ini.any_field_defaults) .type_struct_packed_explicit_defaults else .type_struct_packed_explicit,
81658305 },
......@@ -8171,17 +8311,20 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread
81718311 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?,
81728312 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name_nav").?,
81738313 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?,
8174 .tag_type_index = null,
8175 .fields_len = ini.fields_len,
8176 .field_name_map = field_name_map,
8177 .field_names_start = field_names_start,
8178 .field_comptime_bits_start = null,
8314 .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len },
8315 .field_types = .{ .tid = tid, .start = field_types_start, .len = ini.fields_len },
8316 .field_values = if (ini.any_field_defaults)
8317 .{ .tid = tid, .start = field_defaults_start, .len = ini.fields_len }
8318 else
8319 undefined,
8320 .field_aligns = undefined,
8321 .field_is_comptime_bits = undefined,
81798322 } };
81808323 },
81818324 };
81828325
81838326 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStruct).@"struct".fields.len +
8184 type_hash_captures_extra_len +
8327 2 + // type_hash
81858328 ini.fields_len + // field_name
81868329 ini.fields_len + // field_type
81878330 (if (ini.any_field_defaults) ini.fields_len else 0) + // field_default
......@@ -8191,7 +8334,7 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread
81918334 ini.fields_len); // field_offset
81928335
81938336 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStruct{
8194 .zir_index = zir_index,
8337 .zir_index = ini.zir_index,
81958338 .name = undefined, // set by `finish`
81968339 .name_nav = undefined, // set by `finish`
81978340 .namespace = undefined, // set by `finish`
......@@ -8199,10 +8342,7 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread
81998342 .field_name_map = field_name_map,
82008343 .size = 0,
82018344 .flags = .{
8202 .any_captures = switch (ini.key) {
8203 .declared => |d| if (d.captures.len != 0) .true else .false,
8204 .reified => .reified,
8205 },
8345 .any_captures = .reified,
82068346 .layout = if (is_extern) .@"extern" else .auto,
82078347 .any_comptime_fields = ini.any_comptime_fields,
82088348 .any_field_defaults = ini.any_field_defaults,
......@@ -8210,30 +8350,27 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread
82108350 .has_one_possible_value = false,
82118351 .has_no_possible_value = false,
82128352 .comptime_only = false,
8353 .has_runtime_bits = false,
82138354 .alignment = .none,
82148355 },
82158356 });
8216 switch (ini.key) {
8217 .declared => |d| if (d.captures.len != 0) {
8218 extra.appendAssumeCapacity(.{@intCast(d.captures.len)});
8219 extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)});
8220 },
8221 .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)),
8222 }
8357 _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); // type_hash
82238358 const field_names_start = extra.mutate.len;
82248359 extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name
8360 const field_types_start = extra.mutate.len;
82258361 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type
8362 const field_defaults_start = extra.mutate.len;
82268363 if (ini.any_field_defaults) {
82278364 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_default
82288365 }
8366 const field_aligns_start = extra.mutate.len;
82298367 if (ini.any_field_aligns) {
82308368 extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 3) / 4); // field_align
82318369 }
8232 const field_comptime_bits_start: ?u32 = if (ini.any_comptime_fields) start: {
8233 const start = extra.mutate.len;
8370 const field_is_comptime_bits_start = extra.mutate.len;
8371 if (ini.any_comptime_fields) {
82348372 extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 31) / 32); // field_is_comptime_bits
8235 break :start start;
8236 } else null;
8373 }
82378374 if (!is_extern) {
82388375 extra.appendNTimesAssumeCapacity(.{@intFromEnum(LoadedStructType.RuntimeOrder.unresolved)}, ini.fields_len); // field_runtime_order
82398376 }
......@@ -8248,58 +8385,174 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread
82488385 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name").?,
82498386 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name_nav").?,
82508387 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?,
8251 .tag_type_index = null,
8388 .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len },
8389 .field_types = .{ .tid = tid, .start = field_types_start, .len = ini.fields_len },
8390 .field_values = if (ini.any_field_defaults)
8391 .{ .tid = tid, .start = field_defaults_start, .len = ini.fields_len }
8392 else
8393 undefined,
8394 .field_aligns = if (ini.any_field_aligns)
8395 .{ .tid = tid, .start = field_aligns_start, .len = ini.fields_len }
8396 else
8397 undefined,
8398 .field_is_comptime_bits = if (ini.any_comptime_fields)
8399 .{ .tid = tid, .start = field_is_comptime_bits_start, .len = (ini.fields_len + 31) / 32 }
8400 else
8401 undefined,
8402 } };
8403}
8404
8405pub fn getDeclaredUnionType(
8406 ip: *InternPool,
8407 gpa: Allocator,
8408 io: Io,
8409 tid: Zcu.PerThread.Id,
8410 ini: struct {
8411 zir_index: TrackedInst.Index,
8412 captures: []const CaptureValue,
8413
8414 // If the value of any of the following fields would change on an incremental update, then logic
8415 // in `Zcu.mapOldZirToNew` must detect that (these properties are all trivially known from ZIR)
8416 // and refuse to map the type declaration. This causes `zir_index` to change so that a new type
8417 // will be interned at a fresh index.
8418 //
8419 // In the future, it would be good to remove all of those fields from `ini`, and in fact just
8420 // have a single function `getDeclaredContainer` which is suitable for all container types.
8421 // However, this requires some major changes to how container types are represented in the
8422 // InternPool, so that it is possible for their backing storage to be "reallocated" as needed
8423 // during type resolution.
8424 fields_len: u32,
8425 layout: std.builtin.Type.ContainerLayout,
8426 any_field_aligns: bool,
8427 runtime_tag: LoadedUnionType.RuntimeTag,
8428 enum_tag_mode: BackingTypeMode,
8429 packed_backing_mode: BackingTypeMode,
8430 },
8431) Allocator.Error!WipContainerType.Result {
8432 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .union_type = .{ .declared = .{
8433 .zir_index = ini.zir_index,
8434 .captures = .{ .external = ini.captures },
8435 } } });
8436 defer gop.deinit();
8437 if (gop == .existing) return .{ .existing = gop.existing };
8438
8439 const local = ip.getLocal(tid);
8440 const items = local.getMutableItems(gpa, io);
8441 const extra = local.getMutableExtra(gpa, io);
8442 try items.ensureUnusedCapacity(1);
8443
8444 const is_extern = switch (ini.layout) {
8445 .auto => false,
8446 .@"extern" => true,
8447 .@"packed" => {
8448 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeUnionPacked).@"struct".fields.len +
8449 ini.captures.len + // capture
8450 ini.fields_len); // field_type
8451
8452 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnionPacked{
8453 .zir_index = ini.zir_index,
8454 .captures_len = @enumFromInt(ini.captures.len),
8455 .name = undefined, // set by `finish`
8456 .name_nav = undefined, // set by `finish`
8457 .namespace = undefined, // set by `finish`
8458 .backing_int_type = .none,
8459 .enum_tag_type = .none,
8460 .fields_len = ini.fields_len,
8461 });
8462 extra.appendSliceAssumeCapacity(.{@ptrCast(ini.captures)}); // capture
8463 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type
8464 items.appendAssumeCapacity(.{
8465 .tag = switch (ini.packed_backing_mode) {
8466 .auto => .type_union_packed_auto,
8467 .explicit => .type_union_packed_explicit,
8468 },
8469 .data = extra_index,
8470 });
8471 return .{ .wip = .{
8472 .index = gop.put(),
8473 .tid = tid,
8474 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name").?,
8475 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name_nav").?,
8476 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "namespace").?,
8477 .field_names = undefined,
8478 .field_types = undefined,
8479 .field_values = undefined,
8480 .field_aligns = undefined,
8481 .field_is_comptime_bits = undefined,
8482 } };
8483 },
8484 };
8485
8486 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeUnion).@"struct".fields.len +
8487 1 + // captures_len
8488 ini.captures.len + // capture
8489 ini.fields_len + // field_type
8490 (if (ini.any_field_aligns) (ini.fields_len + 3) / 4 else 0)); // field_align
8491
8492 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{
8493 .zir_index = ini.zir_index,
8494 .name = undefined, // set by `finish`
8495 .name_nav = undefined, // set by `finish`
8496 .namespace = undefined, // set by `finish`
8497 .enum_tag_type = .none,
82528498 .fields_len = ini.fields_len,
8253 .field_name_map = field_name_map,
8254 .field_names_start = field_names_start,
8255 .field_comptime_bits_start = field_comptime_bits_start,
8499 .size = 0,
8500 .padding = 0,
8501 .flags = .{
8502 .any_captures = if (ini.captures.len != 0) .true else .false,
8503 .enum_tag_mode = ini.enum_tag_mode,
8504 .layout = if (is_extern) .@"extern" else .auto,
8505 .any_field_aligns = ini.any_field_aligns,
8506 .runtime_tag = ini.runtime_tag,
8507 .has_one_possible_value = false,
8508 .has_no_possible_value = false,
8509 .comptime_only = false,
8510 .has_runtime_bits = false,
8511 .alignment = .none,
8512 },
8513 });
8514 if (ini.captures.len > 0) {
8515 extra.appendAssumeCapacity(.{@intCast(ini.captures.len)}); // captures_len
8516 extra.appendSliceAssumeCapacity(.{@ptrCast(ini.captures)}); // capture
8517 }
8518 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type
8519 if (ini.any_field_aligns) {
8520 extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 3) / 4); // field_align
8521 }
8522 items.appendAssumeCapacity(.{
8523 .tag = .type_union,
8524 .data = extra_index,
8525 });
8526 return .{ .wip = .{
8527 .index = gop.put(),
8528 .tid = tid,
8529 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?,
8530 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name_nav").?,
8531 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?,
8532 .field_names = undefined,
8533 .field_types = undefined,
8534 .field_values = undefined,
8535 .field_aligns = undefined,
8536 .field_is_comptime_bits = undefined,
82568537 } };
82578538}
82588539
8259pub fn getUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct {
8540pub fn getReifiedUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct {
8541 zir_index: TrackedInst.Index,
8542 type_hash: u64,
82608543 fields_len: u32,
82618544 layout: std.builtin.Type.ContainerLayout,
8262 /// The explicitly specified backing integer type for a `packed union`.
8263 /// `.none` means the backing integer is inferred by the compiler. If set,
8264 /// must be an integer type. If the union is not packed, must be `.none`.
8265 explicit_packed_backing_type: Index,
8266 runtime_tag: LoadedUnionType.RuntimeTag,
8267 /// `true` for `union(T)`, but `false` for anything else, including `union(enum(T))`.
8268 have_explicit_enum_tag: bool,
82698545 any_field_aligns: bool,
8270 key: union(enum) {
8271 declared: struct {
8272 zir_index: TrackedInst.Index,
8273 captures: []const CaptureValue,
8274 /// This is the `T` in one of the following:
8275 /// * `union(T)` (enum tag type)
8276 /// * `union(enum(T))` (int tag type)
8277 /// * `packed union(T)` (int backing type)
8278 /// Or `.none` otherwise.
8279 arg_ty: InternPool.Index,
8280 },
8281 reified: struct {
8282 zir_index: TrackedInst.Index,
8283 type_hash: u64,
8284 },
8285 },
8546 runtime_tag: LoadedUnionType.RuntimeTag,
8547 /// Explicitly specified enum tag type. `.none` if `runtime_tag != .tagged`.
8548 enum_tag_type: Index,
8549 /// Explicitly specified backing int type. `.none` if not packed or if backing type is inferred.
8550 packed_backing_int_type: Index,
82868551}) Allocator.Error!WipContainerType.Result {
8287 if (ini.explicit_packed_backing_type != .none) {
8288 assert(ip.zigTypeTag(ini.explicit_packed_backing_type) == .int);
8289 if (ini.key == .declared) assert(ini.key.declared.arg_ty == ini.explicit_packed_backing_type);
8290 }
8291 const key: Key = .{ .union_type = switch (ini.key) {
8292 .declared => |d| .{ .declared = .{
8293 .zir_index = d.zir_index,
8294 .arg_ty = d.arg_ty,
8295 .captures = .{ .external = d.captures },
8296 } },
8297 .reified => |r| .{ .reified = .{
8298 .zir_index = r.zir_index,
8299 .type_hash = r.type_hash,
8300 } },
8301 } };
8302 var gop = try ip.getOrPutKey(gpa, io, tid, key);
8552 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .union_type = .{ .reified = .{
8553 .zir_index = ini.zir_index,
8554 .type_hash = ini.type_hash,
8555 } } });
83038556 defer gop.deinit();
83048557 if (gop == .existing) return .{ .existing = gop.existing };
83058558
......@@ -8308,98 +8561,86 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.
83088561 const extra = local.getMutableExtra(gpa, io);
83098562 try items.ensureUnusedCapacity(1);
83108563
8311 const zir_index, const type_hash_captures_extra_len = switch (ini.key) {
8312 .declared => |d| .{ d.zir_index, d.captures.len + @intFromBool(ini.layout != .@"packed") },
8313 .reified => |r| .{ r.zir_index, 2 },
8314 };
8315
83168564 const is_extern = switch (ini.layout) {
83178565 .auto => false,
83188566 .@"extern" => true,
83198567 .@"packed" => {
83208568 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeUnionPacked).@"struct".fields.len +
8321 type_hash_captures_extra_len +
8569 2 + // type_hash
8570 ini.fields_len + // reified_field_name
83228571 ini.fields_len); // field_type
83238572
83248573 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnionPacked{
8325 .zir_index = zir_index,
8326 .captures_len = switch (ini.key) {
8327 .declared => |d| @enumFromInt(d.captures.len),
8328 .reified => .reified,
8329 },
8574 .zir_index = ini.zir_index,
8575 .captures_len = .reified,
83308576 .name = undefined, // set by `finish`
83318577 .name_nav = undefined, // set by `finish`
83328578 .namespace = undefined, // set by `finish`
8333 .backing_int_type = ini.explicit_packed_backing_type,
8334 .enum_tag_type = .none, // set by `setTagType`
8579 .backing_int_type = ini.packed_backing_int_type,
8580 .enum_tag_type = .none,
83358581 .fields_len = ini.fields_len,
83368582 });
8337 switch (ini.key) {
8338 .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}),
8339 .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)),
8340 }
8583 _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); // type_hash
8584 const field_names_start = extra.mutate.len;
8585 extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // reified_field_name
8586 const field_types_start = extra.mutate.len;
83418587 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type
83428588 items.appendAssumeCapacity(.{
8343 .tag = switch (ini.explicit_packed_backing_type) {
8589 .tag = switch (ini.packed_backing_int_type) {
83448590 .none => .type_union_packed_auto,
83458591 else => .type_union_packed_explicit,
83468592 },
83478593 .data = extra_index,
83488594 });
8349 return .{
8350 .wip = .{
8351 .index = gop.put(),
8352 .tid = tid,
8353 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name").?,
8354 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name_nav").?,
8355 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "namespace").?,
8356 .tag_type_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "enum_tag_type").?,
8357 .fields_len = 0, // the fields come from the enum, so nothing to set
8358 .field_name_map = undefined,
8359 .field_names_start = undefined,
8360 .field_comptime_bits_start = undefined,
8361 },
8362 };
8595 return .{ .wip = .{
8596 .index = gop.put(),
8597 .tid = tid,
8598 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name").?,
8599 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name_nav").?,
8600 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "namespace").?,
8601 .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len },
8602 .field_types = .{ .tid = tid, .start = field_types_start, .len = ini.fields_len },
8603 .field_values = undefined,
8604 .field_aligns = undefined,
8605 .field_is_comptime_bits = undefined,
8606 } };
83638607 },
83648608 };
83658609
83668610 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeUnion).@"struct".fields.len +
8367 type_hash_captures_extra_len +
8611 2 + // type_hash
8612 ini.fields_len + // reified_field_name
83688613 ini.fields_len + // field_type
83698614 (if (ini.any_field_aligns) (ini.fields_len + 3) / 4 else 0)); // field_align
83708615
83718616 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{
8372 .zir_index = zir_index,
8617 .zir_index = ini.zir_index,
83738618 .name = undefined, // set by `finish`
83748619 .name_nav = undefined, // set by `finish`
83758620 .namespace = undefined, // set by `finish`
8376 .enum_tag_type = .none, // set by `setTagType`
8621 .enum_tag_type = ini.enum_tag_type,
83778622 .fields_len = ini.fields_len,
83788623 .size = 0,
83798624 .padding = 0,
83808625 .flags = .{
8381 .any_captures = switch (ini.key) {
8382 .declared => |d| if (d.captures.len != 0) .true else .false,
8383 .reified => .reified,
8384 },
8385 .explicit_tag_type = ini.have_explicit_enum_tag,
8626 .any_captures = .reified,
8627 .enum_tag_mode = if (ini.enum_tag_type == .none) .auto else .explicit,
83868628 .layout = if (is_extern) .@"extern" else .auto,
83878629 .any_field_aligns = ini.any_field_aligns,
83888630 .runtime_tag = ini.runtime_tag,
83898631 .has_one_possible_value = false,
83908632 .has_no_possible_value = false,
83918633 .comptime_only = false,
8634 .has_runtime_bits = false,
83928635 .alignment = .none,
83938636 },
83948637 });
8395 switch (ini.key) {
8396 .declared => |d| if (d.captures.len != 0) {
8397 extra.appendAssumeCapacity(.{@intCast(d.captures.len)});
8398 extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)});
8399 },
8400 .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)),
8401 }
8638 _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash));
8639 const field_names_start = extra.mutate.len;
8640 extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // reified_field_name
8641 const field_types_start = extra.mutate.len;
84028642 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type
8643 const field_aligns_start = extra.mutate.len;
84038644 if (ini.any_field_aligns) {
84048645 extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 3) / 4); // field_align
84058646 }
......@@ -8407,53 +8648,124 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.
84078648 .tag = .type_union,
84088649 .data = extra_index,
84098650 });
8410 return .{
8411 .wip = .{
8412 .index = gop.put(),
8413 .tid = tid,
8414 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?,
8415 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name_nav").?,
8416 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?,
8417 .tag_type_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "enum_tag_type").?,
8418 .fields_len = 0, // the fields come from the enum, so nothing to set
8419 .field_name_map = undefined,
8420 .field_names_start = undefined,
8421 .field_comptime_bits_start = undefined,
8422 },
8423 };
8651 return .{ .wip = .{
8652 .index = gop.put(),
8653 .tid = tid,
8654 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?,
8655 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name_nav").?,
8656 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?,
8657 .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len },
8658 .field_types = .{ .tid = tid, .start = field_types_start, .len = ini.fields_len },
8659 .field_values = undefined,
8660 .field_aligns = if (ini.any_field_aligns)
8661 .{ .tid = tid, .start = field_aligns_start, .len = ini.fields_len }
8662 else
8663 undefined,
8664 .field_is_comptime_bits = undefined,
8665 } };
84248666}
84258667
8426pub fn getEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct {
8668pub fn getDeclaredEnumType(
8669 ip: *InternPool,
8670 gpa: Allocator,
8671 io: Io,
8672 tid: Zcu.PerThread.Id,
8673 ini: struct {
8674 zir_index: TrackedInst.Index,
8675 captures: []const CaptureValue,
8676
8677 // If the value of any of the following fields would change on an incremental update, then logic
8678 // in `Zcu.mapOldZirToNew` must detect that (these properties are all trivially known from ZIR)
8679 // and refuse to map the type declaration. This causes `zir_index` to change so that a new type
8680 // will be interned at a fresh index.
8681 //
8682 // In the future, it would be good to remove all of those fields from `ini`, and in fact just
8683 // have a single function `getDeclaredContainer` which is suitable for all container types.
8684 // However, this requires some major changes to how container types are represented in the
8685 // InternPool, so that it is possible for their backing storage to be "reallocated" as needed
8686 // during type resolution.
8687 fields_len: u32,
8688 nonexhaustive: bool,
8689 /// For `enum(T)` this is `.explicit`. Otherwise this is `.none`.
8690 int_tag_mode: BackingTypeMode,
8691 },
8692) Allocator.Error!WipContainerType.Result {
8693 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .enum_type = .{ .declared = .{
8694 .zir_index = ini.zir_index,
8695 .captures = .{ .external = ini.captures },
8696 } } });
8697 defer gop.deinit();
8698 if (gop == .existing) return .{ .existing = gop.existing };
8699
8700 const local = ip.getLocal(tid);
8701 const items = local.getMutableItems(gpa, io);
8702 const extra = local.getMutableExtra(gpa, io);
8703 try items.ensureUnusedCapacity(1);
8704
8705 const tag: Tag, const have_values: bool = if (ini.nonexhaustive)
8706 .{ .type_enum_nonexhaustive, true }
8707 else if (ini.int_tag_mode == .explicit)
8708 .{ .type_enum_explicit, true }
8709 else
8710 .{ .type_enum_auto, false };
8711
8712 const field_name_map = try ip.addMap(gpa, io, tid, ini.fields_len);
8713 errdefer local.mutate.maps.len -= 1;
8714
8715 const field_value_map = if (have_values) try ip.addMap(gpa, io, tid, ini.fields_len) else undefined;
8716 errdefer local.mutate.maps.len -= @intFromBool(have_values);
8717
8718 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeEnum).@"struct".fields.len +
8719 1 + // zir_index
8720 ini.captures.len + // capture
8721 @intFromBool(have_values) + // field_value_map
8722 ini.fields_len + // field_name
8723 (if (have_values) ini.fields_len else 0)); // field_value
8724
8725 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeEnum{
8726 .captures_len = @enumFromInt(ini.captures.len),
8727 .name = undefined, // set by `finish`
8728 .name_nav = undefined, // set by `finish`
8729 .namespace = undefined, // set by `finish`
8730 .int_tag_type = .none,
8731 .fields_len = ini.fields_len,
8732 .field_name_map = field_name_map,
8733 });
8734 extra.appendAssumeCapacity(.{@intFromEnum(ini.zir_index)}); // zir_index
8735 extra.appendSliceAssumeCapacity(.{@ptrCast(ini.captures)}); // capture
8736 if (have_values) extra.appendAssumeCapacity(.{@intFromEnum(field_value_map)}); // field_value_map
8737 extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name
8738 if (have_values) extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_value
8739 items.appendAssumeCapacity(.{
8740 .tag = tag,
8741 .data = extra_index,
8742 });
8743 return .{ .wip = .{
8744 .index = gop.put(),
8745 .tid = tid,
8746 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name").?,
8747 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name_nav").?,
8748 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "namespace").?,
8749 .field_names = undefined,
8750 .field_types = undefined,
8751 .field_values = undefined,
8752 .field_aligns = undefined,
8753 .field_is_comptime_bits = undefined,
8754 } };
8755}
8756
8757pub fn getReifiedEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct {
8758 zir_index: TrackedInst.Index,
8759 type_hash: u64,
84278760 fields_len: u32,
8428 /// For `enum(T)` or `union(enum(T))`, this is `T`. Asserts `T` is an integer type.
8429 /// Otherwise, `.none`.
8430 explicit_int_tag_type: Index,
84318761 nonexhaustive: bool,
8432 key: union(enum) {
8433 declared: struct {
8434 zir_index: TrackedInst.Index,
8435 captures: []const CaptureValue,
8436 },
8437 reified: struct {
8438 zir_index: TrackedInst.Index,
8439 type_hash: u64,
8440 },
8441 generated_union_tag: Index,
8442 },
8762 /// Explicitly specified int tag type, or `.none` if the int tag type is inferred.
8763 int_tag_type: Index,
84438764}) Allocator.Error!WipContainerType.Result {
8444 const key: Key = .{ .enum_type = switch (ini.key) {
8445 .declared => |d| .{ .declared = .{
8446 .zir_index = d.zir_index,
8447 .arg_ty = ini.explicit_int_tag_type,
8448 .captures = .{ .external = d.captures },
8449 } },
8450 .reified => |r| .{ .reified = .{
8451 .zir_index = r.zir_index,
8452 .type_hash = r.type_hash,
8453 } },
8454 .generated_union_tag => |u| .{ .generated_union_tag = u },
8455 } };
8456 var gop = try ip.getOrPutKey(gpa, io, tid, key);
8765 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .enum_type = .{ .reified = .{
8766 .zir_index = ini.zir_index,
8767 .type_hash = ini.type_hash,
8768 } } });
84578769 defer gop.deinit();
84588770 if (gop == .existing) return .{ .existing = gop.existing };
84598771
......@@ -8464,7 +8776,7 @@ pub fn getEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.I
84648776
84658777 const tag: Tag, const have_values: bool = if (ini.nonexhaustive)
84668778 .{ .type_enum_nonexhaustive, true }
8467 else if (ini.explicit_int_tag_type != .none)
8779 else if (ini.int_tag_type != .none)
84688780 .{ .type_enum_explicit, true }
84698781 else
84708782 .{ .type_enum_auto, false };
......@@ -8476,44 +8788,27 @@ pub fn getEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.I
84768788 errdefer local.mutate.maps.len -= @intFromBool(have_values);
84778789
84788790 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeEnum).@"struct".fields.len +
8479 switch (ini.key) {
8480 .declared => |d| 1 + d.captures.len, // `zir_index` and `capture`
8481 .reified => 3, // `zir_index` and `type_hash`
8482 .generated_union_tag => 1, // owner_union
8483 } +
8791 1 + // zir_index
8792 2 + // type_hash
84848793 @intFromBool(have_values) + // field_value_map
84858794 ini.fields_len + // field_name
84868795 (if (have_values) ini.fields_len else 0)); // field_value
84878796
84888797 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeEnum{
8489 .captures_len = switch (ini.key) {
8490 .declared => |d| @enumFromInt(d.captures.len),
8491 .reified => .reified,
8492 .generated_union_tag => .generated_union_tag,
8493 },
8798 .captures_len = .reified,
84948799 .name = undefined, // set by `finish`
84958800 .name_nav = undefined, // set by `finish`
84968801 .namespace = undefined, // set by `finish`
8497 .int_tag_type = ini.explicit_int_tag_type,
8802 .int_tag_type = ini.int_tag_type,
84988803 .fields_len = ini.fields_len,
84998804 .field_name_map = field_name_map,
85008805 });
8501 switch (ini.key) {
8502 .declared => |d| {
8503 extra.appendAssumeCapacity(.{@intFromEnum(d.zir_index)}); // zir_index
8504 extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}); // capture
8505 },
8506 .reified => |r| {
8507 extra.appendAssumeCapacity(.{@intFromEnum(r.zir_index)}); // zir_index
8508 _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)); // type_hash
8509 },
8510 .generated_union_tag => |owner_union| {
8511 extra.appendAssumeCapacity(.{@intFromEnum(owner_union)}); // owner_union
8512 },
8513 }
8514 if (have_values) extra.appendAssumeCapacity(.{@intFromEnum(field_value_map)});
8806 extra.appendAssumeCapacity(.{@intFromEnum(ini.zir_index)}); // zir_index
8807 _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); // type_hash
8808 if (have_values) extra.appendAssumeCapacity(.{@intFromEnum(field_value_map)}); // field_value_map
85158809 const field_names_start = extra.mutate.len;
85168810 extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name
8811 const field_values_start = extra.mutate.len;
85178812 if (have_values) extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_value
85188813 items.appendAssumeCapacity(.{
85198814 .tag = tag,
......@@ -8525,22 +8820,91 @@ pub fn getEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.I
85258820 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name").?,
85268821 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name_nav").?,
85278822 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "namespace").?,
8528 .tag_type_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "int_tag_type").?,
8823 .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len },
8824 .field_types = undefined,
8825 .field_values = if (have_values)
8826 .{ .tid = tid, .start = field_values_start, .len = ini.fields_len }
8827 else
8828 undefined,
8829 .field_aligns = undefined,
8830 .field_is_comptime_bits = undefined,
8831 } };
8832}
8833
8834pub fn getGeneratedEnumTagType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct {
8835 /// The union type for which this enum is a generated tag.
8836 union_type: Index,
8837 /// For `union(enum(T))` this is `.explicit`. Otherwise this is `.none`.
8838 int_tag_mode: BackingTypeMode,
8839 fields_len: u32,
8840}) Allocator.Error!WipContainerType.Result {
8841 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .enum_type = .{ .generated_union_tag = ini.union_type } });
8842 defer gop.deinit();
8843 if (gop == .existing) return .{ .existing = gop.existing };
8844
8845 const local = ip.getLocal(tid);
8846 const items = local.getMutableItems(gpa, io);
8847 const extra = local.getMutableExtra(gpa, io);
8848 try items.ensureUnusedCapacity(1);
8849
8850 const field_name_map = try ip.addMap(gpa, io, tid, ini.fields_len);
8851 errdefer local.mutate.maps.len -= 1;
8852
8853 const have_values = switch (ini.int_tag_mode) {
8854 .explicit => true,
8855 .auto => false,
8856 };
8857
8858 const field_value_map = if (have_values) try ip.addMap(gpa, io, tid, ini.fields_len) else undefined;
8859 errdefer local.mutate.maps.len -= @intFromBool(have_values);
8860
8861 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeEnum).@"struct".fields.len +
8862 1 + // owner_union
8863 @intFromBool(have_values) + // field_value_map
8864 ini.fields_len + // field_name
8865 (if (have_values) ini.fields_len else 0)); // field_value
8866
8867 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeEnum{
8868 .captures_len = .generated_union_tag,
8869 .name = undefined, // set by `finish`
8870 .name_nav = undefined, // set by `finish`
8871 .namespace = undefined, // set by `finish`
8872 .int_tag_type = .none,
85298873 .fields_len = ini.fields_len,
85308874 .field_name_map = field_name_map,
8531 .field_names_start = field_names_start,
8532 .field_comptime_bits_start = null,
8875 });
8876 extra.appendAssumeCapacity(.{@intFromEnum(ini.union_type)}); // owner_union
8877 if (have_values) extra.appendAssumeCapacity(.{@intFromEnum(field_value_map)});
8878 extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name
8879 if (have_values) extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_value
8880 items.appendAssumeCapacity(.{
8881 .tag = switch (ini.int_tag_mode) {
8882 .auto => .type_enum_auto,
8883 .explicit => .type_enum_explicit,
8884 },
8885 .data = extra_index,
8886 });
8887 return .{ .wip = .{
8888 .index = gop.put(),
8889 .tid = tid,
8890 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name").?,
8891 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name_nav").?,
8892 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "namespace").?,
8893 .field_names = undefined,
8894 .field_types = undefined,
8895 .field_values = undefined,
8896 .field_aligns = undefined,
8897 .field_is_comptime_bits = undefined,
85338898 } };
85348899}
85358900
8536pub fn getOpaqueType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct {
8901pub fn getDeclaredOpaqueType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct {
85378902 zir_index: TrackedInst.Index,
85388903 captures: []const CaptureValue,
85398904}) Allocator.Error!WipContainerType.Result {
85408905 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .opaque_type = .{ .declared = .{
85418906 .zir_index = ini.zir_index,
85428907 .captures = .{ .external = ini.captures },
8543 .arg_ty = .none,
85448908 } } });
85458909 defer gop.deinit();
85468910 if (gop == .existing) return .{ .existing = gop.existing };
......@@ -8569,11 +8933,11 @@ pub fn getOpaqueType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread
85698933 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name").?,
85708934 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name_nav").?,
85718935 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "namespace").?,
8572 .tag_type_index = null,
8573 .fields_len = 0,
8574 .field_name_map = undefined,
8575 .field_names_start = undefined,
8576 .field_comptime_bits_start = undefined,
8936 .field_names = undefined,
8937 .field_types = undefined,
8938 .field_values = undefined,
8939 .field_aligns = undefined,
8940 .field_is_comptime_bits = undefined,
85778941 } };
85788942}
85798943
......@@ -8584,12 +8948,15 @@ pub const WipContainerType = struct {
85848948 name_nav_index: u32,
85858949 namespace_index: u32,
85868950
8587 tag_type_index: ?u32,
8588
8589 fields_len: u32,
8590 field_name_map: MapIndex,
8591 field_names_start: u32,
8592 field_comptime_bits_start: ?u32,
8951 // These fields are only populated when creating reified types, because reified types populate
8952 // field information immediately, with type resolution only handling validation. This is in
8953 // contrast to declared types, where field information is populated by the type resolution
8954 // process evaluating ZIR expressions.
8955 field_names: NullTerminatedString.Slice,
8956 field_types: Index.Slice,
8957 field_values: Index.Slice,
8958 field_aligns: Alignment.Slice,
8959 field_is_comptime_bits: LoadedStructType.ComptimeBits,
85938960
85948961 pub fn setName(
85958962 wip: WipContainerType,
......@@ -8605,48 +8972,6 @@ pub const WipContainerType = struct {
86058972 extra_items[wip.name_nav_index] = @intFromEnum(name_nav);
86068973 }
86078974
8608 pub fn setTagType(
8609 wip: WipContainerType,
8610 ip: *InternPool,
8611 tag_ty: Index,
8612 ) void {
8613 const extra = ip.getLocalShared(wip.tid).extra.acquire();
8614 const extra_items = extra.view().items(.@"0");
8615 const i = wip.tag_type_index.?;
8616 const old_val: InternPool.Index = @enumFromInt(extra_items[i]);
8617 assert(old_val == .none);
8618 assert(tag_ty != .none);
8619 extra_items[i] = @intFromEnum(tag_ty);
8620 }
8621
8622 /// Returns the already-existing field with the same name, if any.
8623 pub fn nextField(
8624 wip: WipContainerType,
8625 ip: *InternPool,
8626 name: NullTerminatedString,
8627 marked_comptime: bool,
8628 ) ?u32 {
8629 assert(wip.fields_len > 0);
8630 const extra = ip.getLocalShared(wip.tid).extra.acquire();
8631 const extra_items = extra.view().items(.@"0");
8632 const map = wip.field_name_map.get(ip);
8633 const field_idx = map.count();
8634 assert(field_idx < wip.fields_len);
8635 const names: []NullTerminatedString = @ptrCast(extra_items[wip.field_names_start..][0..wip.fields_len]);
8636 const adapter: NullTerminatedString.Adapter = .{ .strings = names[0..field_idx] };
8637 const gop = map.getOrPutAssumeCapacityAdapted(name, adapter);
8638 if (gop.found_existing) return @intCast(gop.index);
8639 names[field_idx] = name;
8640 if (wip.field_comptime_bits_start) |start_idx| {
8641 if (marked_comptime) {
8642 extra_items[start_idx + field_idx / 32] |= @as(u32, 1) << @intCast(field_idx % 32);
8643 }
8644 } else {
8645 assert(!marked_comptime);
8646 }
8647 return null;
8648 }
8649
86508975 pub fn finish(
86518976 wip: WipContainerType,
86528977 ip: *InternPool,
......@@ -8657,14 +8982,6 @@ pub const WipContainerType = struct {
86578982
86588983 extra_items[wip.namespace_index] = @intFromEnum(namespace);
86598984
8660 if (wip.fields_len > 0) {
8661 assert(wip.field_name_map.get(ip).count() == wip.fields_len);
8662 }
8663 if (wip.tag_type_index) |i| {
8664 const tag_ty: Index = @enumFromInt(extra_items[i]);
8665 assert(tag_ty != .none);
8666 }
8667
86688985 return wip.index;
86698986 }
86708987
......@@ -9504,19 +9821,6 @@ fn addStringsToMap(
95049821 }
95059822}
95069823
9507fn addIndexesToMap(
9508 ip: *InternPool,
9509 map_index: MapIndex,
9510 indexes: []const Index,
9511) void {
9512 const map = map_index.get(ip);
9513 const adapter: Index.Adapter = .{ .indexes = indexes };
9514 for (indexes) |index| {
9515 const gop = map.getOrPutAssumeCapacityAdapted(index, adapter);
9516 assert(!gop.found_existing);
9517 }
9518}
9519
95209824fn addMap(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, cap: usize) Allocator.Error!MapIndex {
95219825 const maps = ip.getLocal(tid).getMutableMaps(gpa, io);
95229826 const unwrapped: MapIndex.Unwrapped = .{ .tid = tid, .index = maps.mutate.len };
......@@ -10260,10 +10564,78 @@ pub fn dump(ip: *const InternPool) void {
1026010564 const stderr = std.debug.lockStderr(&buffer);
1026110565 defer std.debug.unlockStderr();
1026210566 const w = &stderr.file_writer.interface;
10567 dumpDependencyStatsFallible(ip, w) catch return;
1026310568 dumpStatsFallible(ip, w, std.heap.page_allocator) catch return;
1026410569 dumpAllFallible(ip, w) catch return;
1026510570}
1026610571
10572fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) !void {
10573 const dep_entries_len = ip.dep_entries.items.len - ip.free_dep_entries.items.len;
10574 const src_hash_deps_len = ip.src_hash_deps.count();
10575 const nav_val_deps_len = ip.nav_val_deps.count();
10576 const nav_ty_deps_len = ip.nav_ty_deps.count();
10577 const func_ies_deps_len = ip.func_ies_deps.count();
10578 const type_layout_deps_len = ip.type_layout_deps.count();
10579 const struct_defaults_deps_len = ip.struct_defaults_deps.count();
10580 const zon_file_deps_len = ip.zon_file_deps.count();
10581 const embed_file_deps_len = ip.embed_file_deps.count();
10582 const namespace_deps_len = ip.namespace_deps.count();
10583 const namespace_name_deps_len = ip.namespace_name_deps.count();
10584 const dep_entries_size = dep_entries_len * @sizeOf(DepEntry);
10585 const src_hash_deps_size = src_hash_deps_len * 8;
10586 const nav_val_deps_size = nav_val_deps_len * 8;
10587 const nav_ty_deps_size = nav_ty_deps_len * 8;
10588 const func_ies_deps_size = func_ies_deps_len * 8;
10589 const type_layout_deps_size = type_layout_deps_len * 8;
10590 const struct_defaults_deps_size = struct_defaults_deps_len * 8;
10591 const zon_file_deps_size = zon_file_deps_len * 8;
10592 const embed_file_deps_size = embed_file_deps_len * 8;
10593 const namespace_deps_size = namespace_deps_len * 8;
10594 const namespace_name_deps_size = namespace_name_deps_len * (@sizeOf(NamespaceNameKey) + 4);
10595
10596 try w.print(
10597 \\InternPool dependencies: {d} bytes
10598 \\ {d} entries: {d} bytes
10599 \\ {d} src_hash: {d} bytes
10600 \\ {d} nav_val: {d} bytes
10601 \\ {d} nav_ty: {d} bytes
10602 \\ {d} func_ies: {d} bytes
10603 \\ {d} type_layout: {d} bytes
10604 \\ {d} struct_defaults: {d} bytes
10605 \\ {d} zon_file: {d} bytes
10606 \\ {d} embed_file: {d} bytes
10607 \\ {d} namespace: {d} bytes
10608 \\ {d} namespace_name: {d} bytes
10609 \\
10610 , .{
10611 dep_entries_size + src_hash_deps_size + nav_val_deps_size + nav_ty_deps_size +
10612 func_ies_deps_size + type_layout_deps_size + struct_defaults_deps_size + zon_file_deps_size +
10613 embed_file_deps_size + namespace_deps_size + namespace_name_deps_size,
10614 dep_entries_len,
10615 dep_entries_size,
10616 src_hash_deps_len,
10617 src_hash_deps_size,
10618 nav_val_deps_len,
10619 nav_val_deps_size,
10620 nav_ty_deps_len,
10621 nav_ty_deps_size,
10622 func_ies_deps_len,
10623 func_ies_deps_size,
10624 type_layout_deps_len,
10625 type_layout_deps_size,
10626 struct_defaults_deps_len,
10627 struct_defaults_deps_size,
10628 zon_file_deps_len,
10629 zon_file_deps_size,
10630 embed_file_deps_len,
10631 embed_file_deps_size,
10632 namespace_deps_len,
10633 namespace_deps_size,
10634 namespace_name_deps_len,
10635 namespace_name_deps_size,
10636 });
10637}
10638
1026710639fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !void {
1026810640 var items_len: usize = 0;
1026910641 var extra_len: usize = 0;
......@@ -10278,10 +10650,10 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo
1027810650 const limbs_size = 8 * limbs_len;
1027910651
1028010652 // TODO: map overhead size is not taken into account
10281 const total_size = @sizeOf(InternPool) + items_size + extra_size + limbs_size;
10653 const total_size = items_size + extra_size + limbs_size;
1028210654
10283 std.debug.print(
10284 \\InternPool size: {d} bytes
10655 try w.print(
10656 \\InternPool values: {d} bytes
1028510657 \\ {d} items: {d} bytes
1028610658 \\ {d} extra: {d} bytes
1028710659 \\ {d} limbs: {d} bytes
......@@ -10302,6 +10674,8 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo
1030210674 };
1030310675 var counts = std.AutoArrayHashMap(Tag, TagStats).init(arena);
1030410676 for (ip.locals) |*local| {
10677 // Early check for length 0, because `view()` is invalid if capacity is 0
10678 if (local.mutate.items.len == 0) continue;
1030510679 const items = local.shared.items.view().slice();
1030610680 const extra_list = local.shared.extra;
1030710681 const extra_items = extra_list.view().items(.@"0");
......@@ -10562,6 +10936,8 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo
1056210936
1056310937fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {
1056410938 for (ip.locals, 0..) |*local, tid| {
10939 // Early check for length 0, because `view()` is invalid if capacity is 0
10940 if (local.mutate.items.len == 0) continue;
1056510941 const items = local.shared.items.view();
1056610942 for (
1056710943 items.items(.tag)[0..local.mutate.items.len],
......@@ -11981,22 +12357,42 @@ pub fn unwrapCoercedFunc(ip: *const InternPool, index: Index) Index {
1198112357 };
1198212358}
1198312359
11984/// Returns the already-existing field with the same name, if any.
12360/// Puts `name` into `names_slice` at the next index (that being the current length of `map`).
12361/// Also inserts the name into `map`. If there is an existing field with this name, its index
12362/// is returned. Otherwise, `null` is returned.
1198512363pub fn addFieldName(
1198612364 ip: *InternPool,
11987 extra: Local.Extra,
11988 names_map: MapIndex,
11989 names_start: u32,
12365 names: NullTerminatedString.Slice,
12366 map: MapIndex,
1199012367 name: NullTerminatedString,
1199112368) ?u32 {
11992 const extra_items = extra.view().items(.@"0");
11993 const map = names_map.get(ip);
11994 const field_index = map.count();
11995 const strings = extra_items[names_start..][0..field_index];
11996 const adapter: NullTerminatedString.Adapter = .{ .strings = @ptrCast(strings) };
11997 const gop = map.getOrPutAssumeCapacityAdapted(name, adapter);
12369 const m = map.get(ip);
12370 const field_idx = m.count();
12371 const names_slice = names.get(ip);
12372 names_slice[field_idx] = name;
12373 const adapter: NullTerminatedString.Adapter = .{ .strings = names_slice[0..field_idx] };
12374 const gop = m.getOrPutAssumeCapacityAdapted(name, adapter);
1199812375 if (gop.found_existing) return @intCast(gop.index);
11999 extra_items[names_start + field_index] = @intFromEnum(name);
12376 assert(gop.index == field_idx);
12377 return null;
12378}
12379
12380/// Like `addFieldName`, but instead of adding a field name to a struct, union, or enum, adds a
12381/// field tag value for an enum.
12382pub fn addFieldTagValue(
12383 ip: *InternPool,
12384 values: Index.Slice,
12385 map: MapIndex,
12386 value: Index,
12387) ?u32 {
12388 const m = map.get(ip);
12389 const field_idx = m.count();
12390 const values_slice = values.get(ip);
12391 values_slice[field_idx] = value;
12392 const adapter: Index.Adapter = .{ .indexes = values_slice[0..field_idx] };
12393 const gop = m.getOrPutAssumeCapacityAdapted(value, adapter);
12394 if (gop.found_existing) return @intCast(gop.index);
12395 assert(gop.index == field_idx);
1200012396 return null;
1200112397}
1200212398
......@@ -12295,6 +12691,7 @@ pub fn resolveStructLayout(
1229512691 has_no_possible_value: bool,
1229612692 has_one_possible_value: bool,
1229712693 comptime_only: bool,
12694 has_runtime_bits: bool,
1229812695) void {
1229912696 const unwrapped_index = struct_type.unwrap(ip);
1230012697
......@@ -12311,6 +12708,7 @@ pub fn resolveStructLayout(
1231112708 flags.has_no_possible_value = has_no_possible_value;
1231212709 flags.has_one_possible_value = has_one_possible_value;
1231312710 flags.comptime_only = comptime_only;
12711 flags.has_runtime_bits = has_runtime_bits;
1231412712 flags.alignment = alignment;
1231512713}
1231612714
......@@ -12322,12 +12720,14 @@ pub fn resolveUnionLayout(
1232212720 ip: *InternPool,
1232312721 io: Io,
1232412722 union_type: Index,
12723 enum_tag_type: Index,
1232512724 size: u32,
1232612725 padding: u32,
1232712726 alignment: Alignment,
1232812727 has_no_possible_value: bool,
1232912728 has_one_possible_value: bool,
1233012729 comptime_only: bool,
12730 has_runtime_bits: bool,
1233112731) void {
1233212732 const unwrapped_index = union_type.unwrap(ip);
1233312733
......@@ -12339,17 +12739,24 @@ pub fn resolveUnionLayout(
1233912739 const item = unwrapped_index.getItem(ip);
1234012740 assert(item.tag == .type_union);
1234112741
12742 extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "enum_tag_type").?] = @intFromEnum(enum_tag_type);
1234212743 extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "size").?] = size;
1234312744 extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "padding").?] = padding;
1234412745 const flags: *Tag.TypeUnion.Flags = @ptrCast(&extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "flags").?]);
1234512746 flags.has_no_possible_value = has_no_possible_value;
1234612747 flags.has_one_possible_value = has_one_possible_value;
1234712748 flags.comptime_only = comptime_only;
12749 flags.has_runtime_bits = has_runtime_bits;
1234812750 flags.alignment = alignment;
1234912751}
1235012752
1235112753/// Asserts that `struct_type` is a packed struct type.
12352pub fn resolvePackedStructBackingInt(ip: *InternPool, io: Io, struct_type: Index, backing_int_type: Index) void {
12754pub fn resolvePackedStructLayout(
12755 ip: *InternPool,
12756 io: Io,
12757 struct_type: Index,
12758 backing_int_type: Index,
12759) void {
1235312760 const unwrapped_index = struct_type.unwrap(ip);
1235412761
1235512762 const local = ip.getLocal(unwrapped_index.tid);
......@@ -12371,7 +12778,13 @@ pub fn resolvePackedStructBackingInt(ip: *InternPool, io: Io, struct_type: Index
1237112778}
1237212779
1237312780/// Asserts that `union_type` is a packed union type.
12374pub fn resolvePackedUnionBackingInt(ip: *InternPool, io: Io, union_type: Index, backing_int_type: Index) void {
12781pub fn resolvePackedUnionLayout(
12782 ip: *InternPool,
12783 io: Io,
12784 union_type: Index,
12785 enum_tag_type: Index,
12786 backing_int_type: Index,
12787) void {
1237512788 const unwrapped_index = union_type.unwrap(ip);
1237612789
1237712790 const local = ip.getLocal(unwrapped_index.tid);
......@@ -12387,5 +12800,32 @@ pub fn resolvePackedUnionBackingInt(ip: *InternPool, io: Io, union_type: Index,
1238712800 else => unreachable,
1238812801 }
1238912802
12803 extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnionPacked, "enum_tag_type").?] = @intFromEnum(enum_tag_type);
1239012804 extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnionPacked, "backing_int_type").?] = @intFromEnum(backing_int_type);
1239112805}
12806
12807/// Asserts that `enum_type` is an enum type.
12808pub fn resolveEnumLayout(
12809 ip: *InternPool,
12810 io: Io,
12811 enum_type: Index,
12812 int_tag_type: Index,
12813) void {
12814 const unwrapped_index = enum_type.unwrap(ip);
12815
12816 const local = ip.getLocal(unwrapped_index.tid);
12817 local.mutate.extra.mutex.lockUncancelable(io);
12818 defer local.mutate.extra.mutex.unlock(io);
12819
12820 const extra_items = local.shared.extra.view().items(.@"0");
12821 const item = unwrapped_index.getItem(ip);
12822 switch (item.tag) {
12823 .type_enum_auto,
12824 .type_enum_explicit,
12825 .type_enum_nonexhaustive,
12826 => {},
12827 else => unreachable,
12828 }
12829
12830 extra_items[item.data + std.meta.fieldIndex(Tag.TypeEnum, "int_tag_type").?] = @intFromEnum(int_tag_type);
12831}
src/Sema.zig+740-1565
......@@ -397,7 +397,7 @@ pub const Block = struct {
397397 /// The name of the current "context" for naming namespace types.
398398 /// The interpretation of this depends on the name strategy in ZIR, but the name
399399 /// is always incorporated into the type name somehow.
400 /// See `Sema.createTypeName`.
400 /// See `Sema.setTypeName`.
401401 type_name_ctx: InternPool.NullTerminatedString,
402402
403403 /// Create a `LazySrcLoc` based on an `Offset` from the code being analyzed in this block.
......@@ -1158,7 +1158,7 @@ fn analyzeBodyInner(
11581158 }, inst });
11591159 }
11601160
1161 const air_inst: Air.Inst.Ref = inst: switch (tags[@intFromEnum(inst)]) {
1161 const air_ref: Air.Inst.Ref = inst: switch (tags[@intFromEnum(inst)]) {
11621162 // zig fmt: off
11631163 .alloc => try sema.zirAlloc(block, inst),
11641164 .alloc_inferred => try sema.zirAllocInferred(block, true),
......@@ -1991,31 +1991,33 @@ fn analyzeBodyInner(
19911991 break :blk .void_value;
19921992 },
19931993 };
1994 if (sema.isNoReturn(air_inst)) {
1994 if (sema.isNoReturn(air_ref)) {
19951995 // We're going to assume that the body itself is noreturn, so let's ensure that now
19961996 assert(block.instructions.items.len > 0);
19971997 assert(sema.isNoReturn(block.instructions.items[block.instructions.items.len - 1].toRef()));
19981998 break;
19991999 }
2000 // <MLUGG TODO REMOVE THIS BLOCK, SILLY OPV CHECK>
2001 if (air_inst.toIndex()) |air_inst_index| {
2002 switch (sema.air_instructions.items(.tag)[@intFromEnum(air_inst_index)]) {
2003 .inferred_alloc, .inferred_alloc_comptime => {},
2004 else => {
2005 assert(sema.typeOf(air_inst).onePossibleValue(pt) catch @panic("") == null);
2006 sema.typeOf(air_inst).assertHasLayout(zcu);
2007 },
2008 }
2009 } else {
2010 switch (tags[@intFromEnum(inst)]) {
2011 // MLUGG TODO: do we actually *want* this exception? we could arguably simplify things without it
2012 // e.g. analyzeNavVal could stop doing ensureLayoutResolved in most cases (`extern` is an exception) and instead do `assertHasLayout`
2013 .func, .func_inferred, .func_fancy => {}, // exception: we're in a func decl, layout will get resolved in a bit by `analyzeNavVal`
2014 else => sema.typeOf(air_inst).assertHasLayout(zcu),
2000
2001 // We must resolve the layout of a type before creating a value of that type. Therefore,
2002 // the layout of the type of `air_ref` must already be resolved.
2003 check_type: {
2004 if (air_ref.toIndex()) |air_inst| switch (sema.air_instructions.items(.tag)[@intFromEnum(air_inst)]) {
2005 .inferred_alloc, .inferred_alloc_comptime => break :check_type,
2006 else => {},
2007 };
2008 sema.typeOf(air_ref).assertHasLayout(zcu);
2009 // If the type has an OPV, `air_ref` must be that OPV: there is no other interned value
2010 // it could be, and it would be a bug for the value to not be comptime-known when it has
2011 // an OPV. Behind a `std.debug.runtime_safety` check because `onePossibleValue` mutates
2012 // the InternPool so cannot be optimized out.
2013 if (std.debug.runtime_safety) {
2014 if (try sema.typeOf(air_ref).onePossibleValue(pt)) |opv| {
2015 assert(air_ref == Air.Inst.Ref.fromValue(opv));
2016 }
20152017 }
20162018 }
2017 // </MLUGG TODO REMOVE THIS BLOCK, SILLY OPV CHECK>
2018 map.putAssumeCapacity(inst, air_inst);
2019
2020 map.putAssumeCapacity(inst, air_ref);
20192021 i += 1;
20202022 }
20212023}
......@@ -2097,7 +2099,7 @@ pub fn resolveConstStringIntern(
20972099
20982100fn resolveTypeOrPoison(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) !?Type {
20992101 const air_inst = try sema.resolveInst(zir_ref);
2100 const ty = try sema.analyzeAsType(block, src, air_inst);
2102 const ty = try sema.analyzeAsType(block, src, .type, air_inst);
21012103 if (ty.isGenericPoison()) return null;
21022104 return ty;
21032105}
......@@ -2216,11 +2218,12 @@ pub fn analyzeAsType(
22162218 sema: *Sema,
22172219 block: *Block,
22182220 src: LazySrcLoc,
2221 reason: std.zig.SimpleComptimeReason,
22192222 air_inst: Air.Inst.Ref,
22202223) !Type {
22212224 const wanted_type: Type = .type;
22222225 const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);
2223 const val = try sema.resolveConstDefinedValue(block, src, coerced_inst, .{ .simple = .type });
2226 const val = try sema.resolveConstDefinedValue(block, src, coerced_inst, .{ .simple = reason });
22242227 return val.toType();
22252228}
22262229
......@@ -4112,9 +4115,11 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
41124115/// or error union pointed to, initializing these pointers along the way.
41134116/// Given a `*E!?T`, returns a (valid) `*T`.
41144117/// May invalidate already-stored payload data.
4118/// Asserts that the layout of the pointer child type is already resolved.
41154119fn optEuBasePtrInit(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, src: LazySrcLoc) CompileError!Air.Inst.Ref {
41164120 const pt = sema.pt;
41174121 const zcu = pt.zcu;
4122 sema.typeOf(ptr).childType(zcu).assertHasLayout(zcu);
41184123 var base_ptr = ptr;
41194124 while (true) switch (sema.typeOf(base_ptr).childType(zcu).zigTypeTag(zcu)) {
41204125 .error_union => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true),
......@@ -4128,6 +4133,7 @@ fn optEuBasePtrInit(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, src: LazySrcL
41284133fn zirOptEuBasePtrInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
41294134 const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
41304135 const ptr = try sema.resolveInst(un_node.operand);
4136 try sema.ensureLayoutResolved(sema.typeOf(ptr).childType(sema.pt.zcu));
41314137 return sema.optEuBasePtrInit(block, ptr, block.nodeOffset(un_node.src_node));
41324138}
41334139
......@@ -4513,7 +4519,7 @@ fn validateStructInit(
45134519 if (struct_ty.structFieldIsComptime(i, zcu)) continue;
45144520
45154521 if (!struct_ty.isTuple(zcu)) {
4516 try sema.ensureFieldInitsResolved(struct_ty);
4522 try sema.ensureStructDefaultsResolved(struct_ty);
45174523 }
45184524
45194525 const default_val = struct_ty.structFieldDefaultValue(i, zcu) orelse {
......@@ -5737,7 +5743,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
57375743 }
57385744 if (zcu.llvm_object != null and options.linkage == .internal) return;
57395745 const export_ty = Value.fromInterned(uav.val).typeOf(zcu);
5740 if (!try sema.validateExternType(export_ty, .other)) {
5746 if (!export_ty.validateExtern(.other, zcu)) {
57415747 return sema.failWithOwnedErrorMsg(block, msg: {
57425748 const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)});
57435749 errdefer msg.destroy(sema.gpa);
......@@ -5789,7 +5795,7 @@ pub fn analyzeExport(
57895795 const exported_nav = ip.getNav(exported_nav_index);
57905796 const export_ty: Type = .fromInterned(exported_nav.typeOf(ip));
57915797
5792 if (!try sema.validateExternType(export_ty, .other)) {
5798 if (!export_ty.validateExtern(.other, zcu)) {
57935799 return sema.failWithOwnedErrorMsg(block, msg: {
57945800 const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)});
57955801 errdefer msg.destroy(gpa);
......@@ -5827,7 +5833,7 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void {
58275833 .nav_val,
58285834 .nav_ty,
58295835 .type_layout,
5830 .type_inits,
5836 .struct_defaults,
58315837 .memoized_state,
58325838 => return, // does nothing outside a function
58335839 };
......@@ -5846,7 +5852,7 @@ fn zirDisableIntrinsics(sema: *Sema) CompileError!void {
58465852 .nav_val,
58475853 .nav_ty,
58485854 .type_layout,
5849 .type_inits,
5855 .struct_defaults,
58505856 .memoized_state,
58515857 => return, // does nothing outside a function
58525858 };
......@@ -6729,8 +6735,28 @@ fn analyzeCall(
67296735 } else func_src;
67306736
67316737 const func_ty_info = zcu.typeToFunc(func_ty).?;
6732 // MLUGG TODO: this isn't quite the check i want. this includes inline functions, which aren't *generic*...
6733 const func_is_generic = !func_ty.fnHasRuntimeBits(zcu);
6738 const any_comptime_params = func_ty_info.comptime_bits != 0 or ct: {
6739 for (func_ty_info.param_types.get(ip)) |param_ty| {
6740 if (Type.fromInterned(param_ty).comptimeOnly(zcu)) break :ct true;
6741 }
6742 break :ct Type.fromInterned(func_ty_info.return_type).comptimeOnly(zcu);
6743 };
6744 const any_generic_types = generic: {
6745 for (func_ty_info.param_types.get(ip)) |param_ty| {
6746 if (param_ty == .generic_poison_type) break :generic true;
6747 }
6748 const ret_ty: Type = .fromInterned(func_ty_info.return_type);
6749 if (ret_ty.toIntern() == .generic_poison_type) {
6750 break :generic true;
6751 }
6752 if (ret_ty.zigTypeTag(zcu) == .error_union and
6753 ret_ty.errorUnionPayload(zcu).toIntern() == .generic_poison_type)
6754 {
6755 break :generic true;
6756 }
6757 break :generic false;
6758 };
6759
67346760 if (!callConvIsCallable(func_ty_info.cc)) {
67356761 return sema.failWithOwnedErrorMsg(block, msg: {
67366762 const msg = try sema.errMsg(
......@@ -6766,7 +6792,7 @@ fn analyzeCall(
67666792 else => unreachable,
67676793 } else .{ null, false };
67686794
6769 if (func_is_generic and func_val == null) {
6795 if ((any_generic_types or any_comptime_params) and func_val == null) {
67706796 return sema.failWithNeededComptime(block, func_src, .{ .simple = .generic_call_target });
67716797 }
67726798
......@@ -6815,13 +6841,13 @@ fn analyzeCall(
68156841 // This is the `inst_map` used when evaluating generic parameters and return types.
68166842 var generic_inst_map: InstMap = .{};
68176843 defer generic_inst_map.deinit(gpa);
6818 if (func_is_generic) {
6844 if (any_generic_types) {
68196845 try generic_inst_map.ensureSpaceForInstructions(gpa, fn_zir_info.param_body);
68206846 }
68216847
68226848 // This exists so that `generic_block` below can include a "called from here" note back to this
68236849 // call site when analyzing generic parameter/return types.
6824 var generic_inlining: Block.Inlining = if (func_is_generic) .{
6850 var generic_inlining: Block.Inlining = if (any_generic_types) .{
68256851 .call_block = block,
68266852 .call_src = call_src,
68276853 .func = func_val.?.toIntern(),
......@@ -6834,7 +6860,7 @@ fn analyzeCall(
68346860 // This is the block in which we evaluate generic function components: that is, generic parameter
68356861 // types and the generic return type. This must not be used if the function is not generic.
68366862 // `comptime_reason` is set as needed.
6837 var generic_block: Block = if (func_is_generic) .{
6863 var generic_block: Block = if (any_generic_types) .{
68386864 .parent = null,
68396865 .sema = sema,
68406866 .namespace = fn_nav.analysis.?.namespace,
......@@ -6843,9 +6869,9 @@ fn analyzeCall(
68436869 .src_base_inst = fn_nav.analysis.?.zir_index,
68446870 .type_name_ctx = fn_nav.fqn,
68456871 } else undefined;
6846 defer if (func_is_generic) generic_block.instructions.deinit(gpa);
6872 defer if (any_generic_types) generic_block.instructions.deinit(gpa);
68476873
6848 if (func_is_generic) {
6874 if (any_generic_types) {
68496875 // We certainly depend on the generic owner's signature!
68506876 try sema.declareDependency(.{ .src_hash = fn_tracked_inst });
68516877 }
......@@ -6857,7 +6883,7 @@ fn analyzeCall(
68576883 if (raw != .generic_poison_type) break :ty .fromInterned(raw);
68586884
68596885 // We must discover the generic parameter type.
6860 assert(func_is_generic);
6886 assert(any_generic_types);
68616887 const param_inst_idx = fn_zir_info.param_body[arg_idx];
68626888 const param_inst = fn_zir.instructions.get(@intFromEnum(param_inst_idx));
68636889 switch (param_inst.tag) {
......@@ -6888,7 +6914,7 @@ fn analyzeCall(
68886914 } };
68896915
68906916 const ty_ref = try sema.resolveInlineBody(&generic_block, body, param_inst_idx);
6891 const param_ty = try sema.analyzeAsType(&generic_block, param_src, ty_ref);
6917 const param_ty = try sema.analyzeAsType(&generic_block, param_src, .fn_param_types, ty_ref);
68926918
68936919 if (!param_ty.isValidParamType(zcu)) {
68946920 const opaque_str = if (param_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else "";
......@@ -6906,7 +6932,7 @@ fn analyzeCall(
69066932 return arg.*; // terminate analysis here
69076933 }
69086934
6909 if (func_is_generic) {
6935 if (any_generic_types) {
69106936 // We need to put the argument into `generic_inst_map` so that other parameters can refer to it.
69116937 const param_inst_idx = fn_zir_info.param_body[arg_idx];
69126938 const declared_comptime = if (std.math.cast(u5, arg_idx)) |i| func_ty_info.paramIsComptime(i) else false;
......@@ -6948,7 +6974,7 @@ fn analyzeCall(
69486974 // calls (where it should be the IES of the instantiation). However, it's how we print this
69496975 // in error messages.
69506976 const resolved_ret_ty: Type = ret_ty: {
6951 if (!func_is_generic) break :ret_ty .fromInterned(func_ty_info.return_type);
6977 if (!any_generic_types) break :ret_ty .fromInterned(func_ty_info.return_type);
69526978
69536979 const maybe_poison_bare = if (fn_zir_info.inferred_error_set) maybe_poison: {
69546980 break :maybe_poison ip.errorUnionPayload(func_ty_info.return_type);
......@@ -6958,7 +6984,7 @@ fn analyzeCall(
69586984
69596985 // Evaluate the generic return type. As with generic parameters, we switch out `sema.code` and `sema.inst_map`.
69606986
6961 assert(func_is_generic);
6987 assert(any_generic_types);
69626988
69636989 const old_code = sema.code;
69646990 const old_inst_map = sema.inst_map;
......@@ -6981,7 +7007,7 @@ fn analyzeCall(
69817007 } else bare: {
69827008 assert(fn_zir_info.ret_ty_body.len != 0);
69837009 const ty_ref = try sema.resolveInlineBody(&generic_block, fn_zir_info.ret_ty_body, fn_zir_inst);
6984 break :bare try sema.analyzeAsType(&generic_block, func_ret_ty_src, ty_ref);
7010 break :bare try sema.analyzeAsType(&generic_block, func_ret_ty_src, .fn_ret_ty, ty_ref);
69857011 };
69867012 assert(bare_ty.toIntern() != .generic_poison_type);
69877013
......@@ -7035,7 +7061,7 @@ fn analyzeCall(
70357061 });
70367062 if (func_ty_info.cc == .auto) {
70377063 switch (sema.owner.unwrap()) {
7038 .@"comptime", .nav_ty, .nav_val, .type_layout, .type_inits, .memoized_state => {},
7064 .@"comptime", .nav_ty, .nav_val, .type_layout, .struct_defaults, .memoized_state => {},
70397065 .func => |owner_func| ip.funcSetHasErrorTrace(io, owner_func, true),
70407066 }
70417067 }
......@@ -7043,7 +7069,7 @@ fn analyzeCall(
70437069 try sema.validateRuntimeValue(block, args_info.argSrc(block, arg_idx), arg);
70447070 }
70457071 const runtime_func: Air.Inst.Ref, const runtime_args: []const Air.Inst.Ref = func: {
7046 if (!func_is_generic) break :func .{ callee, args };
7072 if (!any_generic_types and !any_comptime_params) break :func .{ callee, args };
70477073
70487074 // Instantiate the generic function!
70497075
......@@ -7512,9 +7538,7 @@ fn zirArrayInitElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil
75127538 assert(indexable_ty.isIndexable(zcu)); // validated by a previous instruction
75137539 const elem_ty = switch (indexable_ty.zigTypeTag(zcu)) {
75147540 .@"struct" => indexable_ty.fieldType(@intFromEnum(bin.rhs), zcu),
7515 .array, .vector => indexable_ty.childType(zcu),
7516 .pointer => indexable_ty.indexablePtrElem(zcu),
7517 else => unreachable,
7541 else => indexable_ty.indexableElem(zcu),
75187542 };
75197543 return .fromType(elem_ty);
75207544}
......@@ -7835,8 +7859,8 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
78357859 };
78367860 return sema.failWithOwnedErrorMsg(block, msg);
78377861 }
7838 const lhs_ty = try sema.analyzeAsType(block, lhs_src, lhs);
7839 const rhs_ty = try sema.analyzeAsType(block, rhs_src, rhs);
7862 const lhs_ty = try sema.analyzeAsType(block, lhs_src, .type, lhs);
7863 const rhs_ty = try sema.analyzeAsType(block, rhs_src, .type, rhs);
78407864 if (lhs_ty.zigTypeTag(zcu) != .error_set)
78417865 return sema.fail(block, lhs_src, "expected error set type, found '{f}'", .{lhs_ty.fmt(pt)});
78427866 if (rhs_ty.zigTypeTag(zcu) != .error_set)
......@@ -8017,12 +8041,13 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
80178041 if (dest_ty.zigTypeTag(zcu) != .@"enum") {
80188042 return sema.fail(block, src, "expected enum, found '{f}'", .{dest_ty.fmt(pt)});
80198043 }
8044 try sema.ensureLayoutResolved(dest_ty);
80208045 _ = try sema.checkIntType(block, operand_src, operand_ty);
80218046
80228047 if (try sema.resolveValue(operand)) |int_val| {
80238048 if (dest_ty.isNonexhaustiveEnum(zcu)) {
80248049 const int_tag_ty = dest_ty.intTagType(zcu);
8025 if (try sema.intFitsInType(int_val, int_tag_ty, null)) {
8050 if (int_val.intFitsInType(int_tag_ty, null, zcu)) {
80268051 return Air.internedToRef((try pt.getCoerced(int_val, dest_ty)).toIntern());
80278052 }
80288053 return sema.fail(block, src, "int value '{f}' out of range of non-exhaustive enum '{f}'", .{
......@@ -8077,10 +8102,14 @@ fn zirOptionalPayloadPtr(
80778102 const optional_ptr = try sema.resolveInst(inst_data.operand);
80788103 const src = block.nodeOffset(inst_data.src_node);
80798104
8105 const ptr_ty = sema.typeOf(optional_ptr);
8106 assert(ptr_ty.zigTypeTag(sema.pt.zcu) == .pointer);
8107 try sema.ensureLayoutResolved(ptr_ty.childType(sema.pt.zcu));
8108
80808109 return sema.analyzeOptionalPayloadPtr(block, src, optional_ptr, safety_check, false);
80818110}
80828111
8083/// MLUGG TODO: pre-resolved child?
8112/// Asserts that the layout of the pointer child type is already resolved.
80848113fn analyzeOptionalPayloadPtr(
80858114 sema: *Sema,
80868115 block: *Block,
......@@ -8095,12 +8124,12 @@ fn analyzeOptionalPayloadPtr(
80958124 assert(optional_ptr_ty.zigTypeTag(zcu) == .pointer);
80968125
80978126 const opt_type = optional_ptr_ty.childType(zcu);
8127 opt_type.assertHasLayout(zcu);
80988128 if (opt_type.zigTypeTag(zcu) != .optional) {
80998129 return sema.failWithExpectedOptionalType(block, src, opt_type);
81008130 }
81018131
81028132 const child_type = opt_type.optionalChild(zcu);
8103 try sema.ensureLayoutResolved(child_type);
81048133 const child_pointer = try pt.ptrType(.{
81058134 .child = child_type.toIntern(),
81068135 .flags = .{
......@@ -8283,10 +8312,14 @@ fn zirErrUnionPayloadPtr(
82838312 const operand = try sema.resolveInst(inst_data.operand);
82848313 const src = block.nodeOffset(inst_data.src_node);
82858314
8315 const ptr_ty = sema.typeOf(operand);
8316 assert(ptr_ty.zigTypeTag(sema.pt.zcu) == .pointer);
8317 try sema.ensureLayoutResolved(ptr_ty.childType(sema.pt.zcu));
8318
82868319 return sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);
82878320}
82888321
8289/// MLUGG TODO LAYOUT: already-resolved child?
8322/// Asserts that the layout of the pointer child type is already resolved.
82908323fn analyzeErrUnionPayloadPtr(
82918324 sema: *Sema,
82928325 block: *Block,
......@@ -8307,8 +8340,8 @@ fn analyzeErrUnionPayloadPtr(
83078340 }
83088341
83098342 const err_union_ty = operand_ty.childType(zcu);
8343 err_union_ty.assertHasLayout(zcu);
83108344 const payload_ty = err_union_ty.errorUnionPayload(zcu);
8311 try sema.ensureLayoutResolved(payload_ty);
83128345 const operand_pointer_ty = try pt.ptrType(.{
83138346 .child = payload_ty.toIntern(),
83148347 .flags = .{
......@@ -8744,7 +8777,7 @@ fn checkParamTypeCommon(
87448777 }
87458778 if (!param_ty.isGenericPoison() and
87468779 !target_util.fnCallConvAllowsZigTypes(cc) and
8747 !try sema.validateExternType(param_ty, .param_ty))
8780 !param_ty.validateExtern(.param_ty, zcu))
87488781 {
87498782 return sema.failWithOwnedErrorMsg(block, msg: {
87508783 const msg = try sema.errMsg(param_src, "parameter of type '{f}' not allowed in function with calling convention '{s}'", .{
......@@ -8818,7 +8851,7 @@ fn checkReturnTypeAndCallConvCommon(
88188851 }
88198852 if (!bare_ret_ty.isGenericPoison() and
88208853 !target_util.fnCallConvAllowsZigTypes(@"callconv") and
8821 (inferred_error_set or !try sema.validateExternType(bare_ret_ty, .ret_ty)))
8854 (inferred_error_set or !bare_ret_ty.validateExtern(.ret_ty, zcu)))
88228855 {
88238856 return sema.failWithOwnedErrorMsg(block, msg: {
88248857 const msg = try sema.errMsg(ret_ty_src, "return type '{s}{f}' not allowed in function with calling convention '{s}'", .{
......@@ -9042,7 +9075,7 @@ fn funcCommon(
90429075
90439076 if (inferred_error_set) {
90449077 assert(has_body);
9045 return .fromIntern(try ip.getFuncDeclIes(gpa, io, pt.tid, .{
9078 const func_val: Value = .fromInterned(try ip.getFuncDeclIes(gpa, io, pt.tid, .{
90469079 .owner_nav = sema.owner.unwrap().nav_val,
90479080
90489081 .param_types = param_types,
......@@ -9059,6 +9092,8 @@ fn funcCommon(
90599092 .lbrace_column = @as(u16, @truncate(src_locs.columns)),
90609093 .rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)),
90619094 }));
9095 try sema.ensureLayoutResolved(func_val.typeOf(zcu));
9096 return .fromValue(func_val);
90629097 }
90639098
90649099 const func_ty = try ip.getFuncType(gpa, io, pt.tid, .{
......@@ -9072,6 +9107,7 @@ fn funcCommon(
90729107 });
90739108
90749109 if (has_body) {
9110 try sema.ensureLayoutResolved(.fromInterned(func_ty));
90759111 return .fromIntern(try ip.getFuncDecl(gpa, io, pt.tid, .{
90769112 .owner_nav = sema.owner.unwrap().nav_val,
90779113 .ty = func_ty,
......@@ -9109,7 +9145,7 @@ fn zirParam(
91099145 }
91109146
91119147 const param_ty_inst = try sema.resolveInlineBody(block, body, inst);
9112 break :ty try sema.analyzeAsType(block, src, param_ty_inst);
9148 break :ty try sema.analyzeAsType(block, src, .fn_param_types, param_ty_inst);
91139149 };
91149150
91159151 try block.params.append(sema.arena, .{
......@@ -9948,6 +9984,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
99489984 err_union_ty.fmt(pt),
99499985 });
99509986 }
9987 try sema.ensureLayoutResolved(err_union_ty);
99519988
99529989 const non_err_cond = if (non_err_case.operand_is_ref)
99539990 try sema.analyzePtrIsNonErr(block, operand_src, eu_maybe_ptr)
......@@ -12924,7 +12961,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1292412961 const res_ty: InternPool.Index = b: {
1292512962 if (extra.res_ty == .none) break :b .none;
1292612963 const res_ty_inst = try sema.resolveInst(extra.res_ty);
12927 const res_ty = try sema.analyzeAsType(block, operand_src, res_ty_inst);
12964 const res_ty = try sema.analyzeAsType(block, operand_src, .type, res_ty_inst);
1292812965 if (res_ty.isGenericPoison()) break :b .none;
1292912966 break :b res_ty.toIntern();
1293012967 };
......@@ -15683,8 +15720,8 @@ fn zirCmpEq(
1568315720 return block.addBinOp(air_tag, lhs, rhs);
1568415721 }
1568515722 if (lhs_ty_tag == .type and rhs_ty_tag == .type) {
15686 const lhs_as_type = try sema.analyzeAsType(block, lhs_src, lhs);
15687 const rhs_as_type = try sema.analyzeAsType(block, rhs_src, rhs);
15723 const lhs_as_type = try sema.analyzeAsType(block, lhs_src, .type, lhs);
15724 const rhs_as_type = try sema.analyzeAsType(block, rhs_src, .type, rhs);
1568815725 return if (lhs_as_type.eql(rhs_as_type, zcu) == (op == .eq)) .bool_true else .bool_false;
1568915726 }
1569015727 return sema.analyzeCmp(block, src, lhs, rhs, op, lhs_src, rhs_src, true);
......@@ -15979,16 +16016,7 @@ fn zirThis(
1597916016 extended: Zir.Inst.Extended.InstData,
1598016017) CompileError!Air.Inst.Ref {
1598116018 _ = extended;
15982 const zcu = sema.pt.zcu;
15983 const namespace = zcu.namespacePtr(block.namespace);
15984
15985 switch (zcu.intern_pool.indexToKey(namespace.owner_type)) {
15986 .opaque_type, .struct_type, .union_type => {},
15987 // Enum inits are resolved eagerly. TODO MLUGG: honestly i don't think they SHOULD be lol
15988 .enum_type => try sema.ensureFieldInitsResolved(.fromInterned(namespace.owner_type)),
15989 else => unreachable,
15990 }
15991 return .fromIntern(namespace.owner_type);
16019 return .fromIntern(sema.pt.zcu.namespacePtr(block.namespace).owner_type);
1599216020}
1599316021
1599416022fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
......@@ -16224,12 +16252,12 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1622416252 const type_info_ty = try sema.getBuiltinType(src, .Type);
1622516253 const type_info_tag_ty = type_info_ty.unionTagType(zcu).?;
1622616254
16255 try sema.ensureLayoutResolved(ty);
16256
1622716257 if (ty.typeDeclInst(zcu)) |type_decl_inst| {
1622816258 try sema.declareDependency(.{ .namespace = type_decl_inst });
1622916259 }
1623016260
16231 try sema.ensureLayoutResolved(ty);
16232
1623316261 switch (ty.zigTypeTag(zcu)) {
1623416262 .type,
1623516263 .void,
......@@ -16240,7 +16268,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1624016268 .undefined,
1624116269 .null,
1624216270 .enum_literal,
16243 => |type_info_tag| return unionInitFromEnumTag(sema, block, src, type_info_ty, @intFromEnum(type_info_tag), .void_value),
16271 => |type_info_tag| return .fromValue(try pt.unionValue(
16272 type_info_ty,
16273 Value.uninterpret(type_info_tag, type_info_tag_ty, pt) catch |err| switch (err) {
16274 error.TypeMismatch => @panic("std.builtin is corrupt"),
16275 error.OutOfMemory => |e| return e,
16276 },
16277 .void,
16278 )),
1624416279
1624516280 .@"fn" => {
1624616281 const fn_info_ty = try sema.getBuiltinType(src, .@"Type.Fn");
......@@ -16248,9 +16283,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1624816283
1624916284 const func_ty_info = zcu.typeToFunc(ty).?;
1625016285 const param_vals = try sema.arena.alloc(InternPool.Index, func_ty_info.param_types.len);
16286 var func_is_generic = false;
1625116287 for (param_vals, 0..) |*param_val, i| {
1625216288 const param_ty = func_ty_info.param_types.get(ip)[i];
1625316289 const is_generic = param_ty == .generic_poison_type;
16290 if (is_generic or Type.fromInterned(param_ty).comptimeOnly(zcu)) func_is_generic = true;
1625416291 const param_ty_val = try pt.intern(.{ .opt = .{
1625516292 .ty = try pt.intern(.{ .opt_type = .type_type }),
1625616293 .val = if (is_generic) .none else param_ty,
......@@ -16300,18 +16337,21 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1630016337 } });
1630116338 };
1630216339
16340 const ret_ty_is_generic = generic: {
16341 const ret_ty: Type = .fromInterned(func_ty_info.return_type);
16342 if (ret_ty.toIntern() == .generic_poison_type) break :generic true;
16343 if (ret_ty.zigTypeTag(zcu) == .error_union) {
16344 if (ret_ty.errorUnionPayload(zcu).toIntern() == .generic_poison_type) {
16345 break :generic true;
16346 }
16347 }
16348 break :generic false;
16349 };
16350 if (ret_ty_is_generic) func_is_generic = true;
16351
1630316352 const ret_ty_opt = try pt.intern(.{ .opt = .{
1630416353 .ty = try pt.intern(.{ .opt_type = .type_type }),
16305 .val = opt_val: {
16306 const ret_ty: Type = .fromInterned(func_ty_info.return_type);
16307 if (ret_ty.toIntern() == .generic_poison_type) break :opt_val .none;
16308 if (ret_ty.zigTypeTag(zcu) == .error_union) {
16309 if (ret_ty.errorUnionPayload(zcu).toIntern() == .generic_poison_type) {
16310 break :opt_val .none;
16311 }
16312 }
16313 break :opt_val ret_ty.toIntern();
16314 },
16354 .val = if (ret_ty_is_generic) .none else func_ty_info.return_type,
1631516355 } });
1631616356
1631716357 const callconv_ty = try sema.getBuiltinType(src, .CallingConvention);
......@@ -16320,9 +16360,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1632016360 error.OutOfMemory => |e| return e,
1632116361 };
1632216362
16323 // MLUGG TODO
16324 const func_is_generic = false;
16325
1632616363 const field_values: [5]InternPool.Index = .{
1632716364 // calling_convention: CallingConvention,
1632816365 callconv_val.toIntern(),
......@@ -16837,7 +16874,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1683716874 .struct_type => ip.loadStructType(ty.toIntern()),
1683816875 else => unreachable,
1683916876 };
16840 try sema.ensureFieldInitsResolved(ty); // can't do this sooner, since it's not allowed on tuples
16877 try sema.ensureStructDefaultsResolved(ty); // can't do this sooner, since it's not allowed on tuples
1684116878 struct_field_vals = try gpa.alloc(InternPool.Index, struct_type.field_types.len);
1684216879
1684316880 for (struct_field_vals, 0..) |*field_val, field_index| {
......@@ -18193,7 +18230,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1819318230
1819418231 const elem_ty = blk: {
1819518232 const air_inst = try sema.resolveInst(extra.data.elem_type);
18196 const ty = sema.analyzeAsType(block, elem_ty_src, air_inst) catch |err| {
18233 const ty = sema.analyzeAsType(block, elem_ty_src, .type, air_inst) catch |err| {
1819718234 if (err == error.AnalysisFail and sema.err != null and sema.typeOf(air_inst).isSinglePointer(zcu)) {
1819818235 try sema.errNote(elem_ty_src, sema.err.?, "use '.*' to dereference pointer", .{});
1819918236 }
......@@ -18274,7 +18311,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1827418311 } else if (inst_data.size != .one and elem_ty.zigTypeTag(zcu) == .@"opaque") {
1827518312 return sema.fail(block, elem_ty_src, "indexable pointer to opaque type '{f}' not allowed", .{elem_ty.fmt(pt)});
1827618313 } else if (inst_data.size == .c) {
18277 if (!try sema.validateExternType(elem_ty, .other)) {
18314 if (!elem_ty.validateExtern(.other, zcu)) {
1827818315 const msg = msg: {
1827918316 const msg = try sema.errMsg(elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)});
1828018317 errdefer msg.destroy(sema.gpa);
......@@ -18288,11 +18325,11 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1828818325 }
1828918326 }
1829018327
18291 if (host_size != 0 and !elem_ty.packable(zcu)) {
18292 return sema.failWithOwnedErrorMsg(block, msg: {
18328 if (host_size != 0) {
18329 if (elem_ty.unpackable(zcu)) |reason| return sema.failWithOwnedErrorMsg(block, msg: {
1829318330 const msg = try sema.errMsg(elem_ty_src, "bit-pointer cannot refer to value of type '{f}'", .{elem_ty.fmt(pt)});
1829418331 errdefer msg.destroy(sema.gpa);
18295 try sema.explainWhyTypeIsNotPackable(msg, elem_ty_src, elem_ty);
18332 try sema.explainWhyTypeIsUnpackable(msg, elem_ty_src, reason);
1829618333 break :msg msg;
1829718334 });
1829818335 }
......@@ -18455,63 +18492,32 @@ fn arrayInitEmpty(sema: *Sema, block: *Block, src: LazySrcLoc, obj_ty: Type) Com
1845518492
1845618493fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
1845718494 const pt = sema.pt;
18495 const zcu = pt.zcu;
18496 const ip = &zcu.intern_pool;
1845818497 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
1845918498 const ty_src = block.builtinCallArgSrc(inst_data.src_node, 0);
1846018499 const field_src = block.builtinCallArgSrc(inst_data.src_node, 1);
18461 const init_src = block.builtinCallArgSrc(inst_data.src_node, 2);
18500 const payload_src = block.builtinCallArgSrc(inst_data.src_node, 2);
1846218501 const extra = sema.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data;
1846318502 const union_ty = try sema.resolveType(block, ty_src, extra.union_type);
1846418503 if (union_ty.zigTypeTag(pt.zcu) != .@"union") {
1846518504 return sema.fail(block, ty_src, "expected union type, found '{f}'", .{union_ty.fmt(pt)});
1846618505 }
18506 union_ty.assertHasLayout(zcu); // from a previous `field_type_ref` instruction
1846718507 const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, .{ .simple = .union_field_names });
18468 const init = try sema.resolveInst(extra.init);
18469 return sema.unionInit(block, init, init_src, union_ty, ty_src, field_name, field_src);
18470}
18471
18472fn unionInit(
18473 sema: *Sema,
18474 block: *Block,
18475 uncasted_init: Air.Inst.Ref,
18476 init_src: LazySrcLoc,
18477 union_ty: Type,
18478 union_ty_src: LazySrcLoc,
18479 field_name: InternPool.NullTerminatedString,
18480 field_src: LazySrcLoc,
18481) CompileError!Air.Inst.Ref {
18482 const pt = sema.pt;
18483 const zcu = pt.zcu;
18484 const ip = &zcu.intern_pool;
1848518508 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src);
1848618509 const field_ty: Type = .fromInterned(zcu.typeToUnion(union_ty).?.field_types.get(ip)[field_index]);
18487 const init = try sema.coerce(block, field_ty, uncasted_init, init_src);
18488 _ = union_ty_src;
18489 return unionInitFromEnumTag(sema, block, init_src, union_ty, field_index, init);
18490}
1849118510
18492fn unionInitFromEnumTag(
18493 sema: *Sema,
18494 block: *Block,
18495 init_src: LazySrcLoc,
18496 union_ty: Type,
18497 field_index: u32,
18498 init: Air.Inst.Ref,
18499) !Air.Inst.Ref {
18500 const pt = sema.pt;
18501 const zcu = pt.zcu;
18511 const payload = try sema.coerce(block, field_ty, try sema.resolveInst(extra.init), payload_src);
1850218512
18503 if (try sema.resolveValue(init)) |init_val| {
18513 if (try sema.resolveValue(payload)) |payload_val| {
1850418514 const tag_ty = union_ty.unionTagTypeHypothetical(zcu);
1850518515 const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index);
18506 return Air.internedToRef((try pt.internUnion(.{
18507 .ty = union_ty.toIntern(),
18508 .tag = tag_val.toIntern(),
18509 .val = init_val.toIntern(),
18510 })));
18516 return .fromValue(try pt.unionValue(union_ty, tag_val, payload_val));
1851118517 }
1851218518
18513 try sema.requireRuntimeBlock(block, init_src, null);
18514 return block.addUnionInit(union_ty, field_index, init);
18519 try sema.requireRuntimeBlock(block, payload_src, null);
18520 return block.addUnionInit(union_ty, field_index, payload);
1851518521}
1851618522
1851718523fn zirStructInit(
......@@ -18588,9 +18594,6 @@ fn zirStructInit(
1858818594 const field_ty = resolved_ty.fieldType(field_index, zcu);
1858918595 field_inits[field_index] = try sema.coerce(block, field_ty, uncoerced_init, field_src);
1859018596 if (resolved_ty.structFieldIsComptime(field_index, zcu)) {
18591 if (!resolved_ty.isTuple(zcu)) {
18592 try sema.ensureFieldInitsResolved(resolved_ty);
18593 }
1859418597 const default_value = (try resolved_ty.structFieldValueComptime(pt, field_index)).?;
1859518598 const init_val = (try sema.resolveValue(field_inits[field_index])) orelse {
1859618599 return sema.failWithNeededComptime(block, field_src, .{ .simple = .stored_to_comptime_field });
......@@ -18744,7 +18747,12 @@ fn finishStructInit(
1874418747 continue;
1874518748 }
1874618749
18747 try sema.ensureFieldInitsResolved(struct_ty);
18750 if (struct_type.field_is_comptime_bits.get(ip, i)) {
18751 field_inits[i] = .fromIntern(struct_type.field_defaults.get(ip)[i]);
18752 continue;
18753 }
18754
18755 try sema.ensureStructDefaultsResolved(struct_ty);
1874818756
1874918757 const field_default: InternPool.Index = d: {
1875018758 if (struct_type.field_defaults.len == 0) break :d .none;
......@@ -18935,55 +18943,54 @@ fn structInitAnon(
1893518943 break :hash hasher.final();
1893618944 };
1893718945 const tracked_inst = try block.trackZir(inst);
18938 const struct_ty: Type = switch (try ip.getStructType(gpa, io, pt.tid, .{
18946 const struct_ty: Type = switch (try ip.getReifiedStructType(gpa, io, pt.tid, .{
18947 .zir_index = tracked_inst,
18948 .type_hash = type_hash,
1893918949 .fields_len = extra_data.fields_len,
1894018950 .layout = .auto,
18941 .explicit_packed_backing_type = .none,
1894218951 .any_comptime_fields = any_values,
1894318952 .any_field_defaults = any_values,
1894418953 .any_field_aligns = false,
18945 .key = .{ .reified = .{
18946 .zir_index = tracked_inst,
18947 .type_hash = type_hash,
18948 } },
18954 .packed_backing_int_type = .none,
1894918955 })) {
18956 .existing => |ty| .fromInterned(ty),
1895018957 .wip => |wip| ty: {
1895118958 errdefer wip.cancel(ip, pt.tid);
18952 // MLUGG TODO obvs this sux
18953 const anon_prefix = (try sema.createTypeName(block, .anon, "struct", inst)).anon_prefix;
18954 wip.setName(ip, try ip.getOrPutStringFmt(gpa, io, pt.tid, "{s}_{d}", .{ anon_prefix, @intFromEnum(wip.index) }, .no_embedded_nulls), .none);
18955
18956 const struct_type = ip.loadStructType(wip.index);
18957
18958 for (names, values) |name, init_val| {
18959 assert(wip.nextField(ip, name, init_val != .none) == null); // AstGen validated no duplicates for us
18959 try sema.setTypeName(block, &wip, .anon, "struct", inst);
18960
18961 // Reified structs have field information populated immediately.
18962 @memcpy(wip.field_names.get(ip), names);
18963 @memcpy(wip.field_types.get(ip), types);
18964 if (any_values) {
18965 @memcpy(wip.field_values.get(ip), values);
18966 @memset(wip.field_is_comptime_bits.getAll(ip), 0);
18967 for (values, 0..) |val, field_index| {
18968 if (val == .none) continue;
18969 const bit_bag_index = field_index / 32;
18970 const mask = @as(u32, 1) << @intCast(field_index % 32);
18971 wip.field_is_comptime_bits.getAll(ip)[bit_bag_index] |= mask;
18972 }
1896018973 }
1896118974
18962 // Populating these means the type is already resolved; we don't need to add it to `zcu.outdated` or anything.
18963 // That's important because type resolution relies on types being declared.
18964 @memcpy(struct_type.field_types.get(ip), types);
18965 @memcpy(struct_type.field_defaults.get(ip), if (any_values) values else @as([]const InternPool.Index, &.{}));
18966
18967 try type_resolution.finishStructLayout(sema, block, src, wip.index, &struct_type);
18968
1896918975 const new_namespace_index = try pt.createNamespace(.{
1897018976 .parent = block.namespace.toOptional(),
1897118977 .owner_type = wip.index,
1897218978 .file_scope = block.getFileScopeIndex(zcu),
1897318979 .generation = zcu.generation,
1897418980 });
18975 codegen_type: {
18976 if (zcu.comp.config.use_llvm) break :codegen_type;
18977 if (block.ownerModule().strip) break :codegen_type;
18978 zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
18979 try zcu.comp.queueJob(.{ .link_type = wip.index });
18980 }
1898118981 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
18982
18983 try zcu.outdated.ensureUnusedCapacity(gpa, 1);
18984 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1);
18985 errdefer comptime unreachable; // because we don't remove the `outdated` entries
18986 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0);
18987 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {});
18988
1898218989 break :ty .fromInterned(wip.finish(ip, new_namespace_index));
1898318990 },
18984 .existing => |ty| .fromInterned(ty),
1898518991 };
1898618992 try sema.addTypeReferenceEntry(src, struct_ty);
18993 try sema.ensureLayoutResolved(struct_ty);
1898718994
1898818995 _ = opt_runtime_index orelse {
1898918996 const struct_val = try pt.aggregateValue(struct_ty, values);
......@@ -19338,6 +19345,7 @@ fn fieldType(
1933819345 const pt = sema.pt;
1933919346 const zcu = pt.zcu;
1934019347 const ip = &zcu.intern_pool;
19348 aggregate_ty.assertHasLayout(zcu);
1934119349 var cur_ty = aggregate_ty;
1934219350 while (true) {
1934319351 switch (cur_ty.zigTypeTag(zcu)) {
......@@ -19397,7 +19405,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
1939719405 .func => |func| if (ip.funcAnalysisUnordered(func).has_error_trace and block.ownerModule().error_tracing) {
1939819406 return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty);
1939919407 },
19400 .@"comptime", .nav_ty, .nav_val, .type_layout, .type_inits, .memoized_state => {},
19408 .@"comptime", .nav_ty, .nav_val, .type_layout, .struct_defaults, .memoized_state => {},
1940119409 }
1940219410 return Air.internedToRef(try pt.intern(.{ .opt = .{
1940319411 .ty = opt_ptr_stack_trace_ty.toIntern(),
......@@ -19823,7 +19831,7 @@ fn zirReifyPointer(
1982319831 else => {},
1982419832 }
1982519833
19826 if (size == .c and !try sema.validateExternType(elem_ty, .other)) {
19834 if (size == .c and !elem_ty.validateExtern(.other, zcu)) {
1982719835 return sema.failWithOwnedErrorMsg(block, msg: {
1982819836 const msg = try sema.errMsg(src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)});
1982919837 errdefer msg.destroy(gpa);
......@@ -19988,6 +19996,7 @@ fn zirReifyStruct(
1998819996 const name_strategy: Zir.Inst.NameStrategy = @enumFromInt(extended.small);
1998919997 const extra = sema.code.extraData(Zir.Inst.ReifyStruct, extended.operand).data;
1999019998 const tracked_inst = try block.trackZir(inst);
19999
1999120000 const src: LazySrcLoc = .{
1999220001 .base_node_inst = tracked_inst,
1999320002 .offset = .nodeOffset(.zero),
......@@ -20039,7 +20048,7 @@ fn zirReifyStruct(
2003920048
2004020049 const backing_int_ty_uncoerced = try sema.resolveInst(extra.backing_ty);
2004120050 const backing_int_ty_coerced = try sema.coerce(block, .optional_type, backing_int_ty_uncoerced, backing_ty_src);
20042 const backing_int_ty_val = try sema.resolveConstDefinedValue(block, backing_ty_src, backing_int_ty_coerced, .{ .simple = .type });
20051 const backing_int_ty_val = try sema.resolveConstDefinedValue(block, backing_ty_src, backing_int_ty_coerced, .{ .simple = .packed_struct_backing_int_type });
2004320052
2004420053 const field_names_uncoerced = try sema.resolveInst(extra.field_names);
2004520054 const field_names_coerced = try sema.coerce(block, .slice_const_slice_const_u8, field_names_uncoerced, field_names_src);
......@@ -20079,19 +20088,30 @@ fn zirReifyStruct(
2007920088 return sema.failWithUseOfUndef(block, backing_ty_src, null);
2008020089 }
2008120090
20082 // The validation work here is non-trivial, and it's possible the type already exists.
20083 // So in this first pass, let's just construct a hash to optimize for this case. If the
20084 // inputs turn out to be invalid, we can cancel the WIP type later.
20091 // Most validation of this type happens during type resolution. We basically need to do the work
20092 // which AstGen would normally do. An exception is checking for duplicate field names, which is
20093 // handled by type resolution---it just simplifies some logic a little.
20094
20095 // As well as validation, we're going to gather some information about the fields, and construct
20096 // a hash representing the inputs for deduplication purposes.
2008520097
2008620098 var any_comptime_fields = false;
20087 var any_default_inits = false;
20088 var any_aligned_fields = false;
20099 var any_field_defaults = false;
20100 var any_field_aligns = false;
2008920101
20090 // For deduplication purposes, we must create a hash including all details of this type.
2009120102 // TODO: use a longer hash!
2009220103 var hasher = std.hash.Wyhash.init(0);
2009320104 std.hash.autoHash(&hasher, layout);
2009420105 std.hash.autoHash(&hasher, backing_int_ty_val);
20106
20107 const backing_int_ty: ?Type = if (backing_int_ty_val.optionalValue(zcu)) |backing| ty: {
20108 switch (layout) {
20109 .auto, .@"extern" => return sema.fail(block, backing_ty_src, "non-packed struct does not support backing integer type", .{}),
20110 .@"packed" => {},
20111 }
20112 break :ty backing.toType();
20113 } else null;
20114
2009520115 // The field *type* array has already been deduplicated for us thanks to the InternPool!
2009620116 std.hash.autoHash(&hasher, field_types_arr);
2009720117 // However, for field names and attributes, we need to actually iterate the individual fields,
......@@ -20126,201 +20146,126 @@ fn zirReifyStruct(
2012620146 field_attrs_src,
2012720147 .{ .simple = .struct_field_default_value },
2012820148 );
20149 if (deref_val.canMutateComptimeVarState(zcu)) {
20150 return sema.failWithContainsReferenceToComptimeVar(block, field_attrs_src, field_name, "field default value", deref_val);
20151 }
20152 any_field_defaults = true;
2012920153 break :d deref_val.toIntern();
2013020154 };
2013120155
20156 if (field_attr_comptime.toBool()) {
20157 if (field_default == .none) {
20158 return sema.fail(block, field_attrs_src, "comptime field without default initialization value", .{});
20159 }
20160 if (layout != .auto) {
20161 return sema.fail(block, field_attrs_src, "{t} struct fields cannot be marked comptime", .{layout});
20162 }
20163 any_comptime_fields = true;
20164 }
20165
20166 if (field_attr_align.optionalValue(zcu)) |align_val| {
20167 if (layout == .@"packed") {
20168 return sema.fail(block, field_attrs_src, "packed struct fields cannot be aligned", .{});
20169 }
20170 // Trigger a compile error if the alignment is invalid.
20171 _ = try sema.validateAlign(block, field_attrs_src, align_val.toUnsignedInt(zcu));
20172 any_field_aligns = true;
20173 }
20174
2013220175 std.hash.autoHash(&hasher, .{
2013320176 field_name,
2013420177 field_attr_comptime,
2013520178 field_attr_align,
2013620179 field_default,
2013720180 });
20138
20139 if (field_attr_comptime.toBool()) any_comptime_fields = true;
20140 if (field_attr_align.optionalValue(zcu)) |_| any_aligned_fields = true;
20141 if (field_default != .none) any_default_inits = true;
20142 }
20143
20144 // Some basic validation to avoid a bogus `getStructType` call...
20145 const backing_int_ty: ?Type = if (backing_int_ty_val.optionalValue(zcu)) |backing| ty: {
20146 switch (layout) {
20147 .auto, .@"extern" => return sema.fail(block, backing_ty_src, "non-packed struct does not support backing integer type", .{}),
20148 .@"packed" => {},
20149 }
20150 break :ty backing.toType();
20151 } else null;
20152 if (any_aligned_fields and layout == .@"packed") {
20153 return sema.fail(block, field_attrs_src, "packed struct fields cannot be aligned", .{});
20154 }
20155 if (any_comptime_fields and layout != .auto) {
20156 return sema.fail(block, field_attrs_src, "{t} struct fields cannot be marked comptime", .{layout});
2015720181 }
2015820182
20159 const wip_ty = switch (try ip.getStructType(gpa, io, pt.tid, .{
20183 switch (try ip.getReifiedStructType(gpa, io, pt.tid, .{
20184 .zir_index = tracked_inst,
20185 .type_hash = hasher.final(),
2016020186 .fields_len = @intCast(fields_len),
2016120187 .layout = layout,
20162 .explicit_packed_backing_type = if (backing_int_ty) |t| t.toIntern() else .none,
2016320188 .any_comptime_fields = any_comptime_fields,
20164 .any_field_defaults = any_default_inits,
20165 .any_field_aligns = any_aligned_fields,
20166 .key = .{ .reified = .{
20167 .zir_index = tracked_inst,
20168 .type_hash = hasher.final(),
20169 } },
20189 .any_field_defaults = any_field_defaults,
20190 .any_field_aligns = any_field_aligns,
20191 .packed_backing_int_type = if (backing_int_ty) |ty| ty.toIntern() else .none,
2017020192 })) {
20171 .wip => |wip| wip,
2017220193 .existing => |ty| {
2017320194 try sema.addTypeReferenceEntry(src, .fromInterned(ty));
2017420195 return .fromIntern(ty);
2017520196 },
20176 };
20177 errdefer wip_ty.cancel(ip, pt.tid);
20178
20179 _ = try (try sema.createTypeName(
20180 block,
20181 name_strategy,
20182 "struct",
20183 inst,
20184 )).apply(&wip_ty, pt);
20185
20186 const wip_struct_type = ip.loadStructType(wip_ty.index);
20187
20188 for (0..fields_len) |field_idx| {
20189 const field_name_val = try field_names_arr.elemValue(pt, field_idx);
20190 const field_attrs_val = try field_attrs_arr.elemValue(pt, field_idx);
20191
20192 // Don't pass a reason; first loop acts as a check that this is valid.
20193 const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined);
20194 const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType();
20195 const field_attr_comptime = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
20196 std.builtin.Type.StructField.Attributes,
20197 "comptime",
20198 ).?);
20199 const field_attr_align = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
20200 std.builtin.Type.StructField.Attributes,
20201 "align",
20202 ).?);
20203 const field_attr_default_value_ptr = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
20204 std.builtin.Type.StructField.Attributes,
20205 "default_value_ptr",
20206 ).?);
20197 .wip => |wip| {
20198 errdefer wip.cancel(ip, pt.tid);
20199 try sema.setTypeName(block, &wip, name_strategy, "struct", inst);
20200 for (0..fields_len) |field_idx| {
20201 const field_name_val = try field_names_arr.elemValue(pt, field_idx);
20202 const field_attrs_val = try field_attrs_arr.elemValue(pt, field_idx);
20203
20204 // No source location or reason; first loop checked this is valid.
20205 const field_name = try sema.sliceToIpString(block, .unneeded, field_name_val, undefined);
20206 wip.field_names.get(ip)[field_idx] = field_name;
20207
20208 const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType();
20209 wip.field_types.get(ip)[field_idx] = field_ty.toIntern();
20210
20211 const field_attr_comptime = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
20212 std.builtin.Type.StructField.Attributes,
20213 "comptime",
20214 ).?);
20215 const field_attr_align = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
20216 std.builtin.Type.StructField.Attributes,
20217 "align",
20218 ).?);
20219 const field_attr_default_value_ptr = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
20220 std.builtin.Type.StructField.Attributes,
20221 "default_value_ptr",
20222 ).?);
20223
20224 if (field_attr_comptime.toBool()) {
20225 const bit_bag_index = field_idx / 32;
20226 const mask = @as(u32, 1) << @intCast(field_idx % 32);
20227 wip.field_is_comptime_bits.getAll(ip)[bit_bag_index] |= mask;
20228 }
2020720229
20208 if (wip_ty.nextField(ip, field_name, field_attr_comptime.toBool())) |prev_index| {
20209 _ = prev_index; // TODO: better source location
20210 return sema.fail(block, field_names_src, "duplicate struct field name {f}", .{field_name.fmt(ip)});
20211 }
20230 if (field_attr_default_value_ptr.optionalValue(zcu)) |ptr_val| {
20231 const ptr_ty = try pt.singleConstPtrType(field_ty);
20232 // No source location; first loop checked this is valid.
20233 const deref_val = (try sema.pointerDeref(block, .unneeded, ptr_val, ptr_ty)).?;
20234 wip.field_values.get(ip)[field_idx] = deref_val.toIntern();
20235 } else if (any_field_defaults) {
20236 wip.field_values.get(ip)[field_idx] = .none;
20237 }
2021220238
20213 const field_default: InternPool.Index = d: {
20214 const ptr_val = field_attr_default_value_ptr.optionalValue(zcu) orelse break :d .none;
20215 assert(any_default_inits);
20216 const ptr_ty = try pt.singleConstPtrType(field_ty);
20217 // The first loop checked that this is comptime-dereferencable.
20218 const deref_val = (try sema.pointerDeref(block, field_attrs_src, ptr_val, ptr_ty)).?;
20219 // ...but we've not checked this yet!
20220 if (deref_val.canMutateComptimeVarState(zcu)) {
20221 return sema.failWithContainsReferenceToComptimeVar(block, field_attrs_src, field_name, "field default value", deref_val);
20239 if (field_attr_align.optionalValue(zcu)) |field_align_val| {
20240 const bytes = field_align_val.toUnsignedInt(zcu);
20241 // No source location; first loop checked this is valid.
20242 const a = try sema.validateAlign(block, .unneeded, bytes);
20243 wip.field_aligns.get(ip)[field_idx] = a;
20244 } else if (any_field_aligns) {
20245 wip.field_aligns.get(ip)[field_idx] = .none;
20246 }
2022220247 }
20223 break :d deref_val.toIntern();
20224 };
20225
20226 if (field_attr_comptime.toBool() and field_default == .none) {
20227 return sema.fail(block, field_attrs_src, "comptime field without default initialization value", .{});
20228 }
20229
20230 switch (field_ty.zigTypeTag(zcu)) {
20231 .@"opaque" => return sema.failWithOwnedErrorMsg(block, msg: {
20232 const msg = try sema.errMsg(field_types_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
20233 errdefer msg.destroy(gpa);
20234 try sema.addDeclaredHereNote(msg, field_ty);
20235 break :msg msg;
20236 }),
20237 .noreturn => return sema.failWithOwnedErrorMsg(block, msg: {
20238 const msg = try sema.errMsg(field_types_src, "struct fields cannot be 'noreturn'", .{});
20239 errdefer msg.destroy(gpa);
20240 try sema.addDeclaredHereNote(msg, field_ty);
20241 break :msg msg;
20242 }),
20243 else => {},
20244 }
20245
20246 switch (layout) {
20247 .auto => {},
20248 .@"extern" => if (!try sema.validateExternType(field_ty, .struct_field)) {
20249 return sema.failWithOwnedErrorMsg(block, msg: {
20250 const msg = try sema.errMsg(field_types_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
20251 errdefer msg.destroy(gpa);
20252 try sema.explainWhyTypeIsNotExtern(msg, field_types_src, field_ty, .struct_field);
20253 try sema.addDeclaredHereNote(msg, field_ty);
20254 break :msg msg;
20255 });
20256 },
20257 .@"packed" => if (!field_ty.packable(zcu)) {
20258 return sema.failWithOwnedErrorMsg(block, msg: {
20259 const msg = try sema.errMsg(field_types_src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
20260 errdefer msg.destroy(gpa);
20261 try sema.explainWhyTypeIsNotPackable(msg, field_types_src, field_ty);
20262 try sema.addDeclaredHereNote(msg, field_ty);
20263 break :msg msg;
20264 });
20265 },
20266 }
20267
20268 wip_struct_type.field_types.get(ip)[field_idx] = field_ty.toIntern();
20269 if (field_default != .none) {
20270 wip_struct_type.field_defaults.get(ip)[field_idx] = field_default;
20271 }
20272
20273 if (field_attr_align.optionalValue(zcu)) |field_align_val| {
20274 assert(layout != .@"packed");
20275 const bytes = field_align_val.toUnsignedInt(zcu);
20276 const a = try sema.validateAlign(block, field_attrs_src, bytes);
20277 wip_struct_type.field_aligns.get(ip)[field_idx] = a;
20278 } else if (any_aligned_fields) {
20279 assert(layout != .@"packed");
20280 wip_struct_type.field_aligns.get(ip)[field_idx] = .none;
20281 }
20282 }
2028320248
20284 if (layout == .@"packed") {
20285 var field_bits: u64 = 0;
20286 for (0..fields_len) |field_idx| {
20287 const field_ty: Type = .fromInterned(wip_struct_type.field_types.get(ip)[field_idx]);
20288 try sema.ensureLayoutResolved(field_ty);
20289 field_bits += field_ty.bitSize(zcu);
20290 }
20291 try type_resolution.resolvePackedStructBackingInt(
20292 sema,
20293 block,
20294 field_bits,
20295 .fromInterned(wip_ty.index),
20296 &wip_struct_type,
20297 );
20298 } else {
20299 try type_resolution.finishStructLayout(
20300 sema,
20301 block,
20302 src,
20303 wip_ty.index,
20304 &wip_struct_type,
20305 );
20306 }
20249 const new_namespace_index = try pt.createNamespace(.{
20250 .parent = block.namespace.toOptional(),
20251 .owner_type = wip.index,
20252 .file_scope = block.getFileScopeIndex(zcu),
20253 .generation = zcu.generation,
20254 });
20255 try sema.addTypeReferenceEntry(src, .fromInterned(wip.index));
20256 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
20257 // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind
20258 try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) });
2030720259
20308 const new_namespace_index = try pt.createNamespace(.{
20309 .parent = block.namespace.toOptional(),
20310 .owner_type = wip_ty.index,
20311 .file_scope = block.getFileScopeIndex(zcu),
20312 .generation = zcu.generation,
20313 });
20260 try zcu.outdated.ensureUnusedCapacity(gpa, 1);
20261 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1);
20262 errdefer comptime unreachable; // because we don't remove the `outdated` entries
20263 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0);
20264 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {});
2031420265
20315 codegen_type: {
20316 if (zcu.comp.config.use_llvm) break :codegen_type;
20317 if (block.ownerModule().strip) break :codegen_type;
20318 zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
20319 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
20266 return .fromIntern(wip.finish(ip, new_namespace_index));
20267 },
2032020268 }
20321 try sema.addTypeReferenceEntry(src, .fromInterned(wip_ty.index));
20322 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
20323 return .fromIntern(wip_ty.finish(ip, new_namespace_index));
2032420269}
2032520270
2032620271fn zirReifyUnion(
......@@ -20390,7 +20335,10 @@ fn zirReifyUnion(
2039020335
2039120336 const arg_ty_uncoerced = try sema.resolveInst(extra.arg_ty);
2039220337 const arg_ty_coerced = try sema.coerce(block, .optional_type, arg_ty_uncoerced, arg_ty_src);
20393 const arg_ty_val = try sema.resolveConstDefinedValue(block, arg_ty_src, arg_ty_coerced, .{ .simple = .type });
20338 const arg_ty_val = try sema.resolveConstDefinedValue(block, arg_ty_src, arg_ty_coerced, switch (layout) {
20339 .@"packed" => .{ .simple = .packed_union_backing_int_type },
20340 .auto, .@"extern" => .{ .simple = .union_enum_tag_type },
20341 });
2039420342
2039520343 const field_names_uncoerced = try sema.resolveInst(extra.field_names);
2039620344 const field_names_coerced = try sema.coerce(block, .slice_const_slice_const_u8, field_names_uncoerced, field_names_src);
......@@ -20430,17 +20378,29 @@ fn zirReifyUnion(
2043020378 return sema.failWithUseOfUndef(block, arg_ty_src, null);
2043120379 }
2043220380
20433 // The validation work here is non-trivial, and it's possible the type already exists.
20434 // So in this first pass, let's just construct a hash to optimize for this case. If the
20435 // inputs turn out to be invalid, we can cancel the WIP type later.
20381 // Most validation of this type happens during type resolution. We basically need to do the work
20382 // which AstGen would normally do. An exception is checking for duplicate field names, which is
20383 // handled by type resolution---it just simplifies some logic a little.
20384
20385 // As well as validation, we're going to gather some information about the fields, and construct
20386 // a hash representing the inputs for deduplication purposes.
2043620387
20437 var any_aligned_fields = false;
20388 var any_field_aligns = false;
2043820389
20439 // For deduplication purposes, we must create a hash including all details of this type.
2044020390 // TODO: use a longer hash!
2044120391 var hasher = std.hash.Wyhash.init(0);
2044220392 std.hash.autoHash(&hasher, layout);
2044320393 std.hash.autoHash(&hasher, arg_ty_val);
20394
20395 const explicit_tag_ty: ?Type, const explicit_packed_backing_type: ?Type = ty: {
20396 const arg_ty = arg_ty_val.optionalValue(zcu) orelse break :ty .{ null, null };
20397 switch (layout) {
20398 .@"extern" => return sema.fail(block, arg_ty_src, "extern union does not support enum tag type", .{}),
20399 .@"packed" => break :ty .{ null, arg_ty.toType() },
20400 .auto => break :ty .{ arg_ty.toType(), null },
20401 }
20402 };
20403
2044420404 // `field_types_arr` and `field_attrs_arr` are already deduplicated by the InternPool!
2044520405 std.hash.autoHash(&hasher, field_types_arr);
2044620406 std.hash.autoHash(&hasher, field_attrs_arr);
......@@ -20457,249 +20417,84 @@ fn zirReifyUnion(
2045720417 try field_attrs_arr.elemValue(pt, field_idx),
2045820418 std.builtin.Type.UnionField.Attributes,
2045920419 );
20460 if (field_attrs.@"align" != null) {
20461 any_aligned_fields = true;
20462 }
20463 }
20464
20465 // Some basic validation to avoid a bogus `getUnionType` call...
20466 const explicit_tag_ty: ?Type, const explicit_packed_backing_type: ?Type = ty: {
20467 const arg_ty = arg_ty_val.optionalValue(zcu) orelse break :ty .{ null, null };
20468 switch (layout) {
20469 .@"extern" => return sema.fail(block, arg_ty_src, "extern union does not support enum tag type", .{}),
20470 .@"packed" => break :ty .{ null, arg_ty.toType() },
20471 .auto => break :ty .{ arg_ty.toType(), null },
20420 if (field_attrs.@"align") |bytes| {
20421 if (layout == .@"packed") {
20422 return sema.fail(block, field_attrs_src, "packed union fields cannot be aligned", .{});
20423 }
20424 // Trigger a compile error if the alignment is invalid.
20425 _ = try sema.validateAlign(block, field_attrs_src, bytes);
20426 any_field_aligns = true;
2047220427 }
20473 };
20474 if (any_aligned_fields and layout == .@"packed") {
20475 return sema.fail(block, field_attrs_src, "packed union fields cannot be aligned", .{});
2047620428 }
2047720429
20478 const wip_ty = switch (try ip.getUnionType(gpa, io, pt.tid, .{
20430 switch (try ip.getReifiedUnionType(gpa, io, pt.tid, .{
20431 .zir_index = tracked_inst,
20432 .type_hash = hasher.final(),
2047920433 .fields_len = @intCast(fields_len),
2048020434 .layout = layout,
20481 .explicit_packed_backing_type = if (explicit_packed_backing_type) |t| t.toIntern() else .none,
20435 .any_field_aligns = any_field_aligns,
2048220436 .runtime_tag = rt: {
2048320437 if (explicit_tag_ty != null) break :rt .tagged;
2048420438 if (layout == .auto and block.wantSafeTypes()) break :rt .safety;
2048520439 break :rt .none;
2048620440 },
20487 .have_explicit_enum_tag = explicit_tag_ty != null,
20488 .any_field_aligns = any_aligned_fields,
20489 .key = .{ .reified = .{
20490 .zir_index = tracked_inst,
20491 .type_hash = hasher.final(),
20492 } },
20441 .enum_tag_type = if (explicit_tag_ty) |ty| ty.toIntern() else .none,
20442 .packed_backing_int_type = if (explicit_packed_backing_type) |ty| ty.toIntern() else .none,
2049320443 })) {
20494 .wip => |wip| wip,
2049520444 .existing => |ty| {
2049620445 try sema.addTypeReferenceEntry(src, .fromInterned(ty));
2049720446 return .fromIntern(ty);
2049820447 },
20499 };
20500 errdefer wip_ty.cancel(ip, pt.tid);
20501
20502 const type_name = try (try sema.createTypeName(
20503 block,
20504 name_strategy,
20505 "union",
20506 inst,
20507 )).apply(&wip_ty, pt);
20508
20509 const loaded_union = ip.loadUnionType(wip_ty.index);
20510
20511 const generated_tag_ty: InternPool.Index = if (explicit_tag_ty) |enum_tag_ty| generated_tag: {
20512 if (enum_tag_ty.zigTypeTag(zcu) != .@"enum") {
20513 return sema.fail(block, arg_ty_src, "tag type must be an enum type", .{});
20514 }
20515
20516 const tag_ty_fields_len = enum_tag_ty.enumFieldCount(zcu);
20448 .wip => |wip| {
20449 errdefer wip.cancel(ip, pt.tid);
20450 try sema.setTypeName(block, &wip, name_strategy, "union", inst);
2051720451
20518 for (0..fields_len) |field_idx| {
20519 const field_name_val = try field_names_arr.elemValue(pt, field_idx);
20520 // Don't pass a reason; first loop acts as a check that this is valid.
20521 const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined);
20452 for (0..fields_len) |field_idx| {
20453 const field_name_val = try field_names_arr.elemValue(pt, field_idx);
20454 // No source location or reason; first loop checked this is valid.
20455 const field_name = try sema.sliceToIpString(block, .unneeded, field_name_val, undefined);
20456 wip.field_names.get(ip)[field_idx] = field_name;
2052220457
20523 if (field_idx >= tag_ty_fields_len) {
20524 return sema.fail(block, field_names_src, "no field named '{f}' in enum '{f}'", .{
20525 field_name.fmt(ip), enum_tag_ty.fmt(pt),
20526 });
20527 }
20458 const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType();
20459 wip.field_types.get(ip)[field_idx] = field_ty.toIntern();
2052820460
20529 const enum_field_name = enum_tag_ty.enumFieldName(field_idx, zcu);
20530 if (enum_field_name != field_name) {
20531 return sema.fail(block, field_names_src, "union field name '{f}' does not match enum field name '{f}'", .{
20532 field_name.fmt(ip), enum_field_name.fmt(ip),
20533 });
20534 }
20535 }
20536 if (tag_ty_fields_len > fields_len) return sema.failWithOwnedErrorMsg(block, msg: {
20537 const msg = try sema.errMsg(field_names_src, "{d} enum fields missing in union", .{
20538 tag_ty_fields_len - fields_len,
20539 });
20540 errdefer msg.destroy(gpa);
20541 for (fields_len..tag_ty_fields_len) |enum_field_idx| {
20542 try sema.addFieldErrNote(enum_tag_ty, enum_field_idx, msg, "field '{f}' missing, declared here", .{
20543 enum_tag_ty.enumFieldName(enum_field_idx, zcu).fmt(ip),
20544 });
20461 // No source location; first loop checked this is valid.
20462 const field_attrs = try sema.interpretBuiltinType(
20463 block,
20464 .unneeded,
20465 try field_attrs_arr.elemValue(pt, field_idx),
20466 std.builtin.Type.UnionField.Attributes,
20467 );
20468 if (field_attrs.@"align") |bytes| {
20469 // No source location; first loop checked this is valid.
20470 const a = try sema.validateAlign(block, .unneeded, bytes);
20471 wip.field_aligns.get(ip)[field_idx] = a;
20472 } else if (any_field_aligns) {
20473 wip.field_aligns.get(ip)[field_idx] = .none;
20474 }
2054520475 }
20546 try sema.addDeclaredHereNote(msg, enum_tag_ty);
20547 break :msg msg;
20548 });
20549 wip_ty.setTagType(ip, enum_tag_ty.toIntern());
20550 break :generated_tag .none;
20551 } else generated_tag: {
20552 // Generate the union's hypothetical tag type.
20553 const wip_tag_ty = switch (try ip.getEnumType(gpa, io, pt.tid, .{
20554 .fields_len = @intCast(fields_len),
20555 .explicit_int_tag_type = .none,
20556 .nonexhaustive = false,
20557 .key = .{ .generated_union_tag = wip_ty.index },
20558 })) {
20559 .existing => unreachable, // enum type is keyed on this union type which we're only just creating
20560 .wip => |wip_tag_ty| wip_tag_ty,
20561 };
20562 errdefer wip_tag_ty.cancel(ip, pt.tid);
20563
20564 // Set its name based on the union's name
20565 _ = wip_tag_ty.setName(ip, try ip.getOrPutStringFmt(
20566 gpa,
20567 io,
20568 pt.tid,
20569 "@typeInfo({f}).@\"union\".tag_type.?",
20570 .{type_name.fmt(ip)},
20571 .no_embedded_nulls,
20572 ), .none);
20573
20574 // Populate its fields (and report any duplicates)
20575 for (0..fields_len) |field_idx| {
20576 const field_name_val = try field_names_arr.elemValue(pt, field_idx);
20577 // Don't pass a reason; first loop acts as a check that this is valid.
20578 const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined);
20579 if (wip_tag_ty.nextField(ip, field_name, false)) |prev_field_idx| return sema.failWithOwnedErrorMsg(block, msg: {
20580 const msg = try sema.errMsg(src, "duplicate union field '{f}' at index '{d}", .{ field_name.fmt(ip), field_idx });
20581 errdefer msg.destroy(gpa);
20582 try sema.errNote(src, msg, "previous field at index '{d}'", .{prev_field_idx});
20583 break :msg msg;
20584 });
20585 }
20586
20587 // Populate the enum tag type's *integer* tag type
20588 wip_tag_ty.setTagType(ip, int_tag_ty: {
20589 // Infer the int tag type from the field count
20590 const bits = Type.smallestUnsignedBits(fields_len -| 1);
20591 break :int_tag_ty (try pt.intType(.unsigned, bits)).toIntern();
20592 });
20593
20594 // Lastly, it needs a dummy namespace
20595 const enum_tag_type_namespace = try pt.createNamespace(.{
20596 .parent = block.namespace.toOptional(),
20597 .owner_type = wip_tag_ty.index,
20598 .file_scope = block.getFileScopeIndex(zcu),
20599 .generation = zcu.generation,
20600 });
20601 errdefer pt.destroyNamespace(enum_tag_type_namespace);
20602
20603 wip_ty.setTagType(ip, wip_tag_ty.index);
20604
20605 break :generated_tag wip_tag_ty.finish(ip, enum_tag_type_namespace);
20606 };
20607 // If we fail to create the union type, we must delete the generated enum tag type, since it
20608 // would hold a reference to the deleted union.
20609 errdefer if (generated_tag_ty != .none) ip.remove(pt.tid, generated_tag_ty);
20610
20611 for (0..fields_len) |field_idx| {
20612 const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType();
20613 const field_attrs = try sema.interpretBuiltinType(
20614 block,
20615 field_attrs_src,
20616 try field_attrs_arr.elemValue(pt, field_idx),
20617 std.builtin.Type.UnionField.Attributes,
20618 );
2061920476
20620 if (field_ty.zigTypeTag(zcu) == .@"opaque") {
20621 return sema.failWithOwnedErrorMsg(block, msg: {
20622 const msg = try sema.errMsg(field_types_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{});
20623 errdefer msg.destroy(gpa);
20624 try sema.addDeclaredHereNote(msg, field_ty);
20625 break :msg msg;
20477 const new_namespace_index = try pt.createNamespace(.{
20478 .parent = block.namespace.toOptional(),
20479 .owner_type = wip.index,
20480 .file_scope = block.getFileScopeIndex(zcu),
20481 .generation = zcu.generation,
2062620482 });
20627 }
20628
20629 switch (layout) {
20630 .auto => {},
20631 .@"extern" => if (!try sema.validateExternType(field_ty, .union_field)) {
20632 return sema.failWithOwnedErrorMsg(block, msg: {
20633 const msg = try sema.errMsg(field_types_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
20634 errdefer msg.destroy(gpa);
20635
20636 try sema.explainWhyTypeIsNotExtern(msg, field_types_src, field_ty, .union_field);
20637
20638 try sema.addDeclaredHereNote(msg, field_ty);
20639 break :msg msg;
20640 });
20641 },
20642 .@"packed" => if (!field_ty.packable(zcu)) {
20643 return sema.failWithOwnedErrorMsg(block, msg: {
20644 const msg = try sema.errMsg(field_types_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
20645 errdefer msg.destroy(gpa);
20646
20647 try sema.explainWhyTypeIsNotPackable(msg, field_types_src, field_ty);
20648
20649 try sema.addDeclaredHereNote(msg, field_ty);
20650 break :msg msg;
20651 });
20652 },
20653 }
20654
20655 loaded_union.field_types.get(ip)[field_idx] = field_ty.toIntern();
20656 if (field_attrs.@"align") |bytes| {
20657 assert(layout != .@"packed");
20658 const a = try sema.validateAlign(block, field_attrs_src, bytes);
20659 loaded_union.field_aligns.get(ip)[field_idx] = a;
20660 } else if (any_aligned_fields) {
20661 assert(layout != .@"packed");
20662 loaded_union.field_aligns.get(ip)[field_idx] = .none;
20663 }
20664 }
20483 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
20484 try sema.addTypeReferenceEntry(src, .fromInterned(wip.index));
2066520485
20666 if (layout == .@"packed") {
20667 try type_resolution.resolvePackedUnionBackingInt(
20668 sema,
20669 block,
20670 .fromInterned(wip_ty.index),
20671 &loaded_union,
20672 true,
20673 );
20674 } else {
20675 try type_resolution.finishUnionLayout(
20676 sema,
20677 block,
20678 src,
20679 wip_ty.index,
20680 &loaded_union,
20681 explicit_tag_ty orelse .fromInterned(generated_tag_ty),
20682 );
20683 }
20486 // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind
20487 try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) });
2068420488
20685 const new_namespace_index = try pt.createNamespace(.{
20686 .parent = block.namespace.toOptional(),
20687 .owner_type = wip_ty.index,
20688 .file_scope = block.getFileScopeIndex(zcu),
20689 .generation = zcu.generation,
20690 });
20489 try zcu.outdated.ensureUnusedCapacity(gpa, 1);
20490 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1);
20491 errdefer comptime unreachable; // because we don't remove the `outdated` entry
20492 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0);
20493 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {});
2069120494
20692 codegen_type: {
20693 if (zcu.comp.config.use_llvm) break :codegen_type;
20694 if (block.ownerModule().strip) break :codegen_type;
20695 zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
20696 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
20697 }
20698 try sema.addTypeReferenceEntry(src, .fromInterned(wip_ty.index));
20699 if (zcu.comp.debugIncremental()) {
20700 try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
20495 return .fromIntern(wip.finish(ip, new_namespace_index));
20496 },
2070120497 }
20702 return .fromIntern(wip_ty.finish(ip, new_namespace_index));
2070320498}
2070420499
2070520500fn zirReifyEnum(
......@@ -20754,10 +20549,10 @@ fn zirReifyEnum(
2075420549
2075520550 const enum_mode_ty = try sema.getBuiltinType(mode_src, .@"Type.Enum.Mode");
2075620551
20757 const tag_ty = try sema.resolveType(block, tag_ty_src, extra.tag_ty);
20758 if (tag_ty.zigTypeTag(zcu) != .int) {
20759 return sema.fail(block, tag_ty_src, "tag type must be an integer type", .{});
20760 }
20552 const tag_ty_uncoerced = try sema.resolveInst(extra.tag_ty);
20553 const tag_ty_coerced = try sema.coerce(block, .type, tag_ty_uncoerced, tag_ty_src);
20554 const tag_ty_val = try sema.resolveConstDefinedValue(block, tag_ty_src, tag_ty_coerced, .{ .simple = .enum_int_tag_type });
20555 const tag_ty = tag_ty_val.toType();
2076120556
2076220557 const mode_uncoerced = try sema.resolveInst(extra.mode);
2076320558 const mode_coerced = try sema.coerce(block, enum_mode_ty, mode_uncoerced, mode_src);
......@@ -20790,11 +20585,13 @@ fn zirReifyEnum(
2079020585 }
2079120586 // We don't need to check `field_names_arr`, because `sliceToIpString` will check that for us.
2079220587
20793 // The validation work here is non-trivial, and it's possible the type already exists.
20794 // So in this first pass, let's just construct a hash to optimize for this case. If the
20795 // inputs turn out to be invalid, we can cancel the WIP type later.
20588 // Most validation of this type happens during type resolution. We basically need to do the work
20589 // which AstGen would normally do. An exception is checking for duplicate field names, which is
20590 // handled by type resolution---it just simplifies some logic a little.
20591
20592 // As well as validation, we're going to gather some information about the fields, and construct
20593 // a hash representing the inputs for deduplication purposes.
2079620594
20797 // For deduplication purposes, we must create a hash including all details of this type.
2079820595 // TODO: use a longer hash!
2079920596 var hasher = std.hash.Wyhash.init(0);
2080020597 std.hash.autoHash(&hasher, tag_ty.toIntern());
......@@ -20810,85 +20607,55 @@ fn zirReifyEnum(
2081020607 std.hash.autoHash(&hasher, field_name);
2081120608 }
2081220609
20813 const wip_ty = switch (try ip.getEnumType(gpa, io, pt.tid, .{
20610 switch (try ip.getReifiedEnumType(gpa, io, pt.tid, .{
20611 .zir_index = tracked_inst,
20612 .type_hash = hasher.final(),
2081420613 .fields_len = @intCast(fields_len),
20815 .explicit_int_tag_type = tag_ty.toIntern(),
2081620614 .nonexhaustive = nonexhaustive,
20817 .key = .{ .reified = .{
20818 .zir_index = tracked_inst,
20819 .type_hash = hasher.final(),
20820 } },
20615 .int_tag_type = tag_ty.toIntern(),
2082120616 })) {
20822 .wip => |wip| wip,
2082320617 .existing => |ty| {
2082420618 try sema.addTypeReferenceEntry(src, .fromInterned(ty));
2082520619 return .fromIntern(ty);
2082620620 },
20827 };
20828 errdefer wip_ty.cancel(ip, pt.tid);
20621 .wip => |wip| {
20622 errdefer wip.cancel(ip, pt.tid);
2082920623
20830 _ = try (try sema.createTypeName(
20831 block,
20832 name_strategy,
20833 "enum",
20834 inst,
20835 )).apply(&wip_ty, pt);
20624 try sema.setTypeName(block, &wip, name_strategy, "enum", inst);
2083620625
20837 for (0..fields_len) |field_idx| {
20838 const field_name_val = try field_names_arr.elemValue(pt, field_idx);
20839 // Don't pass a reason; first loop acts as a check that this is valid.
20840 const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined);
20841 if (wip_ty.nextField(ip, field_name, false)) |prev_field_idx| return sema.failWithOwnedErrorMsg(block, msg: {
20842 const msg = try sema.errMsg(field_names_src, "duplicate enum field '{f}' at index '{d}'", .{ field_name.fmt(ip), field_idx });
20843 errdefer msg.destroy(gpa);
20844 try sema.errNote(field_names_src, msg, "previous field at index '{d}'", .{prev_field_idx});
20845 break :msg msg;
20846 });
20847 }
20626 // Populate field names and values. Duplicate checking will be handled by type resolution.
20627 for (0..fields_len) |field_index| {
20628 const field_name_val = try field_names_arr.elemValue(pt, field_index);
20629 // No source location or reason; first loop checked this is valid.
20630 const field_name = try sema.sliceToIpString(block, .unneeded, field_name_val, undefined);
20631 wip.field_names.get(ip)[field_index] = field_name;
2084820632
20849 const enum_obj = ip.loadEnumType(wip_ty.index);
20850 const field_value_map = enum_obj.field_value_map.unwrap().?;
20851 for (0..fields_len) |field_idx| {
20852 const field_val = try field_values_arr.elemValue(pt, field_idx);
20853 const field_values = enum_obj.field_values.get(ip);
20854 field_values[field_idx] = field_val.toIntern();
20855 const adapter: InternPool.Index.Adapter = .{ .indexes = field_values[0..field_idx] };
20856 const gop = field_value_map.get(ip).getOrPutAssumeCapacityAdapted(field_val.toIntern(), adapter);
20857 if (gop.found_existing) return sema.failWithOwnedErrorMsg(block, msg: {
20858 const field_names = enum_obj.field_names.get(ip);
20859 const this_field_name = field_names[field_idx];
20860 const prev_field_name = field_names[gop.index];
20861 const msg = try sema.errMsg(field_names_src, "duplicate enum tag value '{f}' in field '{f}'", .{
20862 field_val.fmtValueSema(pt, sema),
20863 this_field_name.fmt(ip),
20633 const field_val = try field_values_arr.elemValue(pt, field_index);
20634 wip.field_values.get(ip)[field_index] = field_val.toIntern();
20635 }
20636
20637 const new_namespace_index = try pt.createNamespace(.{
20638 .parent = block.namespace.toOptional(),
20639 .owner_type = wip.index,
20640 .file_scope = block.getFileScopeIndex(zcu),
20641 .generation = zcu.generation,
2086420642 });
20865 errdefer msg.destroy(gpa);
20866 try sema.errNote(field_names_src, msg, "previous usage in field '{f}'", .{prev_field_name.fmt(ip)});
20867 break :msg msg;
20868 });
20869 }
2087020643
20871 if (nonexhaustive and fields_len > 1 and std.math.log2_int(u64, fields_len) == tag_ty.bitSize(zcu)) {
20872 return sema.fail(block, src, "non-exhaustive enum specified every value", .{});
20873 }
20644 try sema.addTypeReferenceEntry(src, .fromInterned(wip.index));
20645 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
2087420646
20875 const new_namespace_index = try pt.createNamespace(.{
20876 .parent = block.namespace.toOptional(),
20877 .owner_type = wip_ty.index,
20878 .file_scope = block.getFileScopeIndex(zcu),
20879 .generation = zcu.generation,
20880 });
20647 // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind
20648 try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) });
2088120649
20882 codegen_type: {
20883 if (zcu.comp.config.use_llvm) break :codegen_type;
20884 if (block.ownerModule().strip) break :codegen_type;
20885 zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
20886 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
20887 }
20650 try zcu.outdated.ensureUnusedCapacity(gpa, 1);
20651 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1);
20652 errdefer comptime unreachable; // because we don't remove the `outdated` entry
20653 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0);
20654 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {});
2088820655
20889 try sema.addTypeReferenceEntry(src, .fromInterned(wip_ty.index));
20890 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
20891 return .fromIntern(wip_ty.finish(ip, new_namespace_index));
20656 return .fromIntern(wip.finish(ip, new_namespace_index));
20657 },
20658 }
2089220659}
2089320660
2089420661fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref {
......@@ -20909,7 +20676,7 @@ fn zirCVaArg(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C
2090920676 const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.lhs);
2091020677 const arg_ty = try sema.resolveType(block, ty_src, extra.rhs);
2091120678
20912 if (!try sema.validateExternType(arg_ty, .param_ty)) {
20679 if (!arg_ty.validateExtern(.param_ty, sema.pt.zcu)) {
2091320680 const msg = msg: {
2091420681 const msg = try sema.errMsg(ty_src, "cannot get '{f}' from variadic argument", .{arg_ty.fmt(sema.pt)});
2091520682 errdefer msg.destroy(sema.gpa);
......@@ -24205,8 +23972,8 @@ fn zirMemcpy(
2420523972 return sema.failWithOwnedErrorMsg(block, msg);
2420623973 }
2420723974
24208 const dest_elem_ty = dest_ty.indexablePtrElem(zcu);
24209 const src_elem_ty = src_ty.indexablePtrElem(zcu);
23975 const dest_elem_ty = dest_ty.indexableElem(zcu);
23976 const src_elem_ty = src_ty.indexableElem(zcu);
2421023977
2421123978 try sema.ensureLayoutResolved(dest_elem_ty);
2421223979 try sema.ensureLayoutResolved(src_elem_ty);
......@@ -24906,7 +24673,7 @@ fn zirBuiltinExtern(
2490624673 if (!ty.isPtrAtRuntime(zcu)) {
2490724674 return sema.fail(block, ty_src, "expected (optional) pointer", .{});
2490824675 }
24909 if (!try sema.validateExternType(ty, .other)) {
24676 if (!ty.validateExtern(.other, zcu)) {
2491024677 const msg = msg: {
2491124678 const msg = try sema.errMsg(ty_src, "extern symbol cannot have type '{f}'", .{ty.fmt(pt)});
2491224679 errdefer msg.destroy(sema.gpa);
......@@ -24954,7 +24721,7 @@ fn zirBuiltinExtern(
2495424721 // So, for now, just use our containing `declaration`.
2495524722 .zir_index = switch (sema.owner.unwrap()) {
2495624723 .@"comptime" => |cu| ip.getComptimeUnit(cu).zir_index,
24957 .type_layout, .type_inits => |owner_ty| Type.fromInterned(owner_ty).typeDeclInstAllowGeneratedTag(zcu).?,
24724 .type_layout, .struct_defaults => |owner_ty| Type.fromInterned(owner_ty).typeDeclInstAllowGeneratedTag(zcu).?,
2495824725 .memoized_state => unreachable,
2495924726 .nav_ty, .nav_val => |nav| ip.getNav(nav).analysis.?.zir_index,
2496024727 .func => |func| zir_index: {
......@@ -25060,6 +24827,7 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
2506024827 // Values are handled here.
2506124828 .calling_convention_c => {
2506224829 const callconv_ty = try sema.getBuiltinType(src, .CallingConvention);
24830 // Cannot use `Value.uninterpret` because `c` is a *declaration* whose value depends on the target.
2506324831 return try sema.namespaceLookupVal(
2506424832 block,
2506524833 src,
......@@ -25068,17 +24836,15 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
2506824836 ) orelse @panic("std.builtin is corrupt");
2506924837 },
2507024838 .calling_convention_inline => {
25071 comptime assert(@typeInfo(std.builtin.CallingConvention.Tag).@"enum".tag_type == u8);
2507224839 const callconv_ty = try sema.getBuiltinType(src, .CallingConvention);
25073 const callconv_tag_ty = callconv_ty.unionTagType(zcu) orelse @panic("std.builtin is corrupt");
25074 const inline_tag_val = try pt.enumValue(
25075 callconv_tag_ty,
25076 (try pt.intValue(
25077 .u8,
25078 @intFromEnum(std.builtin.CallingConvention.@"inline"),
25079 )).toIntern(),
25080 );
25081 return sema.coerce(block, callconv_ty, Air.internedToRef(inline_tag_val.toIntern()), src);
24840 return .fromValue(Value.uninterpret(
24841 @as(std.builtin.CallingConvention, .@"inline"),
24842 callconv_ty,
24843 pt,
24844 ) catch |err| switch (err) {
24845 error.TypeMismatch => @panic("std.builtin is corrupt"),
24846 error.OutOfMemory => |e| return e,
24847 });
2508224848 },
2508324849 };
2508424850 return .fromType(try sema.getBuiltinType(src, builtin_type));
......@@ -25180,7 +24946,7 @@ pub fn validateVarType(
2518024946 const zcu = pt.zcu;
2518124947 var_ty.assertHasLayout(zcu);
2518224948 if (is_extern) {
25183 if (!try sema.validateExternType(var_ty, .other)) {
24949 if (!var_ty.validateExtern(.other, zcu)) {
2518424950 const msg = msg: {
2518524951 const msg = try sema.errMsg(src, "extern variable cannot have type '{f}'", .{var_ty.fmt(pt)});
2518624952 errdefer msg.destroy(sema.gpa);
......@@ -25296,124 +25062,17 @@ fn explainWhyTypeIsComptime(
2529625062 }
2529725063}
2529825064
25299const ExternPosition = enum {
25300 ret_ty,
25301 param_ty,
25302 union_field,
25303 struct_field,
25304 element,
25305 other,
25306};
25307
25308/// Returns true if `ty` is allowed in extern types.
25309/// Does not require `ty` to be resolved in any way.
25310pub fn validateExternType(
25311 sema: *Sema,
25312 ty: Type,
25313 position: ExternPosition,
25314) !bool {
25315 const pt = sema.pt;
25316 const zcu = pt.zcu;
25317 switch (ty.zigTypeTag(zcu)) {
25318 .type,
25319 .comptime_float,
25320 .comptime_int,
25321 .enum_literal,
25322 .undefined,
25323 .null,
25324 .error_union,
25325 .error_set,
25326 .frame,
25327 => return false,
25328 .void => return switch (position) {
25329 .ret_ty,
25330 .union_field,
25331 .struct_field,
25332 .element,
25333 => true,
25334 .param_ty,
25335 .other,
25336 => false,
25337 },
25338 .noreturn => return position == .ret_ty,
25339 .@"opaque",
25340 .bool,
25341 .float,
25342 .@"anyframe",
25343 => return true,
25344 .pointer => {
25345 if (ty.isSlice(zcu)) return false;
25346 const child_ty = ty.childType(zcu);
25347 if (child_ty.zigTypeTag(zcu) == .@"fn") {
25348 return ty.isConstPtr(zcu) and try sema.validateExternType(child_ty, .other);
25349 }
25350 return true;
25351 },
25352 .int => switch (ty.intInfo(zcu).bits) {
25353 0, 8, 16, 32, 64, 128 => return true,
25354 else => return false,
25355 },
25356 .@"fn" => {
25357 if (position != .other) return false;
25358 // For now we want to authorize PTX kernel to use zig objects, even if we end up exposing the ABI.
25359 // The goal is to experiment with more integrated CPU/GPU code.
25360 if (ty.fnCallingConvention(zcu) == .nvptx_kernel) {
25361 return true;
25362 }
25363 return !target_util.fnCallConvAllowsZigTypes(ty.fnCallingConvention(zcu));
25364 },
25365 .@"enum" => {
25366 const enum_obj = zcu.intern_pool.loadEnumType(ty.toIntern());
25367 if (!enum_obj.int_tag_is_explicit) return false;
25368 return sema.validateExternType(.fromInterned(enum_obj.int_tag_type), position);
25369 },
25370 .@"struct" => {
25371 const struct_obj = zcu.intern_pool.loadStructType(ty.toIntern());
25372 return switch (struct_obj.layout) {
25373 .auto => false,
25374 .@"extern" => true,
25375 .@"packed" => switch (struct_obj.packed_backing_mode) {
25376 .auto => false,
25377 .explicit => try sema.validateExternType(.fromInterned(struct_obj.packed_backing_int_type), position),
25378 },
25379 };
25380 },
25381 .@"union" => {
25382 const union_obj = zcu.intern_pool.loadUnionType(ty.toIntern());
25383 return switch (union_obj.layout) {
25384 .auto => false,
25385 .@"extern" => true,
25386 .@"packed" => switch (union_obj.packed_backing_mode) {
25387 .auto => false,
25388 .explicit => try sema.validateExternType(.fromInterned(union_obj.packed_backing_int_type), position),
25389 },
25390 };
25391 },
25392 .array => {
25393 if (position == .ret_ty or position == .param_ty) return false;
25394 return sema.validateExternType(ty.childType(zcu), .element);
25395 },
25396 .vector => return sema.validateExternType(ty.childType(zcu), .element),
25397 .optional => return ty.isPtrLikeOptional(zcu),
25398 }
25399}
25400
25065/// Keep in sync with `Type.validateExtern`.
2540125066pub fn explainWhyTypeIsNotExtern(
2540225067 sema: *Sema,
2540325068 msg: *Zcu.ErrorMsg,
2540425069 src_loc: LazySrcLoc,
2540525070 ty: Type,
25406 position: ExternPosition,
25071 position: Type.ExternPosition,
2540725072) CompileError!void {
2540825073 const pt = sema.pt;
2540925074 const zcu = pt.zcu;
2541025075 switch (ty.zigTypeTag(zcu)) {
25411 .@"opaque",
25412 .bool,
25413 .float,
25414 .@"anyframe",
25415 => return,
25416
2541725076 .type,
2541825077 .comptime_float,
2541925078 .comptime_int,
......@@ -25425,101 +25084,110 @@ pub fn explainWhyTypeIsNotExtern(
2542525084 .frame,
2542625085 => return,
2542725086
25428 .pointer => {
25429 if (ty.isSlice(zcu)) {
25430 try sema.errNote(src_loc, msg, "slices have no guaranteed in-memory representation", .{});
25087 .void => try sema.errNote(src_loc, msg, "'void' is a zero bit type", .{}),
25088 .noreturn => try sema.errNote(src_loc, msg, "'noreturn' is only allowed as a return type", .{}),
25089
25090 .@"opaque",
25091 .bool,
25092 .float,
25093 .@"anyframe",
25094 => unreachable, // these *are* allowed
25095
25096 .pointer => if (ty.isSlice(zcu)) {
25097 try sema.errNote(src_loc, msg, "slices have no guaranteed in-memory representation", .{});
25098 } else {
25099 assert(ty.childType(zcu).zigTypeTag(zcu) == .@"fn");
25100 if (!ty.isConstPtr(zcu)) {
25101 try sema.errNote(src_loc, msg, "pointer to extern function must be 'const'", .{});
2543125102 } else {
25432 const pointee_ty = ty.childType(zcu);
25433 if (!ty.isConstPtr(zcu) and pointee_ty.zigTypeTag(zcu) == .@"fn") {
25434 try sema.errNote(src_loc, msg, "pointer to extern function must be 'const'", .{});
25435 }
25436 try sema.explainWhyTypeIsNotExtern(msg, src_loc, pointee_ty, .other);
25103 try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.childType(zcu), .other);
2543725104 }
2543825105 },
25439 .void => try sema.errNote(src_loc, msg, "'void' is a zero bit type; for C 'void' use 'anyopaque'", .{}),
25440 .noreturn => try sema.errNote(src_loc, msg, "'noreturn' is only allowed as a return type", .{}),
2544125106 .int => if (!std.math.isPowerOfTwo(ty.intInfo(zcu).bits)) {
2544225107 try sema.errNote(src_loc, msg, "only integers with 0 or power of two bits are extern compatible", .{});
2544325108 } else {
2544425109 try sema.errNote(src_loc, msg, "only integers with 0, 8, 16, 32, 64 and 128 bits are extern compatible", .{});
2544525110 },
25446 .@"fn" => {
25447 if (position != .other) {
25448 try sema.errNote(src_loc, msg, "type has no guaranteed in-memory representation", .{});
25449 try sema.errNote(src_loc, msg, "use '*const ' to make a function pointer type", .{});
25450 return;
25451 }
25452 switch (ty.fnCallingConvention(zcu)) {
25453 .auto => try sema.errNote(src_loc, msg, "extern function must specify calling convention", .{}),
25454 .async => try sema.errNote(src_loc, msg, "async function cannot be extern", .{}),
25455 .@"inline" => try sema.errNote(src_loc, msg, "inline function cannot be extern", .{}),
25456 else => return,
25457 }
25111 .@"fn" => if (position != .other) {
25112 try sema.errNote(src_loc, msg, "type has no guaranteed in-memory representation", .{});
25113 try sema.errNote(src_loc, msg, "use '*const ' to make a function pointer type", .{});
25114 } else switch (ty.fnCallingConvention(zcu)) {
25115 .auto => try sema.errNote(src_loc, msg, "extern function must specify calling convention", .{}),
25116 else => |cc| try sema.errNote(src_loc, msg, "{t} function cannot be extern", .{cc}),
2545825117 },
2545925118 .@"enum" => {
2546025119 const tag_ty = ty.intTagType(zcu);
2546125120 try sema.errNote(src_loc, msg, "enum tag type '{f}' is not extern compatible", .{tag_ty.fmt(pt)});
2546225121 try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position);
2546325122 },
25464 // MLUGG TODO: these notes are bad now (because ABI sized packed type also needs explicit backing type)
25465 .@"struct" => try sema.errNote(src_loc, msg, "only extern structs and ABI sized packed structs are extern compatible", .{}),
25466 .@"union" => try sema.errNote(src_loc, msg, "only extern unions and ABI sized packed unions are extern compatible", .{}),
25467 .array => {
25468 if (position == .ret_ty) {
25469 return sema.errNote(src_loc, msg, "arrays are not allowed as a return type", .{});
25470 } else if (position == .param_ty) {
25471 return sema.errNote(src_loc, msg, "arrays are not allowed as a parameter type", .{});
25123 .@"struct" => {
25124 const struct_obj = zcu.intern_pool.loadStructType(ty.toIntern());
25125 switch (struct_obj.layout) {
25126 .auto => try sema.errNote(src_loc, msg, "struct with automatic layout has no guaranteed in-memory representation", .{}),
25127 .@"extern" => unreachable,
25128 .@"packed" => switch (struct_obj.packed_backing_mode) {
25129 .auto => try sema.errNote(src_loc, msg, "inferred backing integer of packed struct has unspecified signedness", .{}),
25130 .explicit => {
25131 const backing_int_ty: Type = .fromInterned(struct_obj.packed_backing_int_type);
25132 try sema.errNote(src_loc, msg, "packed struct backing integer type '{f}' is not extern compatible", .{backing_int_ty.fmt(pt)});
25133 try sema.explainWhyTypeIsNotExtern(msg, src_loc, backing_int_ty, position);
25134 },
25135 },
25136 }
25137 },
25138 .@"union" => {
25139 const union_obj = zcu.intern_pool.loadStructType(ty.toIntern());
25140 switch (union_obj.layout) {
25141 .auto => try sema.errNote(src_loc, msg, "union with automatic layout has no guaranteed in-memory representation", .{}),
25142 .@"extern" => unreachable,
25143 .@"packed" => switch (union_obj.packed_backing_mode) {
25144 .auto => try sema.errNote(src_loc, msg, "inferred backing integer of packed union has unspecified signedness", .{}),
25145 .explicit => {
25146 const backing_int_ty: Type = .fromInterned(union_obj.packed_backing_int_type);
25147 try sema.errNote(src_loc, msg, "packed union backing integer type '{f}' is not extern compatible", .{backing_int_ty.fmt(pt)});
25148 try sema.explainWhyTypeIsNotExtern(msg, src_loc, backing_int_ty, position);
25149 },
25150 },
2547225151 }
25473 try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.childType(zcu), .element);
25152 },
25153 .array => switch (position) {
25154 .ret_ty => try sema.errNote(src_loc, msg, "arrays are not allowed as a return type", .{}),
25155 .param_ty => try sema.errNote(src_loc, msg, "arrays are not allowed as a parameter type", .{}),
25156 else => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.childType(zcu), .element),
2547425157 },
2547525158 .vector => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.childType(zcu), .element),
25476 .optional => try sema.errNote(src_loc, msg, "only pointer like optionals are extern compatible", .{}),
25159 .optional => try sema.errNote(src_loc, msg, "non-pointer optionals have no guaranteed in-memory representation", .{}),
2547725160 }
2547825161}
2547925162
25480pub fn explainWhyTypeIsNotPackable(
25163pub fn explainWhyTypeIsUnpackable(
2548125164 sema: *Sema,
2548225165 msg: *Zcu.ErrorMsg,
25483 src_loc: LazySrcLoc,
25484 ty: Type,
25166 src: LazySrcLoc,
25167 reason: Type.UnpackableReason,
2548525168) CompileError!void {
2548625169 const pt = sema.pt;
2548725170 const zcu = pt.zcu;
25488 switch (ty.zigTypeTag(zcu)) {
25489 .void,
25490 .bool,
25491 .float,
25492 .int,
25493 .vector,
25494 .@"enum",
25495 => return,
25496 .type,
25497 .comptime_float,
25498 .comptime_int,
25499 .enum_literal,
25500 .undefined,
25501 .null,
25502 .frame,
25503 .noreturn,
25504 .@"opaque",
25505 .error_union,
25506 .error_set,
25507 .@"anyframe",
25508 .optional,
25509 .array,
25510 => try sema.errNote(src_loc, msg, "type has no guaranteed in-memory representation", .{}),
25511 .pointer => if (ty.isSlice(zcu)) {
25512 try sema.errNote(src_loc, msg, "slices have no guaranteed in-memory representation", .{});
25513 } else {
25514 try sema.errNote(src_loc, msg, "comptime-only pointer has no guaranteed in-memory representation", .{});
25515 try sema.explainWhyTypeIsComptime(msg, src_loc, ty);
25171 switch (reason) {
25172 .comptime_only => try sema.errNote(src, msg, "comptime-only types have no bit-packed representation", .{}),
25173 .pointer => {
25174 try sema.errNote(src, msg, "pointers cannot be directly bitpacked", .{});
25175 try sema.errNote(src, msg, "consider using 'usize' and '@intFromPtr'", .{});
2551625176 },
25517 .@"fn" => {
25518 try sema.errNote(src_loc, msg, "type has no guaranteed in-memory representation", .{});
25519 try sema.errNote(src_loc, msg, "use '*const ' to make a function pointer type", .{});
25177 .enum_inferred_int_tag => |enum_ty| {
25178 const enum_src = enum_ty.srcLoc(zcu);
25179 try sema.errNote(enum_src, msg, "integer tag type of enum is inferred", .{});
25180 try sema.errNote(enum_src, msg, "consider explicitly specifying the integer tag type", .{});
25181 },
25182 .non_packed_struct => |struct_ty| {
25183 try sema.errNote(src, msg, "non-packed structs do not have a bit-packed representation", .{});
25184 try sema.addDeclaredHereNote(msg, struct_ty);
25185 },
25186 .non_packed_union => |union_ty| {
25187 try sema.errNote(src, msg, "non-packed unions do not have a bit-packed representation", .{});
25188 try sema.addDeclaredHereNote(msg, union_ty);
2552025189 },
25521 .@"struct" => try sema.errNote(src_loc, msg, "struct in packed type must have packed layout", .{}),
25522 .@"union" => try sema.errNote(src_loc, msg, "union in packed type must have packed layout", .{}),
25190 .other => try sema.errNote(src, msg, "type does not have a bit-packed representation", .{}),
2552325191 }
2552425192}
2552525193
......@@ -25545,7 +25213,7 @@ fn getPanicIdFunc(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.SimplePanicId) !In
2554525213 try sema.ensureMemoizedStateResolved(src, .panic);
2554625214 const panic_fn_index = zcu.builtin_decl_values.get(panic_id.toBuiltin());
2554725215 switch (sema.owner.unwrap()) {
25548 .@"comptime", .nav_ty, .nav_val, .type_layout, .type_inits, .memoized_state => {},
25216 .@"comptime", .nav_ty, .nav_val, .type_layout, .struct_defaults, .memoized_state => {},
2554925217 .func => |owner_func| zcu.intern_pool.funcSetHasErrorTrace(io, owner_func, true),
2555025218 }
2555125219 return panic_fn_index;
......@@ -25962,6 +25630,7 @@ fn fieldVal(
2596225630 if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {
2596325631 return inst;
2596425632 }
25633 try sema.ensureLayoutResolved(child_type);
2596525634 if (child_type.unionTagType(zcu)) |enum_ty| {
2596625635 if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index_usize| {
2596725636 const field_index: u32 = @intCast(field_index_usize);
......@@ -25974,6 +25643,7 @@ fn fieldVal(
2597425643 if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {
2597525644 return inst;
2597625645 }
25646 try sema.ensureLayoutResolved(child_type);
2597725647 const field_index_usize = child_type.enumFieldIndex(field_name, zcu) orelse
2597825648 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
2597925649 const field_index: u32 = @intCast(field_index_usize);
......@@ -26195,6 +25865,7 @@ fn fieldPtr(
2619525865 if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {
2619625866 return inst;
2619725867 }
25868 try sema.ensureLayoutResolved(child_type);
2619825869 if (child_type.unionTagType(zcu)) |enum_ty| {
2619925870 if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index| {
2620025871 const field_index_u32: u32 = @intCast(field_index);
......@@ -26208,6 +25879,7 @@ fn fieldPtr(
2620825879 if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {
2620925880 return inst;
2621025881 }
25882 try sema.ensureLayoutResolved(child_type);
2621125883 const field_index = child_type.enumFieldIndex(field_name, zcu) orelse {
2621225884 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
2621325885 };
......@@ -26444,9 +26116,6 @@ fn finishFieldCallBind(
2644426116 const container_ty = ptr_ty.childType(zcu);
2644526117 if (container_ty.zigTypeTag(zcu) == .@"struct") {
2644626118 if (container_ty.structFieldIsComptime(field_index, zcu)) {
26447 if (!container_ty.isTuple(zcu)) {
26448 try sema.ensureFieldInitsResolved(container_ty);
26449 }
2645026119 const default_val = (try container_ty.structFieldValueComptime(pt, field_index)).?;
2645126120 return .{ .direct = Air.internedToRef(default_val.toIntern()) };
2645226121 }
......@@ -26623,7 +26292,7 @@ fn structFieldPtrByIndex(
2662326292 const ptr_field_ty = try pt.ptrType(ptr_ty_data);
2662426293
2662526294 if (field_is_comptime) {
26626 try sema.ensureFieldInitsResolved(struct_ty);
26295 assert(struct_type.field_defaults.get(ip)[field_index] != .none);
2662726296 const val = try pt.intern(.{ .ptr = .{
2662826297 .ty = ptr_field_ty.toIntern(),
2662926298 .base_addr = .{ .comptime_field = struct_type.field_defaults.get(ip)[field_index] },
......@@ -26647,6 +26316,8 @@ fn structFieldVal(
2664726316 const zcu = pt.zcu;
2664826317 const ip = &zcu.intern_pool;
2664926318 assert(struct_ty.zigTypeTag(zcu) == .@"struct");
26319 assert(sema.typeOf(struct_byval).toIntern() == struct_ty.toIntern());
26320 struct_ty.assertHasLayout(zcu);
2665026321
2665126322 switch (ip.indexToKey(struct_ty.toIntern())) {
2665226323 .struct_type => {
......@@ -26655,7 +26326,6 @@ fn structFieldVal(
2665526326 const field_index = struct_type.nameIndex(ip, field_name) orelse
2665626327 return sema.failWithBadStructFieldAccess(block, struct_ty, struct_type, field_name_src, field_name);
2665726328 if (struct_type.field_is_comptime_bits.get(ip, field_index)) {
26658 try sema.ensureFieldInitsResolved(struct_ty);
2665926329 return .fromIntern(struct_type.field_defaults.get(ip)[field_index]);
2666026330 }
2666126331
......@@ -26886,6 +26556,8 @@ fn unionFieldVal(
2688626556 const zcu = pt.zcu;
2688726557 const ip = &zcu.intern_pool;
2688826558 assert(union_ty.zigTypeTag(zcu) == .@"union");
26559 assert(sema.typeOf(union_byval).toIntern() == union_ty.toIntern());
26560 union_ty.assertHasLayout(zcu);
2688926561
2689026562 const union_obj = zcu.typeToUnion(union_ty).?;
2689126563 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
......@@ -27149,11 +26821,11 @@ fn validateRuntimeElemAccess(
2714926821 const msg = try sema.errMsg(
2715026822 elem_index_src,
2715126823 "values of type '{f}' must be comptime-known, but index value is runtime-known",
27152 .{parent_ty.fmt(sema.pt)},
26824 .{elem_ty.fmt(sema.pt)},
2715326825 );
2715426826 errdefer msg.destroy(sema.gpa);
2715526827
27156 try sema.explainWhyTypeIsComptime(msg, parent_src, parent_ty);
26828 try sema.explainWhyTypeIsComptime(msg, parent_src, elem_ty);
2715726829
2715826830 break :msg msg;
2715926831 };
......@@ -27885,18 +27557,14 @@ fn coerceExtra(
2788527557 // empty tuple to zero-length slice
2788627558 // note that this allows coercing to a mutable slice.
2788727559 if (inst_child_ty.structFieldCount(zcu) == 0) {
27888 // TODO MLUGG: this is *unacceptably* stupid. we're resolving the child for the alignment value
27889 try sema.ensureLayoutResolved(dest_ty.childType(zcu));
27890 const align_val = dest_ty.ptrAlignment(zcu);
27891 return Air.internedToRef(try pt.intern(.{ .slice = .{
27892 .ty = dest_ty.toIntern(),
27893 .ptr = try pt.intern(.{ .ptr = .{
27894 .ty = dest_ty.slicePtrFieldType(zcu).toIntern(),
27895 .base_addr = .int,
27896 .byte_offset = align_val.toByteUnits().?,
27897 } }),
27898 .len = .zero_usize,
27899 } }));
27560 const empty_array_ty = try pt.arrayType(.{
27561 .len = 0,
27562 .child = dest_info.child,
27563 .sentinel = dest_info.sentinel,
27564 });
27565 const empty_array_val = try pt.aggregateValue(empty_array_ty, &.{});
27566 const empty_array_ptr = try sema.uavRef(empty_array_val.toIntern());
27567 return sema.coerceArrayPtrToSlice(block, dest_ty, empty_array_ptr, inst_src);
2790027568 }
2790127569
2790227570 // pointer to tuple to slice
......@@ -27955,7 +27623,7 @@ fn coerceExtra(
2795527623 .int, .comptime_int => {
2795627624 if (maybe_inst_val) |val| {
2795727625 // comptime-known integer to other number
27958 if (!(try sema.intFitsInType(val, dest_ty, null))) {
27626 if (!val.intFitsInType(dest_ty, null, zcu)) {
2795927627 if (!opts.report_err) return error.NotCoercible;
2796027628 return sema.fail(block, inst_src, "type '{f}' cannot represent integer value '{f}'", .{ dest_ty.fmt(pt), val.fmtValueSema(pt, sema) });
2796127629 }
......@@ -28039,28 +27707,26 @@ fn coerceExtra(
2803927707 }
2804027708 break :int;
2804127709 };
27710 if (val.isUndef(zcu)) {
27711 return .fromValue(try pt.undefValue(dest_ty));
27712 }
2804227713 const result_val = try pt.floatValue(dest_ty, val.toFloat(f128, zcu));
28043 const fits: bool = switch (ip.indexToKey(result_val.toIntern())) {
28044 else => unreachable,
28045 .undef => true,
28046 .float => |float| fits: {
28047 var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined;
28048 const operand_big_int = val.toBigInt(&buffer, zcu);
28049 switch (float.storage) {
28050 inline else => |x| {
28051 if (!std.math.isFinite(x)) break :fits false;
28052 var result_big_int: std.math.big.int.Mutable = .{
28053 .limbs = try sema.arena.alloc(std.math.big.Limb, std.math.big.int.calcLimbLen(x)),
28054 .len = undefined,
28055 .positive = undefined,
28056 };
28057 switch (result_big_int.setFloat(x, .nearest_even)) {
28058 .inexact => break :fits false,
28059 .exact => {},
28060 }
28061 break :fits result_big_int.toConst().eql(operand_big_int);
28062 },
27714 const float = ip.indexToKey(result_val.toIntern()).float;
27715 var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined;
27716 const operand_big_int = val.toBigInt(&buffer, zcu);
27717 const fits = switch (float.storage) {
27718 inline else => |x| fits: {
27719 if (!std.math.isFinite(x)) break :fits false;
27720 var result_big_int: std.math.big.int.Mutable = .{
27721 .limbs = try sema.arena.alloc(std.math.big.Limb, std.math.big.int.calcLimbLen(x)),
27722 .len = undefined,
27723 .positive = undefined,
27724 };
27725 switch (result_big_int.setFloat(x, .nearest_even)) {
27726 .inexact => break :fits false,
27727 .exact => {},
2806327728 }
27729 break :fits result_big_int.toConst().eql(operand_big_int);
2806427730 },
2806527731 };
2806627732 if (!fits) return sema.fail(
......@@ -28699,7 +28365,7 @@ pub fn coerceInMemoryAllowed(
2869928365 // Comptime int to regular int.
2870028366 if (dest_tag == .int and src_tag == .comptime_int) {
2870128367 if (src_val) |val| {
28702 if (!(try sema.intFitsInType(val, dest_ty, null))) {
28368 if (!val.intFitsInType(dest_ty, null, zcu)) {
2870328369 return .{ .comptime_int_not_coercible = .{ .wanted = dest_ty, .actual = val } };
2870428370 }
2870528371 }
......@@ -29333,7 +28999,7 @@ fn coerceVarArgParam(
2933328999 }
2933429000 },
2933529001 else => if (uncasted_ty.isAbiInt(zcu)) int: {
29336 if (!try sema.validateExternType(uncasted_ty, .param_ty)) break :int inst;
29002 if (!uncasted_ty.validateExtern(.param_ty, zcu)) break :int inst;
2933729003 const target = zcu.getTarget();
2933829004 const uncasted_info = uncasted_ty.intInfo(zcu);
2933929005 if (uncasted_info.bits <= target.cTypeBitSize(switch (uncasted_info.signedness) {
......@@ -29362,7 +29028,7 @@ fn coerceVarArgParam(
2936229028 };
2936329029
2936429030 const coerced_ty = sema.typeOf(coerced);
29365 if (!try sema.validateExternType(coerced_ty, .param_ty)) {
29031 if (!coerced_ty.validateExtern(.param_ty, zcu)) {
2936629032 const msg = msg: {
2936729033 const msg = try sema.errMsg(inst_src, "cannot pass '{f}' to variadic function", .{coerced_ty.fmt(pt)});
2936829034 errdefer msg.destroy(sema.gpa);
......@@ -33283,12 +32949,12 @@ fn typeIsArrayLike(sema: *Sema, ty: Type) ?ArrayLike {
3328332949 .elem_ty = ty.childType(zcu),
3328432950 },
3328532951 .@"struct" => {
32952 if (!ty.isTuple(zcu)) return null;
3328632953 const field_count = ty.structFieldCount(zcu);
3328732954 if (field_count == 0) return .{
3328832955 .len = 0,
3328932956 .elem_ty = .noreturn,
3329032957 };
33291 if (!ty.isTuple(zcu)) return null;
3329232958 const elem_ty = ty.fieldType(0, zcu);
3329332959 for (1..field_count) |i| {
3329432960 if (!ty.fieldType(i, zcu).eql(elem_ty, zcu)) {
......@@ -33700,6 +33366,7 @@ fn usizeCast(sema: *Sema, block: *Block, src: LazySrcLoc, int: u64) CompileError
3370033366 return std.math.cast(usize, int) orelse return sema.fail(block, src, "expression produces integer value '{d}' which is too big for this compiler implementation to handle", .{int});
3370133367}
3370233368
33369/// Asserts that the layout of `union_ty` is already resolved.
3370333370fn unionFieldIndex(
3370433371 sema: *Sema,
3370533372 block: *Block,
......@@ -33717,6 +33384,7 @@ fn unionFieldIndex(
3371733384 return @intCast(field_index);
3371833385}
3371933386
33387/// Asserts that the layout of `struct_ty` is already resolved.
3372033388fn structFieldIndex(
3372133389 sema: *Sema,
3372233390 block: *Block,
......@@ -33811,64 +33479,6 @@ fn intFromFloatScalar(
3381133479 return pt.getCoerced(cti_result, int_ty);
3381233480}
3381333481
33814/// Asserts the value is an integer, and the destination type is ComptimeInt or Int.
33815/// Vectors are also accepted. Vector results are reduced with AND.
33816///
33817/// If provided, `vector_index` reports the first element that failed the range check.
33818/// MLUGG TODO: move to `Value` or `Type`?
33819fn intFitsInType(
33820 sema: *Sema,
33821 val: Value,
33822 ty: Type,
33823 vector_index: ?*usize,
33824) CompileError!bool {
33825 const pt = sema.pt;
33826 const zcu = pt.zcu;
33827 if (ty.toIntern() == .comptime_int_type) return true;
33828 const info = ty.intInfo(zcu);
33829 switch (val.toIntern()) {
33830 .zero_usize, .zero_u8 => return true,
33831 else => switch (zcu.intern_pool.indexToKey(val.toIntern())) {
33832 .undef => return true,
33833 .variable, .@"extern", .func, .ptr => {
33834 const target = zcu.getTarget();
33835 const ptr_bits = target.ptrBitWidth();
33836 return switch (info.signedness) {
33837 .signed => info.bits > ptr_bits,
33838 .unsigned => info.bits >= ptr_bits,
33839 };
33840 },
33841 .int => |int| {
33842 var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined;
33843 const big_int = int.storage.toBigInt(&buffer);
33844 return big_int.fitsInTwosComp(info.signedness, info.bits);
33845 },
33846 .aggregate => |aggregate| {
33847 assert(ty.zigTypeTag(zcu) == .vector);
33848 return switch (aggregate.storage) {
33849 .bytes => |bytes| for (bytes.toSlice(ty.vectorLen(zcu), &zcu.intern_pool), 0..) |byte, i| {
33850 if (byte == 0) continue;
33851 const actual_needed_bits = std.math.log2(byte) + 1 + @intFromBool(info.signedness == .signed);
33852 if (info.bits >= actual_needed_bits) continue;
33853 if (vector_index) |vi| vi.* = i;
33854 break false;
33855 } else true,
33856 .elems, .repeated_elem => for (switch (aggregate.storage) {
33857 .bytes => unreachable,
33858 .elems => |elems| elems,
33859 .repeated_elem => |elem| @as(*const [1]InternPool.Index, &elem),
33860 }, 0..) |elem, i| {
33861 if (try sema.intFitsInType(Value.fromInterned(elem), ty.scalarType(zcu), null)) continue;
33862 if (vector_index) |vi| vi.* = i;
33863 break false;
33864 } else true,
33865 };
33866 },
33867 else => unreachable,
33868 },
33869 }
33870}
33871
3387233482fn intInRange(sema: *Sema, tag_ty: Type, int_val: Value, end: usize) !bool {
3387333483 const pt = sema.pt;
3387433484 if (!int_val.compareAllWithZero(.gte, pt.zcu)) return false;
......@@ -33886,7 +33496,7 @@ fn enumHasInt(sema: *Sema, ty: Type, int: Value) CompileError!bool {
3388633496 // The `tagValueIndex` function call below relies on the type being the integer tag type.
3388733497 // `getCoerced` assumes the value will fit the new type.
3388833498 const int_tag_ty: Type = .fromInterned(enum_type.int_tag_type);
33889 if (!try sema.intFitsInType(int, int_tag_ty, null)) return false;
33499 if (!int.intFitsInType(int_tag_ty, null, zcu)) return false;
3389033500 const int_coerced = try pt.getCoerced(int, int_tag_ty);
3389133501 return enum_type.tagValueIndex(&zcu.intern_pool, int_coerced.toIntern()) != null;
3389233502}
......@@ -33919,7 +33529,6 @@ fn compareAll(
3391933529}
3392033530
3392133531/// Asserts the values are comparable. Both operands have type `ty`.
33922/// MLUGG TODO: move to `Value`?
3392333532fn compareScalar(
3392433533 sema: *Sema,
3392533534 lhs: Value,
......@@ -34422,7 +34031,7 @@ const ComptimeStoreResult = @import("Sema/comptime_ptr_access.zig").ComptimeStor
3442234031// MLUGG TODO: decide how to do the namespacing here
3442334032pub const type_resolution = @import("Sema/type_resolution.zig");
3442434033pub const ensureLayoutResolved = type_resolution.ensureLayoutResolved;
34425pub const ensureFieldInitsResolved = type_resolution.ensureFieldInitsResolved;
34034pub const ensureStructDefaultsResolved = type_resolution.ensureStructDefaultsResolved;
3442634035
3442734036pub fn getBuiltinType(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl) SemaError!Type {
3442834037 assert(decl.kind() == .type);
......@@ -34644,48 +34253,14 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ
3464434253 };
3464534254}
3464634255
34647/// TODO MLUGG: this is a gnarly hack
34648const PartialTypeName = union(enum) {
34649 exact: struct {
34650 name: InternPool.NullTerminatedString,
34651 nav: InternPool.Nav.Index.Optional,
34652 },
34653 anon_prefix: []const u8,
34654 fn apply(
34655 name: PartialTypeName,
34656 wip: *const InternPool.WipContainerType,
34657 pt: Zcu.PerThread,
34658 ) (Allocator.Error || std.Io.Cancelable)!InternPool.NullTerminatedString {
34659 const zcu = pt.zcu;
34660 const comp = zcu.comp;
34661 const ip = &zcu.intern_pool;
34662 switch (name) {
34663 .exact => |e| {
34664 wip.setName(ip, e.name, e.nav);
34665 return e.name;
34666 },
34667 .anon_prefix => |prefix| {
34668 const resolved_name = try ip.getOrPutStringFmt(
34669 comp.gpa,
34670 comp.io,
34671 pt.tid,
34672 "{s}_{d}",
34673 .{ prefix, @intFromEnum(wip.index) },
34674 .no_embedded_nulls,
34675 );
34676 wip.setName(ip, resolved_name, .none);
34677 return resolved_name;
34678 },
34679 }
34680 }
34681};
34682pub fn createTypeName(
34256fn setTypeName(
3468334257 sema: *Sema,
3468434258 block: *Block,
34259 wip: *const InternPool.WipContainerType,
3468534260 name_strategy: Zir.Inst.NameStrategy,
3468634261 anon_prefix: []const u8,
3468734262 inst: Zir.Inst.Index,
34688) CompileError!PartialTypeName {
34263) CompileError!void {
3468934264 const pt = sema.pt;
3469034265 const zcu = pt.zcu;
3469134266 const comp = zcu.comp;
......@@ -34693,13 +34268,26 @@ pub fn createTypeName(
3469334268 const io = comp.io;
3469434269 const ip = &zcu.intern_pool;
3469534270
34696 switch (name_strategy) {
34697 .anon => {}, // handled after switch
34698 .parent => return .{ .exact = .{
34699 .name = block.type_name_ctx,
34700 .nav = sema.owner.unwrap().nav_val.toOptional(),
34701 } },
34702 .func => func_strat: {
34271 strat: switch (name_strategy) {
34272 .anon => {
34273 // It would be neat to have "struct:line:column" but this name has
34274 // to survive incremental updates, where it may have been shifted down
34275 // or up to a different line, but unchanged, and thus not unnecessarily
34276 // semantically analyzed.
34277 // TODO: that would be possible, by detecting line number changes and renaming
34278 // types appropriately. However, `@typeName` becomes a problem then. If we remove
34279 // that builtin from the language, we can consider this.
34280 wip.setName(ip, try ip.getOrPutStringFmt(
34281 gpa,
34282 io,
34283 pt.tid,
34284 "{f}__{s}_{d}",
34285 .{ block.type_name_ctx.fmt(ip), anon_prefix, @intFromEnum(wip.index) },
34286 .no_embedded_nulls,
34287 ), .none);
34288 },
34289 .parent => wip.setName(ip, block.type_name_ctx, sema.owner.unwrap().nav_val.toOptional()),
34290 .func => {
3470334291 const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse return error.AnalysisFail);
3470434292 const zir_tags = sema.code.instructions.items(.tag);
3470534293
......@@ -34717,7 +34305,9 @@ pub fn createTypeName(
3471734305 // If not then this is a struct type being returned from a non-generic
3471834306 // function and the name doesn't matter since it will later
3471934307 // result in a compile error.
34720 const arg_val = try sema.resolveValue(arg) orelse break :func_strat; // fall through to anon strat
34308 const arg_val = try sema.resolveValue(arg) orelse {
34309 continue :strat .anon;
34310 };
3472134311
3472234312 if (arg_i != 0) w.writeByte(',') catch return error.OutOfMemory;
3472334313
......@@ -34739,431 +34329,28 @@ pub fn createTypeName(
3473934329 };
3474034330
3474134331 w.writeByte(')') catch return error.OutOfMemory;
34742 return .{ .exact = .{
34743 .name = try ip.getOrPutString(gpa, io, pt.tid, aw.written(), .no_embedded_nulls),
34744 .nav = .none,
34745 } };
34332 const name = try ip.getOrPutString(gpa, io, pt.tid, aw.written(), .no_embedded_nulls);
34333 wip.setName(ip, name, .none);
3474634334 },
3474734335 .dbg_var => {
3474834336 // TODO: this logic is questionable. We ideally should be traversing the `Block` rather than relying on the order of AstGen instructions.
3474934337 const ref = inst.toRef();
3475034338 const zir_tags = sema.code.instructions.items(.tag);
3475134339 const zir_data = sema.code.instructions.items(.data);
34752 for (@intFromEnum(inst)..zir_tags.len) |i| switch (zir_tags[i]) {
34340 const var_name = for (@intFromEnum(inst)..zir_tags.len) |i| switch (zir_tags[i]) {
3475334341 .dbg_var_ptr, .dbg_var_val => if (zir_data[i].str_op.operand == ref) {
34754 return .{ .exact = .{
34755 .name = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}.{s}", .{
34756 block.type_name_ctx.fmt(ip), zir_data[i].str_op.getStr(sema.code),
34757 }, .no_embedded_nulls),
34758 .nav = .none,
34759 } };
34342 break zir_data[i].str_op.getStr(sema.code);
3476034343 },
3476134344 else => {},
34345 } else {
34346 continue :strat .anon;
3476234347 };
34763 // fall through to anon strat
34348 const name = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}.{s}", .{
34349 block.type_name_ctx.fmt(ip), var_name,
34350 }, .no_embedded_nulls);
34351 wip.setName(ip, name, .none);
3476434352 },
3476534353 }
34766
34767 // anon strat handling
34768
34769 // It would be neat to have "struct:line:column" but this name has
34770 // to survive incremental updates, where it may have been shifted down
34771 // or up to a different line, but unchanged, and thus not unnecessarily
34772 // semantically analyzed.
34773 // TODO: that would be possible, by detecting line number changes and renaming
34774 // types appropriately. However, `@typeName` becomes a problem then. If we remove
34775 // that builtin from the language, we can consider this.
34776
34777 return .{ .anon_prefix = try std.fmt.allocPrint(
34778 sema.arena,
34779 "{f}__{s}",
34780 .{ block.type_name_ctx.fmt(ip), anon_prefix },
34781 ) };
34782}
34783
34784pub fn analyzeStructDecl(
34785 pt: Zcu.PerThread,
34786 file_index: Zcu.File.Index,
34787 zir: *const Zir,
34788 parent_namespace: InternPool.OptionalNamespaceIndex,
34789 tracked_inst: InternPool.TrackedInst.Index,
34790 struct_decl: *const Zir.UnwrappedStructDecl,
34791 explicit_backing_type: ?Type,
34792 captures: []const InternPool.CaptureValue,
34793 type_name: PartialTypeName,
34794) (Allocator.Error || std.Io.Cancelable)!Type {
34795 const zcu = pt.zcu;
34796 const comp = zcu.comp;
34797 const gpa = comp.gpa;
34798 const io = comp.io;
34799 const ip = &zcu.intern_pool;
34800
34801 const wip = switch (try ip.getStructType(gpa, io, pt.tid, .{
34802 .fields_len = @intCast(struct_decl.field_names.len),
34803 .layout = struct_decl.layout,
34804 .explicit_packed_backing_type = if (explicit_backing_type) |ty| ty.toIntern() else .none,
34805 .any_comptime_fields = struct_decl.field_comptime_bits != null,
34806 .any_field_defaults = struct_decl.field_default_body_lens != null,
34807 .any_field_aligns = struct_decl.field_align_body_lens != null,
34808 .key = .{ .declared = .{
34809 .zir_index = tracked_inst,
34810 .captures = captures,
34811 } },
34812 })) {
34813 .existing => |ty| return .fromInterned(ty),
34814 .wip => |wip| wip,
34815 };
34816 errdefer wip.cancel(ip, pt.tid);
34817
34818 _ = try type_name.apply(&wip, pt);
34819
34820 var field_it = struct_decl.iterateFields();
34821 while (field_it.next()) |field| {
34822 const name_slice = zir.nullTerminatedString(field.name);
34823 const name = try ip.getOrPutString(gpa, io, pt.tid, name_slice, .no_embedded_nulls);
34824 assert(wip.nextField(ip, name, field.is_comptime) == null); // AstGen validated this for us
34825 }
34826
34827 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
34828 .parent = parent_namespace,
34829 .owner_type = wip.index,
34830 .file_scope = file_index,
34831 .generation = zcu.generation,
34832 });
34833 errdefer pt.destroyNamespace(new_namespace_index);
34834
34835 try pt.scanNamespace(new_namespace_index, struct_decl.decls);
34836
34837 // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind
34838 try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) });
34839 try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_inits = wip.index }) });
34840
34841 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
34842
34843 try zcu.outdated.ensureUnusedCapacity(gpa, 2);
34844 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 2);
34845 errdefer comptime unreachable; // because we don't remove the `outdated` entries
34846 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0);
34847 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_inits = wip.index }), 0);
34848 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {});
34849 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_inits = wip.index }), {});
34850
34851 return .fromInterned(wip.finish(ip, new_namespace_index));
34852}
34853const AnalyzeUnionDeclError = error{
34854 OutOfMemory,
34855 Canceled,
34856 /// `packed union(T)` syntax was used, but `T` was not an integer type.
34857 ExplicitBackingNotInt,
34858 /// `union(enum(T))` syntax was used, but `T` was not an integer type.
34859 ExplicitTagNotInt,
34860 /// `union(T)` syntax was used, but `T` was not an enum type.
34861 ExplicitTagNotEnum,
34862 /// `union(T)` syntax was used, but the fields of the union do not exactly
34863 /// correspond to the fields of the enum `T`.
34864 ExplicitTagFieldMismatch,
34865};
34866fn analyzeUnionDecl(
34867 pt: Zcu.PerThread,
34868 file_index: Zcu.File.Index,
34869 zir: *const Zir,
34870 parent_namespace: InternPool.OptionalNamespaceIndex,
34871 want_safe_types: bool,
34872 tracked_inst: InternPool.TrackedInst.Index,
34873 union_decl: *const Zir.UnwrappedUnionDecl,
34874 arg_type: ?Type,
34875 captures: []const InternPool.CaptureValue,
34876 type_name: PartialTypeName,
34877) AnalyzeUnionDeclError!Type {
34878 const zcu = pt.zcu;
34879 const comp = zcu.comp;
34880 const gpa = comp.gpa;
34881 const io = comp.io;
34882 const ip = &zcu.intern_pool;
34883
34884 switch (union_decl.kind) {
34885 .tagged_explicit => if (arg_type.?.zigTypeTag(zcu) != .@"enum") {
34886 return error.ExplicitTagNotEnum;
34887 },
34888 .tagged_enum_explicit => if (arg_type.?.zigTypeTag(zcu) != .int) {
34889 return error.ExplicitTagNotInt;
34890 },
34891 .packed_explicit => if (arg_type.?.zigTypeTag(zcu) != .int) {
34892 return error.ExplicitBackingNotInt;
34893 },
34894 .auto,
34895 .tagged_enum,
34896 .@"extern",
34897 .@"packed",
34898 => assert(arg_type == null),
34899 }
34900
34901 const wip = switch (try ip.getUnionType(gpa, io, pt.tid, .{
34902 .fields_len = @intCast(union_decl.field_names.len),
34903 .layout = union_decl.kind.layout(),
34904 .explicit_packed_backing_type = switch (union_decl.kind) {
34905 .packed_explicit => arg_type.?.toIntern(),
34906 else => .none,
34907 },
34908 .runtime_tag = switch (union_decl.kind) {
34909 .auto => if (want_safe_types) .safety else .none,
34910
34911 .tagged_explicit,
34912 .tagged_enum,
34913 .tagged_enum_explicit,
34914 => .tagged,
34915
34916 .@"extern",
34917 .@"packed",
34918 .packed_explicit,
34919 => .none,
34920 },
34921 .have_explicit_enum_tag = union_decl.kind == .tagged_explicit,
34922 .any_field_aligns = union_decl.field_align_body_lens != null,
34923 .key = .{ .declared = .{
34924 .zir_index = tracked_inst,
34925 .captures = captures,
34926 .arg_ty = if (arg_type) |t| t.toIntern() else .none,
34927 } },
34928 })) {
34929 .existing => |ty| return .fromInterned(ty),
34930 .wip => |wip| wip,
34931 };
34932 errdefer wip.cancel(ip, pt.tid);
34933
34934 const resolved_type_name = try type_name.apply(&wip, pt);
34935
34936 const generated_tag_ty: InternPool.Index = if (union_decl.kind == .tagged_explicit) generated_tag_ty: {
34937 const tag_type = arg_type.?;
34938 const enum_field_names = ip.loadEnumType(tag_type.toIntern()).field_names;
34939 // Check that the enum field names match the union field names
34940 if (union_decl.field_names.len != enum_field_names.len) {
34941 return error.ExplicitTagFieldMismatch;
34942 }
34943 for (union_decl.field_names, enum_field_names.get(ip)) |union_field_zir, enum_field_ip| {
34944 const union_field_name = zir.nullTerminatedString(union_field_zir);
34945 const enum_field_name = enum_field_ip.toSlice(ip);
34946 if (!std.mem.eql(u8, union_field_name, enum_field_name)) {
34947 return error.ExplicitTagFieldMismatch;
34948 }
34949 }
34950 wip.setTagType(ip, tag_type.toIntern());
34951 break :generated_tag_ty .none;
34952 } else generated_tag_ty: {
34953 // Generate a tag type. Even if the union is untagged (`.none`), we still generate a
34954 // hypothetical tag type.
34955 const wip_tag_ty = switch (try ip.getEnumType(gpa, io, pt.tid, .{
34956 .fields_len = @intCast(union_decl.field_names.len),
34957 .explicit_int_tag_type = switch (union_decl.kind) {
34958 .tagged_enum_explicit => arg_type.?.toIntern(),
34959 else => .none,
34960 },
34961 .nonexhaustive = false,
34962 .key = .{ .generated_union_tag = wip.index },
34963 })) {
34964 .existing => unreachable, // enum type is keyed on this union type which we're only just creating
34965 .wip => |wip_tag_ty| wip_tag_ty,
34966 };
34967 errdefer wip_tag_ty.cancel(ip, pt.tid);
34968 // Populate the generated tag type's name
34969 const tag_type_name = try ip.getOrPutStringFmt(
34970 gpa,
34971 io,
34972 pt.tid,
34973 "@typeInfo({f}).@\"union\".tag_type.?",
34974 .{resolved_type_name.fmt(ip)},
34975 .no_embedded_nulls,
34976 );
34977 wip_tag_ty.setName(ip, tag_type_name, .none);
34978 // Populate the generated tag type's field names
34979 for (union_decl.field_names) |zir_name| {
34980 const name_slice = zir.nullTerminatedString(zir_name);
34981 const name = try ip.getOrPutString(gpa, io, pt.tid, name_slice, .no_embedded_nulls);
34982 assert(wip_tag_ty.nextField(ip, name, false) == null); // AstGen validated this for us
34983 }
34984 // If not explicitly given, populate the generated tag type's *integer* tag type
34985 switch (union_decl.kind) {
34986 .tagged_enum_explicit => {}, // already set by `getEnumType`
34987 else => {
34988 // Infer the int tag type from the field count
34989 const bits = Type.smallestUnsignedBits(union_decl.field_names.len -| 1);
34990 const int_tag_type = try pt.intType(.unsigned, bits);
34991 wip_tag_ty.setTagType(ip, int_tag_type.toIntern());
34992 },
34993 }
34994 // Create a dummy namespace for the generated tag type
34995 const new_namespace_index = try pt.createNamespace(.{
34996 .parent = parent_namespace,
34997 .owner_type = wip_tag_ty.index,
34998 .file_scope = file_index,
34999 .generation = zcu.generation,
35000 });
35001 errdefer pt.destroyNamespace(new_namespace_index);
35002 wip.setTagType(ip, wip_tag_ty.index);
35003 break :generated_tag_ty wip_tag_ty.finish(ip, new_namespace_index);
35004 };
35005 // If we fail to create the union type, we must delete the generated enum tag type, since it
35006 // would hold a reference to the deleted union.
35007 errdefer if (generated_tag_ty != .none) ip.remove(pt.tid, generated_tag_ty);
35008
35009 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
35010 .parent = parent_namespace,
35011 .owner_type = wip.index,
35012 .file_scope = file_index,
35013 .generation = zcu.generation,
35014 });
35015 errdefer pt.destroyNamespace(new_namespace_index);
35016
35017 try pt.scanNamespace(new_namespace_index, union_decl.decls);
35018
35019 // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind
35020 try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) });
35021 if (generated_tag_ty != .none) {
35022 try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_inits = generated_tag_ty }) });
35023 }
35024
35025 if (zcu.comp.debugIncremental()) {
35026 try zcu.incremental_debug_state.newType(zcu, wip.index);
35027 if (generated_tag_ty != .none) {
35028 try zcu.incremental_debug_state.newType(zcu, generated_tag_ty);
35029 }
35030 }
35031
35032 try zcu.outdated.ensureUnusedCapacity(gpa, 2);
35033 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 2);
35034 errdefer comptime unreachable; // because we don't remove the `outdated` entry
35035 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0);
35036 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {});
35037 if (generated_tag_ty != .none) {
35038 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_inits = generated_tag_ty }), 0);
35039 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_inits = generated_tag_ty }), {});
35040 }
35041
35042 return .fromInterned(wip.finish(ip, new_namespace_index));
35043}
35044const AnalyzeEnumDeclError = error{
35045 OutOfMemory,
35046 Canceled,
35047 /// `enum(T)` syntax was used, but `T` was not an integer type.
35048 ExplicitTagNotInt,
35049};
35050fn analyzeEnumDecl(
35051 pt: Zcu.PerThread,
35052 file_index: Zcu.File.Index,
35053 zir: *const Zir,
35054 parent_namespace: InternPool.OptionalNamespaceIndex,
35055 tracked_inst: InternPool.TrackedInst.Index,
35056 enum_decl: *const Zir.UnwrappedEnumDecl,
35057 explicit_tag_type: ?Type,
35058 captures: []const InternPool.CaptureValue,
35059 type_name: PartialTypeName,
35060) AnalyzeEnumDeclError!Type {
35061 const zcu = pt.zcu;
35062 const comp = zcu.comp;
35063 const gpa = comp.gpa;
35064 const io = comp.io;
35065 const ip = &zcu.intern_pool;
35066
35067 if (explicit_tag_type) |ty| {
35068 // MLUGG TODO: make a final call on whether comptime_int is a valid int tag type, and follow it everywhere.
35069 // i think not in the name of simplicity, but my opinion might depend on whether it's broken in practice today
35070 switch (ty.zigTypeTag(zcu)) {
35071 .int, .comptime_int => {},
35072 else => return error.ExplicitTagNotInt,
35073 }
35074 }
35075
35076 const wip = switch (try ip.getEnumType(gpa, io, pt.tid, .{
35077 .fields_len = @intCast(enum_decl.field_names.len),
35078 .explicit_int_tag_type = if (explicit_tag_type) |ty| ty.toIntern() else .none,
35079 .nonexhaustive = enum_decl.nonexhaustive,
35080 .key = .{ .declared = .{
35081 .zir_index = tracked_inst,
35082 .captures = captures,
35083 } },
35084 })) {
35085 .existing => |ty| return .fromInterned(ty),
35086 .wip => |wip| wip,
35087 };
35088 errdefer wip.cancel(ip, pt.tid);
35089
35090 _ = try type_name.apply(&wip, pt);
35091
35092 var field_it = enum_decl.iterateFields();
35093 while (field_it.next()) |field| {
35094 const name_slice = zir.nullTerminatedString(field.name);
35095 const name = try ip.getOrPutString(gpa, io, pt.tid, name_slice, .no_embedded_nulls);
35096 assert(wip.nextField(ip, name, false) == null); // AstGen validated this for us
35097 }
35098
35099 if (explicit_tag_type == null) {
35100 // Infer the int tag type from the field count
35101 const bits = Type.smallestUnsignedBits(enum_decl.field_names.len -| 1);
35102 const int_tag_ty = try pt.intType(.unsigned, bits);
35103 wip.setTagType(ip, int_tag_ty.toIntern());
35104 }
35105
35106 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
35107 .parent = parent_namespace,
35108 .owner_type = wip.index,
35109 .file_scope = file_index,
35110 .generation = zcu.generation,
35111 });
35112 errdefer pt.destroyNamespace(new_namespace_index);
35113
35114 try pt.scanNamespace(new_namespace_index, enum_decl.decls);
35115
35116 // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind
35117 try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_inits = wip.index }) });
35118
35119 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
35120
35121 try zcu.outdated.ensureUnusedCapacity(gpa, 1);
35122 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1);
35123 errdefer comptime unreachable; // because we don't remove the `outdated` entry
35124 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_inits = wip.index }), 0);
35125 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_inits = wip.index }), {});
35126
35127 return .fromInterned(wip.finish(ip, new_namespace_index));
35128}
35129fn analyzeOpaqueDecl(
35130 pt: Zcu.PerThread,
35131 file_index: Zcu.File.Index,
35132 parent_namespace: InternPool.OptionalNamespaceIndex,
35133 tracked_inst: InternPool.TrackedInst.Index,
35134 opaque_decl: *const Zir.UnwrappedOpaqueDecl,
35135 captures: []const InternPool.CaptureValue,
35136 type_name: PartialTypeName,
35137) (Allocator.Error || std.Io.Cancelable)!Type {
35138 const zcu = pt.zcu;
35139 const comp = zcu.comp;
35140 const gpa = comp.gpa;
35141 const io = comp.io;
35142 const ip = &zcu.intern_pool;
35143
35144 const wip = switch (try ip.getOpaqueType(gpa, io, pt.tid, .{
35145 .zir_index = tracked_inst,
35146 .captures = captures,
35147 })) {
35148 .existing => |ty| return .fromInterned(ty),
35149 .wip => |wip| wip,
35150 };
35151 errdefer wip.cancel(ip, pt.tid);
35152
35153 _ = try type_name.apply(&wip, pt);
35154
35155 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
35156 .parent = parent_namespace,
35157 .owner_type = wip.index,
35158 .file_scope = file_index,
35159 .generation = zcu.generation,
35160 });
35161 errdefer pt.destroyNamespace(new_namespace_index);
35162
35163 try pt.scanNamespace(new_namespace_index, opaque_decl.decls);
35164
35165 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
35166 return .fromInterned(wip.finish(ip, new_namespace_index));
3516734354}
3516834355
3516934356fn zirStructDecl(
......@@ -35173,6 +34360,10 @@ fn zirStructDecl(
3517334360) CompileError!Air.Inst.Ref {
3517434361 const pt = sema.pt;
3517534362 const zcu = pt.zcu;
34363 const comp = zcu.comp;
34364 const gpa = comp.gpa;
34365 const io = comp.io;
34366 const ip = &zcu.intern_pool;
3517634367
3517734368 const tracked_inst = try block.trackZir(inst);
3517834369
......@@ -35180,32 +34371,50 @@ fn zirStructDecl(
3518034371 .base_node_inst = tracked_inst,
3518134372 .offset = .nodeOffset(.zero),
3518234373 };
35183 const backing_ty_src: LazySrcLoc = .{
35184 .base_node_inst = tracked_inst,
35185 .offset = .{ .node_offset_container_tag = .zero },
35186 };
3518734374
3518834375 const struct_decl = sema.code.getStructDecl(inst);
3518934376
3519034377 const captures = try sema.getCaptures(block, src, struct_decl.captures, struct_decl.capture_names);
3519134378
35192 const backing_int_type: ?Type = ty: {
35193 if (struct_decl.backing_int_type == .none) break :ty null;
35194 break :ty try sema.resolveType(block, backing_ty_src, struct_decl.backing_int_type);
35195 // MLUGG TODO validate it's an int!
35196 };
34379 const ty: Type = switch (try ip.getDeclaredStructType(gpa, io, pt.tid, .{
34380 .zir_index = tracked_inst,
34381 .captures = captures,
34382 .fields_len = @intCast(struct_decl.field_names.len),
34383 .layout = struct_decl.layout,
34384 .any_comptime_fields = struct_decl.field_comptime_bits != null,
34385 .any_field_defaults = struct_decl.field_default_body_lens != null,
34386 .any_field_aligns = struct_decl.field_align_body_lens != null,
34387 .packed_backing_mode = if (struct_decl.backing_int_type_body != null) .explicit else .auto,
34388 })) {
34389 .existing => |ty| .fromInterned(ty),
34390 .wip => |wip| ty: {
34391 errdefer wip.cancel(ip, pt.tid);
34392 try sema.setTypeName(block, &wip, struct_decl.name_strategy, "struct", inst);
34393 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
34394 .parent = block.namespace.toOptional(),
34395 .owner_type = wip.index,
34396 .file_scope = block.getFileScopeIndex(zcu),
34397 .generation = zcu.generation,
34398 });
34399 errdefer pt.destroyNamespace(new_namespace_index);
34400 try pt.scanNamespace(new_namespace_index, struct_decl.decls);
34401 // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind
34402 try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) });
34403 try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .struct_defaults = wip.index }) });
3519734404
35198 const ty = try analyzeStructDecl(
35199 pt,
35200 block.getFileScopeIndex(zcu),
35201 &sema.code,
35202 block.namespace.toOptional(),
35203 tracked_inst,
35204 &struct_decl,
35205 backing_int_type,
35206 captures,
35207 try sema.createTypeName(block, struct_decl.name_strategy, "struct", inst),
35208 );
34405 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
34406
34407 try zcu.outdated.ensureUnusedCapacity(gpa, 2);
34408 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 2);
34409 errdefer comptime unreachable; // because we don't remove the `outdated` entries
34410 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0);
34411 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .struct_defaults = wip.index }), 0);
34412 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {});
34413 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .struct_defaults = wip.index }), {});
34414
34415 break :ty .fromInterned(wip.finish(ip, new_namespace_index));
34416 },
34417 };
3520934418
3521034419 try sema.addTypeReferenceEntry(src, ty);
3521134420
......@@ -35234,124 +34443,68 @@ fn zirUnionDecl(
3523434443 .base_node_inst = tracked_inst,
3523534444 .offset = .nodeOffset(.zero),
3523634445 };
35237 const arg_ty_src: LazySrcLoc = .{
35238 .base_node_inst = tracked_inst,
35239 .offset = .{ .node_offset_container_tag = .zero },
35240 };
3524134446
3524234447 const union_decl = sema.code.getUnionDecl(inst);
3524334448
3524434449 const captures = try sema.getCaptures(block, src, union_decl.captures, union_decl.capture_names);
3524534450
35246 const arg_type: ?Type = ty: {
35247 if (union_decl.arg_type == .none) break :ty null;
35248 break :ty try sema.resolveType(block, arg_ty_src, union_decl.arg_type);
35249 };
34451 const ty: Type = switch (try ip.getDeclaredUnionType(gpa, io, pt.tid, .{
34452 .zir_index = tracked_inst,
34453 .captures = captures,
34454 .fields_len = @intCast(union_decl.field_names.len),
34455 .layout = union_decl.kind.layout(),
34456 .any_field_aligns = union_decl.field_align_body_lens != null,
34457 .runtime_tag = switch (union_decl.kind) {
34458 .auto => if (block.wantSafeTypes()) .safety else .none,
3525034459
35251 const ty = analyzeUnionDecl(
35252 pt,
35253 block.getFileScopeIndex(zcu),
35254 &sema.code,
35255 block.namespace.toOptional(),
35256 block.wantSafeTypes(),
35257 tracked_inst,
35258 &union_decl,
35259 arg_type,
35260 captures,
35261 try sema.createTypeName(block, union_decl.name_strategy, "union", inst),
35262 ) catch |err| switch (err) {
35263 error.OutOfMemory,
35264 error.Canceled,
35265 => |e| return e,
35266
35267 error.ExplicitBackingNotInt => return sema.fail(
35268 block,
35269 arg_ty_src,
35270 "expected integer backing type, found '{f}'",
35271 .{arg_type.?.fmt(pt)},
35272 ),
35273 error.ExplicitTagNotInt => return sema.fail(
35274 block,
35275 arg_ty_src,
35276 "expected integer tag type, found '{f}'",
35277 .{arg_type.?.fmt(pt)},
35278 ),
35279 error.ExplicitTagNotEnum => return sema.fail(
35280 block,
35281 arg_ty_src,
35282 "expected enum tag type, found '{f}'",
35283 .{arg_type.?.fmt(pt)},
35284 ),
35285 error.ExplicitTagFieldMismatch => {
35286 const enum_obj = ip.loadEnumType(arg_type.?.toIntern());
35287 const enum_to_union_map = try sema.arena.alloc(?u32, enum_obj.field_names.len);
35288 @memset(enum_to_union_map, null);
35289 for (union_decl.field_names, 0..) |field_name_zir, union_field_idx| {
35290 const field_name_ip = try ip.getOrPutString(gpa, io, pt.tid, sema.code.nullTerminatedString(field_name_zir), .no_embedded_nulls);
35291 if (enum_obj.nameIndex(ip, field_name_ip)) |enum_field_idx| {
35292 enum_to_union_map[enum_field_idx] = @intCast(union_field_idx);
35293 continue;
35294 }
35295 const union_field_src: LazySrcLoc = .{
35296 .base_node_inst = tracked_inst,
35297 .offset = .{ .container_field_name = @intCast(union_field_idx) },
35298 };
35299 return sema.failWithOwnedErrorMsg(block, msg: {
35300 const msg = try sema.errMsg(union_field_src, "no field named '{f}' in enum '{f}'", .{ field_name_ip.fmt(ip), arg_type.?.fmt(pt) });
35301 errdefer msg.destroy(gpa);
35302 try sema.addDeclaredHereNote(msg, arg_type.?);
35303 break :msg msg;
35304 });
35305 }
35306 for (enum_to_union_map, 0..) |union_field_idx, enum_field_idx| {
35307 if (union_field_idx != null) continue;
35308 const field_name_ip = enum_obj.field_names.get(ip)[enum_field_idx];
35309 const enum_field_src: LazySrcLoc = .{
35310 .base_node_inst = arg_type.?.typeDeclInstAllowGeneratedTag(zcu).?,
35311 .offset = .{ .container_field_name = @intCast(enum_field_idx) },
35312 };
35313 return sema.failWithOwnedErrorMsg(block, msg: {
35314 const msg = try sema.errMsg(src, "enum field '{f}' missing from union", .{field_name_ip.fmt(ip)});
35315 errdefer msg.destroy(gpa);
35316 try sema.errNote(enum_field_src, msg, "enum field here", .{});
35317 break :msg msg;
35318 });
35319 }
35320 for (enum_to_union_map, 0..) |union_field_idx, enum_field_idx| {
35321 if (union_field_idx.? == enum_field_idx) continue;
35322 const field_name = sema.code.nullTerminatedString(
35323 union_decl.field_names[union_field_idx.?],
35324 );
35325 const union_field_src: LazySrcLoc = .{
35326 .base_node_inst = tracked_inst,
35327 .offset = .{ .container_field_name = union_field_idx.? },
35328 };
35329 const enum_field_src: LazySrcLoc = .{
35330 .base_node_inst = arg_type.?.typeDeclInstAllowGeneratedTag(zcu).?,
35331 .offset = .{ .container_field_name = @intCast(enum_field_idx) },
35332 };
35333 return sema.failWithOwnedErrorMsg(block, msg: {
35334 const msg = try sema.errMsg(src, "union field order does not match tag enum field order", .{});
35335 errdefer msg.destroy(gpa);
35336 try sema.errNote(union_field_src, msg, "union field '{s}' is index {d}", .{ field_name, union_field_idx.? });
35337 try sema.errNote(enum_field_src, msg, "enum field '{s}' is index {d}", .{ field_name, enum_field_idx });
35338 break :msg msg;
35339 });
35340 }
35341 unreachable;
34460 .tagged_explicit,
34461 .tagged_enum,
34462 .tagged_enum_explicit,
34463 => .tagged,
34464
34465 .@"extern",
34466 .@"packed",
34467 .packed_explicit,
34468 => .none,
3534234469 },
35343 };
34470 .enum_tag_mode = switch (union_decl.kind) {
34471 .tagged_explicit => .explicit,
34472 else => .auto,
34473 },
34474 .packed_backing_mode = switch (union_decl.kind) {
34475 .packed_explicit => .explicit,
34476 else => .auto,
34477 },
34478 })) {
34479 .existing => |ty| .fromInterned(ty),
34480 .wip => |wip| ty: {
34481 errdefer wip.cancel(ip, pt.tid);
34482 try sema.setTypeName(block, &wip, union_decl.name_strategy, "union", inst);
3534434483
35345 const enum_tag_ty = ty.unionTagTypeHypothetical(zcu);
35346 switch (ip.indexToKey(enum_tag_ty.toIntern()).enum_type) {
35347 .declared, .reified => {},
35348 .generated_union_tag => |owner_union_ty| {
35349 assert(owner_union_ty == ty.toIntern());
35350 // generated tag type [MLUGG]
35351 // Enum inits are resolved eagerly. TODO MLUGG: honestly i don't think they SHOULD be lol
35352 try sema.ensureFieldInitsResolved(.fromInterned(ip.loadUnionType(ty.toIntern()).enum_tag_type));
34484 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
34485 .parent = block.namespace.toOptional(),
34486 .owner_type = wip.index,
34487 .file_scope = block.getFileScopeIndex(zcu),
34488 .generation = zcu.generation,
34489 });
34490 errdefer pt.destroyNamespace(new_namespace_index);
34491
34492 try pt.scanNamespace(new_namespace_index, union_decl.decls);
34493
34494 // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind
34495 try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) });
34496
34497 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
34498
34499 try zcu.outdated.ensureUnusedCapacity(gpa, 1);
34500 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1);
34501 errdefer comptime unreachable; // because we don't remove the `outdated` entry
34502 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0);
34503 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {});
34504
34505 break :ty .fromInterned(wip.finish(ip, new_namespace_index));
3535334506 },
35354 }
34507 };
3535534508
3535634509 try sema.addTypeReferenceEntry(src, ty);
3535734510
......@@ -35369,6 +34522,10 @@ fn zirEnumDecl(
3536934522) CompileError!Air.Inst.Ref {
3537034523 const pt = sema.pt;
3537134524 const zcu = pt.zcu;
34525 const comp = zcu.comp;
34526 const gpa = comp.gpa;
34527 const io = comp.io;
34528 const ip = &zcu.intern_pool;
3537234529
3537334530 const tracked_inst = try block.trackZir(inst);
3537434531
......@@ -35376,45 +34533,48 @@ fn zirEnumDecl(
3537634533 .base_node_inst = tracked_inst,
3537734534 .offset = .nodeOffset(.zero),
3537834535 };
35379 const tag_ty_src: LazySrcLoc = .{
35380 .base_node_inst = tracked_inst,
35381 .offset = .{ .node_offset_container_tag = .zero },
35382 };
3538334536
3538434537 const enum_decl = sema.code.getEnumDecl(inst);
3538534538
3538634539 const captures = try sema.getCaptures(block, src, enum_decl.captures, enum_decl.capture_names);
3538734540
35388 const tag_type: ?Type = ty: {
35389 if (enum_decl.tag_type == .none) break :ty null;
35390 break :ty try sema.resolveType(block, tag_ty_src, enum_decl.tag_type);
35391 };
34541 const ty: Type = switch (try ip.getDeclaredEnumType(gpa, io, pt.tid, .{
34542 .zir_index = tracked_inst,
34543 .captures = captures,
34544 .fields_len = @intCast(enum_decl.field_names.len),
34545 .nonexhaustive = enum_decl.nonexhaustive,
34546 .int_tag_mode = if (enum_decl.tag_type_body != null) .explicit else .auto,
34547 })) {
34548 .existing => |ty| .fromInterned(ty),
34549 .wip => |wip| ty: {
34550 errdefer wip.cancel(ip, pt.tid);
3539234551
35393 const ty = analyzeEnumDecl(
35394 pt,
35395 block.getFileScopeIndex(zcu),
35396 &sema.code,
35397 block.namespace.toOptional(),
35398 tracked_inst,
35399 &enum_decl,
35400 tag_type,
35401 captures,
35402 try sema.createTypeName(block, enum_decl.name_strategy, "enum", inst),
35403 ) catch |err| switch (err) {
35404 error.OutOfMemory,
35405 error.Canceled,
35406 => |e| return e,
35407
35408 error.ExplicitTagNotInt => return sema.fail(
35409 block,
35410 tag_ty_src,
35411 "expected integer tag type, found '{f}'",
35412 .{tag_type.?.fmt(pt)},
35413 ),
35414 };
34552 try sema.setTypeName(block, &wip, enum_decl.name_strategy, "enum", inst);
34553
34554 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
34555 .parent = block.namespace.toOptional(),
34556 .owner_type = wip.index,
34557 .file_scope = block.getFileScopeIndex(zcu),
34558 .generation = zcu.generation,
34559 });
34560 errdefer pt.destroyNamespace(new_namespace_index);
3541534561
35416 // Enum inits are resolved eagerly. TODO MLUGG: honestly i don't think they SHOULD be lol
35417 try sema.ensureFieldInitsResolved(ty);
34562 try pt.scanNamespace(new_namespace_index, enum_decl.decls);
34563
34564 // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind
34565 try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) });
34566
34567 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
34568
34569 try zcu.outdated.ensureUnusedCapacity(gpa, 1);
34570 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1);
34571 errdefer comptime unreachable; // because we don't remove the `outdated` entry
34572 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0);
34573 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {});
34574
34575 break :ty .fromInterned(wip.finish(ip, new_namespace_index));
34576 },
34577 };
3541834578
3541934579 try sema.addTypeReferenceEntry(src, ty);
3542034580
......@@ -35432,6 +34592,10 @@ fn zirOpaqueDecl(
3543234592) CompileError!Air.Inst.Ref {
3543334593 const pt = sema.pt;
3543434594 const zcu = pt.zcu;
34595 const comp = zcu.comp;
34596 const gpa = comp.gpa;
34597 const io = comp.io;
34598 const ip = &zcu.intern_pool;
3543534599
3543634600 const tracked_inst = try block.trackZir(inst);
3543734601
......@@ -35444,15 +34608,26 @@ fn zirOpaqueDecl(
3544434608
3544534609 const captures = try sema.getCaptures(block, src, opaque_decl.captures, opaque_decl.capture_names);
3544634610
35447 const ty = try analyzeOpaqueDecl(
35448 pt,
35449 block.getFileScopeIndex(zcu),
35450 block.namespace.toOptional(),
35451 tracked_inst,
35452 &opaque_decl,
35453 captures,
35454 try sema.createTypeName(block, opaque_decl.name_strategy, "opaque", inst),
35455 );
34611 const ty: Type = switch (try ip.getDeclaredOpaqueType(gpa, io, pt.tid, .{
34612 .zir_index = tracked_inst,
34613 .captures = captures,
34614 })) {
34615 .existing => |ty| .fromInterned(ty),
34616 .wip => |wip| ty: {
34617 errdefer wip.cancel(ip, pt.tid);
34618 try sema.setTypeName(block, &wip, opaque_decl.name_strategy, "opaque", inst);
34619 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
34620 .parent = block.namespace.toOptional(),
34621 .owner_type = wip.index,
34622 .file_scope = block.getFileScopeIndex(zcu),
34623 .generation = zcu.generation,
34624 });
34625 errdefer pt.destroyNamespace(new_namespace_index);
34626 try pt.scanNamespace(new_namespace_index, opaque_decl.decls);
34627 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
34628 break :ty .fromInterned(wip.finish(ip, new_namespace_index));
34629 },
34630 };
3545634631
3545734632 try sema.addTypeReferenceEntry(src, ty);
3545834633
src/Sema/LowerZon.zig+1-1
......@@ -769,7 +769,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool
769769 const ip = &pt.zcu.intern_pool;
770770
771771 try self.sema.ensureLayoutResolved(res_ty);
772 try self.sema.ensureFieldInitsResolved(res_ty);
772 try self.sema.ensureStructDefaultsResolved(res_ty);
773773 const struct_info = self.sema.pt.zcu.typeToStruct(res_ty).?;
774774
775775 const fields: @FieldType(Zoir.Node, "struct_literal") = switch (node.get(self.file.zoir.?)) {
src/Sema/type_resolution.zig+719-454
......@@ -18,10 +18,6 @@ const arith = @import("arith.zig");
1818/// `ty` may be any type; its layout is resolved *recursively* if necessary.
1919/// Adds incremental dependencies tracking any required type resolution.
2020/// MLUGG TODO: to make the langspec non-stupid, we need to call this from WAY fewer places (the conditions need to be less specific).
21/// e.g. I think creating the type `fn (A, B) C` should force layout resolution of `A`,`B`,`C`, which will simplify some `analyzeCall` logic.
22/// wait i just realised that's probably a terrible idea, fns are a common cause of dep loops rn... so maybe not lol idk...
23/// perhaps "layout resolution" for a function should resolve layout of ret ty and stuff, idk. justification: the "layout" of a function is whether
24/// fnHasRuntimeBits, which depends whether the ret ty is comptime-only, i.e. the ret ty layout
2521/// MLUGG TODO: to be clear, i should audit EVERY use of this before PRing
2622pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void {
2723 const pt = sema.pt;
......@@ -33,7 +29,6 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void {
3329 .anyframe_type,
3430 .simple_type,
3531 .opaque_type,
36 .enum_type,
3732 .error_set_type,
3833 .inferred_error_set_type,
3934 => {},
......@@ -52,7 +47,7 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void {
5247 .tuple_type => |tuple| for (tuple.types.get(ip)) |field_ty| {
5348 try ensureLayoutResolved(sema, .fromInterned(field_ty));
5449 },
55 .struct_type, .union_type => {
50 .struct_type, .union_type, .enum_type => {
5651 try sema.declareDependency(.{ .type_layout = ty.toIntern() });
5752 if (zcu.analysis_in_progress.contains(.wrap(.{ .type_layout = ty.toIntern() }))) {
5853 // TODO: better error message
......@@ -89,36 +84,36 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void {
8984 }
9085}
9186
92/// Asserts that `ty` is either a `struct` type, or an `enum` type.
93/// If `ty` is a struct, ensures that fields' default values are resolved.
94/// If `ty` is an enum, ensures that fields' integer tag valus are resolved.
95/// Adds incremental dependencies tracking the required type resolution.
96pub fn ensureFieldInitsResolved(sema: *Sema, ty: Type) SemaError!void {
87/// Asserts that `ty` is a non-tuple `struct` type, and ensures that its fields' default values
88/// are resolved. Adds incremental dependencies tracking the required type resolution.
89///
90/// It is not necessary to call this function to query the values of comptime fields: those values
91/// are available from type *layout* resolution, see `ensureLayoutResolved`.
92pub fn ensureStructDefaultsResolved(sema: *Sema, ty: Type) SemaError!void {
9793 const pt = sema.pt;
9894 const zcu = pt.zcu;
9995 const ip = &zcu.intern_pool;
100 switch (ip.indexToKey(ty.toIntern())) {
101 .struct_type, .enum_type => {},
102 else => unreachable, // assertion failure
103 }
96 assert(ip.indexToKey(ty.toIntern()) == .struct_type);
10497
105 try sema.declareDependency(.{ .type_inits = ty.toIntern() });
106 if (zcu.analysis_in_progress.contains(.wrap(.{ .type_inits = ty.toIntern() }))) {
98 try sema.declareDependency(.{ .struct_defaults = ty.toIntern() });
99 if (zcu.analysis_in_progress.contains(.wrap(.{ .struct_defaults = ty.toIntern() }))) {
107100 // TODO: better error message
108101 return sema.failWithOwnedErrorMsg(null, try sema.errMsg(
109102 ty.srcLoc(zcu),
110 "{s} '{f}' depends on itself",
111 .{ @tagName(ty.zigTypeTag(zcu)), ty.fmt(pt) },
103 "struct '{f}' depends on itself",
104 .{ty.fmt(pt)},
112105 ));
113106 }
114 try pt.ensureTypeInitsUpToDate(ty);
107 try pt.ensureStructDefaultsUpToDate(ty);
115108}
109
116110/// Asserts that `struct_ty` is a non-packed non-tuple struct, and that `sema.owner` is that type.
117111/// This function *does* register the `src_hash` dependency on the struct.
118112pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
119113 const pt = sema.pt;
120114 const zcu = pt.zcu;
121115 const comp = zcu.comp;
116 const io = comp.io;
122117 const gpa = comp.gpa;
123118 const ip = &zcu.intern_pool;
124119
......@@ -127,10 +122,6 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
127122 const struct_obj = ip.loadStructType(struct_ty.toIntern());
128123 const zir_index = struct_obj.zir_index.resolve(ip).?;
129124
130 assert(struct_obj.layout != .@"packed");
131
132 try sema.declareDependency(.{ .src_hash = struct_obj.zir_index });
133
134125 var block: Block = .{
135126 .parent = null,
136127 .sema = sema,
......@@ -143,39 +134,92 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
143134 };
144135 defer assert(block.instructions.items.len == 0);
145136
146 const zir_struct = sema.code.getStructDecl(zir_index);
147 var field_it = zir_struct.iterateFields();
148 while (field_it.next()) |zir_field| {
149 const field_ty_src: LazySrcLoc = .{
150 .base_node_inst = struct_obj.zir_index,
151 .offset = .{ .container_field_type = zir_field.idx },
152 };
153 const field_align_src: LazySrcLoc = .{
154 .base_node_inst = struct_obj.zir_index,
155 .offset = .{ .container_field_align = zir_field.idx },
156 };
137 // There may be old field names in here from a previous update.
138 struct_obj.field_name_map.get(ip).clearRetainingCapacity();
139
140 if (struct_obj.is_reified) {
141 // The field names are populated, but we haven't checked for duplicates (nor populated the map) yet.
142 for (0..struct_obj.field_names.len) |field_index| {
143 const name = struct_obj.field_names.get(ip)[field_index];
144 if (ip.addFieldName(struct_obj.field_names, struct_obj.field_name_map, name)) |prev_field_index| {
145 return sema.failWithOwnedErrorMsg(&block, msg: {
146 const src = block.nodeOffset(.zero);
147 const msg = try sema.errMsg(src, "duplicate struct field '{f}' at index '{d}", .{ name.fmt(ip), field_index });
148 errdefer msg.destroy(gpa);
149 try sema.errNote(src, msg, "previous field at index '{d}'", .{prev_field_index});
150 break :msg msg;
151 });
152 }
153 }
154 } else {
155 // Declared structs do not yet have field information populated:
156 // * field names
157 // * field comptime-ness
158 // * field types
159 // * field aligns
160 // It's our job to populate these now.
161 try sema.declareDependency(.{ .src_hash = struct_obj.zir_index });
162
163 // Likewise, comptime bits may be set. We clear them all first because it avoids needing
164 // "unset bit with AND" logic below (instead we only need the "set bit with OR" case).
165 @memset(struct_obj.field_is_comptime_bits.getAll(ip), 0);
166
167 const zir_struct = sema.code.getStructDecl(zir_index);
168 var field_it = zir_struct.iterateFields();
169 while (field_it.next()) |zir_field| {
170 {
171 const name_slice = sema.code.nullTerminatedString(zir_field.name);
172 const name = try ip.getOrPutString(gpa, io, pt.tid, name_slice, .no_embedded_nulls);
173 assert(ip.addFieldName(struct_obj.field_names, struct_obj.field_name_map, name) == null); // AstGen validated this for us
174 }
157175
158 const field_ty: Type = field_ty: {
159 block.comptime_reason = .{ .reason = .{
160 .src = field_ty_src,
161 .r = .{ .simple = .struct_field_types },
162 } };
163 const type_ref = try sema.resolveInlineBody(&block, zir_field.type_body, zir_index);
164 break :field_ty try sema.analyzeAsType(&block, field_ty_src, type_ref);
165 };
166 assert(!field_ty.isGenericPoison());
176 if (zir_field.is_comptime) {
177 const bit_bag_index = zir_field.idx / 32;
178 const mask = @as(u32, 1) << @intCast(zir_field.idx % 32);
179 struct_obj.field_is_comptime_bits.getAll(ip)[bit_bag_index] |= mask;
180 }
167181
168 try sema.ensureLayoutResolved(field_ty);
182 {
183 const field_ty_src = block.src(.{ .container_field_type = zir_field.idx });
184 const field_ty: Type = field_ty: {
185 block.comptime_reason = .{ .reason = .{
186 .src = field_ty_src,
187 .r = .{ .simple = .struct_field_types },
188 } };
189 const type_ref = try sema.resolveInlineBody(&block, zir_field.type_body, zir_index);
190 break :field_ty try sema.analyzeAsType(&block, field_ty_src, .struct_field_types, type_ref);
191 };
192 struct_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern();
193 }
169194
170 const explicit_field_align: Alignment = a: {
171 block.comptime_reason = .{ .reason = .{
172 .src = field_align_src,
173 .r = .{ .simple = .struct_field_attrs },
174 } };
175 const align_body = zir_field.align_body orelse break :a .none;
176 const align_ref = try sema.resolveInlineBody(&block, align_body, zir_index);
177 break :a try sema.analyzeAsAlign(&block, field_align_src, align_ref);
178 };
195 if (struct_obj.field_aligns.len == 0) {
196 assert(zir_field.align_body == null);
197 } else {
198 const field_align_src = block.src(.{ .container_field_align = zir_field.idx });
199 const field_align: Alignment = a: {
200 block.comptime_reason = .{ .reason = .{
201 .src = field_align_src,
202 .r = .{ .simple = .struct_field_attrs },
203 } };
204 const align_body = zir_field.align_body orelse break :a .none;
205 const align_ref = try sema.resolveInlineBody(&block, align_body, zir_index);
206 break :a try sema.analyzeAsAlign(&block, field_align_src, align_ref);
207 };
208 struct_obj.field_aligns.get(ip)[zir_field.idx] = field_align;
209 }
210 }
211 }
212
213 if (struct_obj.layout == .@"packed") {
214 return resolvePackedStructLayout(sema, &block, struct_ty, &struct_obj);
215 }
216
217 // Resolve the layout of all fields, and check their types are allowed.
218 for (struct_obj.field_types.get(ip), 0..) |field_ty_ip, field_index| {
219 const field_ty: Type = .fromInterned(field_ty_ip);
220 assert(!field_ty.isGenericPoison());
221 const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) });
222 try sema.ensureLayoutResolved(field_ty);
179223
180224 if (field_ty.zigTypeTag(zcu) == .@"opaque") {
181225 return sema.failWithOwnedErrorMsg(&block, msg: {
......@@ -186,7 +230,8 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
186230 break :msg msg;
187231 });
188232 }
189 if (struct_obj.layout == .@"extern" and !try sema.validateExternType(field_ty, .struct_field)) {
233
234 if (struct_obj.layout == .@"extern" and !field_ty.validateExtern(.struct_field, zcu)) {
190235 return sema.failWithOwnedErrorMsg(&block, msg: {
191236 const msg = try sema.errMsg(field_ty_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
192237 errdefer msg.destroy(gpa);
......@@ -195,35 +240,14 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
195240 break :msg msg;
196241 });
197242 }
198
199 struct_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern();
200 if (struct_obj.field_aligns.len != 0) {
201 struct_obj.field_aligns.get(ip)[zir_field.idx] = explicit_field_align;
202 } else {
203 assert(explicit_field_align == .none);
204 }
205243 }
206244
207 try finishStructLayout(sema, &block, struct_ty.srcLoc(zcu), struct_ty.toIntern(), &struct_obj);
208}
245 // Fields are okay. Now we need to resolve the struct's overall layout (size, field offsets, etc).
209246
210/// Called after populating field types and alignments; populates field offsets, runtime order, and
211/// overall struct layout information (size, alignment, comptime-only state, etc).
212pub fn finishStructLayout(
213 sema: *Sema,
214 /// Only used to report compile errors.
215 block: *Block,
216 struct_src: LazySrcLoc,
217 struct_ty: InternPool.Index,
218 struct_obj: *const InternPool.LoadedStructType,
219) SemaError!void {
220 const pt = sema.pt;
221 const zcu = pt.zcu;
222 const comp = zcu.comp;
223 const io = comp.io;
224 const ip = &zcu.intern_pool;
247 var any_comptime_fields = false;
225248 var comptime_only = false;
226249 var one_possible_value = true;
250 var has_runtime_bits = false;
227251 var struct_align: Alignment = .@"1";
228252 // Unlike `struct_obj.field_aligns`, these are not `.none`.
229253 const resolved_field_aligns = try sema.arena.alloc(Alignment, struct_obj.field_names.len);
......@@ -240,12 +264,15 @@ pub fn finishStructLayout(
240264 // Non-`comptime` fields contribute to the struct's layout.
241265 struct_align = struct_align.maxStrict(field_align);
242266 if (field_ty.comptimeOnly(zcu)) comptime_only = true;
267 if (field_ty.hasRuntimeBits(zcu)) has_runtime_bits = true;
243268 if (try field_ty.onePossibleValue(pt) == null) one_possible_value = false;
244269 if (struct_obj.layout == .auto) {
245270 struct_obj.field_runtime_order.get(ip)[field_idx] = @enumFromInt(field_idx);
246271 }
247 } else if (struct_obj.layout == .auto) {
272 } else {
273 assert(struct_obj.layout == .auto); // comptime fields not allowed in extern or packed structs
248274 struct_obj.field_runtime_order.get(ip)[field_idx] = .omitted; // comptime fields are not in the runtime order
275 any_comptime_fields = true;
249276 }
250277 align_out.* = field_align;
251278 }
......@@ -297,75 +324,53 @@ pub fn finishStructLayout(
297324 cur_offset = offset + field_ty.abiSize(zcu);
298325 }
299326 const struct_size = std.math.cast(u32, struct_align.forward(cur_offset)) orelse return sema.fail(
300 block,
301 struct_src,
327 &block,
328 struct_ty.srcLoc(zcu),
302329 "struct layout requires size {d}, this compiler implementation supports up to {d}",
303330 .{ struct_align.forward(cur_offset), std.math.maxInt(u32) },
304331 );
305332 ip.resolveStructLayout(
306333 io,
307 struct_ty,
334 struct_ty.toIntern(),
308335 struct_size,
309336 struct_align,
310337 false, // MLUGG TODO XXX NPV
311338 one_possible_value,
312339 comptime_only,
340 has_runtime_bits,
313341 );
342
343 if (any_comptime_fields and !struct_obj.is_reified) {
344 // We also resolve field inits in this case. MLUGG TODO: this sucks, see TODO in resolveStructDefaults
345 return resolveStructDefaultsInner(sema, &block, &struct_obj);
346 }
314347}
315348
316349/// Asserts that `struct_ty` is a packed struct, and that `sema.owner` is that type.
317350/// This function *does* register the `src_hash` dependency on the struct.
318pub fn resolvePackedStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
351fn resolvePackedStructLayout(
352 sema: *Sema,
353 block: *Block,
354 struct_ty: Type,
355 struct_obj: *const InternPool.LoadedStructType,
356) CompileError!void {
319357 const pt = sema.pt;
320358 const zcu = pt.zcu;
321359 const comp = zcu.comp;
360 const io = comp.io;
322361 const gpa = comp.gpa;
323362 const ip = &zcu.intern_pool;
324363
325 assert(sema.owner.unwrap().type_layout == struct_ty.toIntern());
326
327 const struct_obj = ip.loadStructType(struct_ty.toIntern());
328 const zir_index = struct_obj.zir_index.resolve(ip).?;
329
330 assert(struct_obj.layout == .@"packed");
331
332 try sema.declareDependency(.{ .src_hash = struct_obj.zir_index });
333
334 var block: Block = .{
335 .parent = null,
336 .sema = sema,
337 .namespace = struct_obj.namespace,
338 .instructions = .{},
339 .inlining = null,
340 .comptime_reason = undefined, // always set before using `block`
341 .src_base_inst = struct_obj.zir_index,
342 .type_name_ctx = struct_obj.name,
343 };
344 defer assert(block.instructions.items.len == 0);
345
364 // Resolve the layout of all fields, and check their types are allowed.
365 // Also count the number of bits while we're at it.
346366 var field_bits: u64 = 0;
347 const zir_struct = sema.code.getStructDecl(zir_index);
348 var field_it = zir_struct.iterateFields();
349 while (field_it.next()) |zir_field| {
350 const field_ty_src: LazySrcLoc = .{
351 .base_node_inst = struct_obj.zir_index,
352 .offset = .{ .container_field_type = zir_field.idx },
353 };
354 const field_ty: Type = field_ty: {
355 block.comptime_reason = .{ .reason = .{
356 .src = field_ty_src,
357 .r = .{ .simple = .struct_field_types },
358 } };
359 const type_ref = try sema.resolveInlineBody(&block, zir_field.type_body, zir_index);
360 break :field_ty try sema.analyzeAsType(&block, field_ty_src, type_ref);
361 };
367 for (struct_obj.field_types.get(ip), 0..) |field_ty_ip, field_index| {
368 const field_ty: Type = .fromInterned(field_ty_ip);
362369 assert(!field_ty.isGenericPoison());
363 struct_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern();
364
370 const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) });
365371 try sema.ensureLayoutResolved(field_ty);
366
367372 if (field_ty.zigTypeTag(zcu) == .@"opaque") {
368 return sema.failWithOwnedErrorMsg(&block, msg: {
373 return sema.failWithOwnedErrorMsg(block, msg: {
369374 const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in struct", .{field_ty.fmt(pt)});
370375 errdefer msg.destroy(gpa);
371376 try sema.errNote(field_ty_src, msg, "opaque types have unknown size", .{});
......@@ -373,62 +378,73 @@ pub fn resolvePackedStructLayout(sema: *Sema, struct_ty: Type) CompileError!void
373378 break :msg msg;
374379 });
375380 }
376 if (!field_ty.packable(zcu)) {
377 return sema.failWithOwnedErrorMsg(&block, msg: {
378 const msg = try sema.errMsg(field_ty_src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
379 errdefer msg.destroy(gpa);
380 try sema.explainWhyTypeIsNotPackable(msg, field_ty_src, field_ty);
381 try sema.addDeclaredHereNote(msg, field_ty);
382 break :msg msg;
383 });
384 }
381 if (field_ty.unpackable(zcu)) |reason| return sema.failWithOwnedErrorMsg(block, msg: {
382 const msg = try sema.errMsg(field_ty_src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
383 errdefer msg.destroy(gpa);
384 try sema.explainWhyTypeIsUnpackable(msg, field_ty_src, reason);
385 try sema.addDeclaredHereNote(msg, field_ty);
386 break :msg msg;
387 });
385388 assert(!field_ty.comptimeOnly(zcu)); // packable types are not comptime-only
386389 field_bits += field_ty.bitSize(zcu);
387390 }
388391
389 try resolvePackedStructBackingInt(sema, &block, field_bits, struct_ty, &struct_obj);
390}
391
392pub fn resolvePackedStructBackingInt(
393 sema: *Sema,
394 block: *Block,
395 field_bits: u64,
396 struct_ty: Type,
397 struct_obj: *const InternPool.LoadedStructType,
398) SemaError!void {
399 const pt = sema.pt;
400 const zcu = pt.zcu;
401 const comp = zcu.comp;
402 const gpa = comp.gpa;
403 const io = comp.io;
404 const ip = &zcu.intern_pool;
392 const explicit_backing_int_ty: ?Type = if (struct_obj.is_reified) ty: {
393 break :ty switch (struct_obj.packed_backing_mode) {
394 .explicit => .fromInterned(struct_obj.packed_backing_int_type),
395 .auto => null,
396 };
397 } else ty: {
398 const zir_index = struct_obj.zir_index.resolve(ip).?;
399 const zir_struct = sema.code.getStructDecl(zir_index);
400 const backing_int_type_body = zir_struct.backing_int_type_body orelse {
401 break :ty null; // inferred backing type
402 };
403 // Explicitly specified, so evaluate the backing int type expression.
404 const backing_int_type_src = block.src(.container_arg);
405 block.comptime_reason = .{ .reason = .{
406 .src = backing_int_type_src,
407 .r = .{ .simple = .packed_struct_backing_int_type },
408 } };
409 const type_ref = try sema.resolveInlineBody(block, backing_int_type_body, zir_index);
410 break :ty try sema.analyzeAsType(block, backing_int_type_src, .packed_struct_backing_int_type, type_ref);
411 };
405412
406 switch (struct_obj.packed_backing_mode) {
407 .explicit => {
408 // We only need to validate the type.
409 const backing_ty: Type = .fromInterned(struct_obj.packed_backing_int_type);
410 assert(backing_ty.zigTypeTag(zcu) == .int);
411 if (field_bits != backing_ty.intInfo(zcu).bits) return sema.failWithOwnedErrorMsg(block, msg: {
412 const src = struct_ty.srcLoc(zcu);
413 const msg = try sema.errMsg(src, "backing integer bit width does not match total bit width of fields", .{});
414 errdefer msg.destroy(gpa);
415 try sema.errNote(src, msg, "backing integer '{f}' has bit width '{d}'", .{ backing_ty.fmt(pt), backing_ty.bitSize(zcu) });
416 try sema.errNote(src, msg, "struct fields have total bit width '{d}'", .{field_bits});
417 break :msg msg;
418 });
419 },
420 .auto => {
421 // We need to generate the inferred tag.
422 const want_bits = std.math.cast(u16, field_bits) orelse return sema.fail(
423 block,
424 struct_ty.srcLoc(zcu),
425 "packed struct bit width '{d}' exceeds maximum bit width of 65535",
426 .{field_bits},
427 );
428 const backing_int = try pt.intType(.unsigned, want_bits);
429 ip.resolvePackedStructBackingInt(io, struct_ty.toIntern(), backing_int.toIntern());
430 },
431 }
413 // Finally, either validate or infer the backing int type.
414 const backing_int_ty: Type = if (explicit_backing_int_ty) |backing_ty| ty: {
415 // We only need to validate the type.
416 if (backing_ty.zigTypeTag(zcu) != .int) return sema.failWithOwnedErrorMsg(block, msg: {
417 const src = struct_ty.srcLoc(zcu);
418 const msg = try sema.errMsg(src, "expected backing integer type, found '{f}'", .{backing_ty.fmt(pt)});
419 errdefer msg.destroy(gpa);
420 try sema.errNote(src, msg, "backing integer '{f}' has bit width '{d}'", .{ backing_ty.fmt(pt), backing_ty.bitSize(zcu) });
421 try sema.errNote(src, msg, "struct fields have total bit width '{d}'", .{field_bits});
422 break :msg msg;
423 });
424 if (field_bits != backing_ty.intInfo(zcu).bits) return sema.failWithOwnedErrorMsg(block, msg: {
425 const src = struct_ty.srcLoc(zcu);
426 const msg = try sema.errMsg(src, "backing integer bit width does not match total bit width of fields", .{});
427 errdefer msg.destroy(gpa);
428 try sema.errNote(src, msg, "backing integer '{f}' has bit width '{d}'", .{ backing_ty.fmt(pt), backing_ty.bitSize(zcu) });
429 try sema.errNote(src, msg, "struct fields have total bit width '{d}'", .{field_bits});
430 break :msg msg;
431 });
432 break :ty backing_ty;
433 } else ty: {
434 // We need to generate the inferred tag.
435 const backing_int_bits = std.math.cast(u16, field_bits) orelse return sema.fail(
436 block,
437 struct_ty.srcLoc(zcu),
438 "packed struct bit width '{d}' exceeds maximum bit width of 65535",
439 .{field_bits},
440 );
441 break :ty try pt.intType(.unsigned, backing_int_bits);
442 };
443 ip.resolvePackedStructLayout(
444 io,
445 struct_ty.toIntern(),
446 backing_int_ty.toIntern(),
447 );
432448}
433449
434450/// Asserts that `struct_ty` is a non-tuple struct, and that `sema.owner` is that type.
......@@ -436,25 +452,33 @@ pub fn resolvePackedStructBackingInt(
436452pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void {
437453 const pt = sema.pt;
438454 const zcu = pt.zcu;
439 const comp = zcu.comp;
440 const gpa = comp.gpa;
441455 const ip = &zcu.intern_pool;
442456
443 assert(sema.owner.unwrap().type_inits == struct_ty.toIntern());
457 assert(sema.owner.unwrap().struct_defaults == struct_ty.toIntern());
444458
445459 try sema.ensureLayoutResolved(struct_ty);
446460
447461 const struct_obj = ip.loadStructType(struct_ty.toIntern());
448 const zir_index = struct_obj.zir_index.resolve(ip).?;
449462
450463 try sema.declareDependency(.{ .src_hash = struct_obj.zir_index });
451464
465 // This logic isn't used for reified structs, because the signature of `@Struct` requires that
466 // default values are populated and correctly typed from the moment the struct type is interned
467 // (because `Sema.zirReifyStruct` had to dereference the default value from a pointer).
468 assert(!struct_obj.is_reified);
469
452470 if (struct_obj.field_defaults.len == 0) {
453471 // The struct has no default field values, so the slice has been omitted.
454472 return;
455473 }
456474
457 const field_types = struct_obj.field_types.get(ip);
475 for (struct_obj.field_is_comptime_bits.getAll(ip)) |bit_bag| {
476 if (bit_bag != 0) {
477 // There is a comptime field, so layout resolution already filled in the defaults for us!
478 // MLUGG TODO: perhaps a better idea would be for layout resolution to populate only the defaults *for comptime fields*.
479 return;
480 }
481 }
458482
459483 var block: Block = .{
460484 .parent = null,
......@@ -468,16 +492,30 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void {
468492 };
469493 defer assert(block.instructions.items.len == 0);
470494
495 return resolveStructDefaultsInner(sema, &block, &struct_obj);
496}
497/// MLUGG TODO: i dislike this, see the 'TODO' in the prev func
498fn resolveStructDefaultsInner(
499 sema: *Sema,
500 block: *Block,
501 struct_obj: *const InternPool.LoadedStructType,
502) CompileError!void {
503 const pt = sema.pt;
504 const zcu = pt.zcu;
505 const comp = zcu.comp;
506 const gpa = comp.gpa;
507 const ip = &zcu.intern_pool;
508
471509 // We'll need to map the struct decl instruction to provide result types
510 const zir_index = struct_obj.zir_index.resolve(ip).?;
472511 try sema.inst_map.ensureSpaceForInstructions(gpa, &.{zir_index});
473512
513 const field_types = struct_obj.field_types.get(ip);
514
474515 const zir_struct = sema.code.getStructDecl(zir_index);
475516 var field_it = zir_struct.iterateFields();
476517 while (field_it.next()) |zir_field| {
477 const default_val_src: LazySrcLoc = .{
478 .base_node_inst = struct_obj.zir_index,
479 .offset = .{ .container_field_value = zir_field.idx },
480 };
518 const default_val_src = block.src(.{ .container_field_value = zir_field.idx });
481519 block.comptime_reason = .{ .reason = .{
482520 .src = default_val_src,
483521 .r = .{ .simple = .struct_field_default_value },
......@@ -491,13 +529,13 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void {
491529 // Provide the result type
492530 sema.inst_map.putAssumeCapacity(zir_index, .fromIntern(field_ty.toIntern()));
493531 defer assert(sema.inst_map.remove(zir_index));
494 break :ref try sema.resolveInlineBody(&block, default_body, zir_index);
532 break :ref try sema.resolveInlineBody(block, default_body, zir_index);
495533 };
496 const coerced = try sema.coerce(&block, field_ty, uncoerced, default_val_src);
497 const default_val = try sema.resolveConstValue(&block, default_val_src, coerced, null);
534 const coerced = try sema.coerce(block, field_ty, uncoerced, default_val_src);
535 const default_val = try sema.resolveConstValue(block, default_val_src, coerced, null);
498536 if (default_val.canMutateComptimeVarState(zcu)) {
499537 const field_name = struct_obj.field_names.get(ip)[zir_field.idx];
500 return sema.failWithContainsReferenceToComptimeVar(&block, default_val_src, field_name, "field default value", default_val);
538 return sema.failWithContainsReferenceToComptimeVar(block, default_val_src, field_name, "field default value", default_val);
501539 }
502540 struct_obj.field_defaults.get(ip)[zir_field.idx] = default_val.toIntern();
503541 }
......@@ -508,6 +546,7 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
508546 const pt = sema.pt;
509547 const zcu = pt.zcu;
510548 const comp = zcu.comp;
549 const io = comp.io;
511550 const gpa = comp.gpa;
512551 const ip = &zcu.intern_pool;
513552
......@@ -516,10 +555,6 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
516555 const union_obj = ip.loadUnionType(union_ty.toIntern());
517556 const zir_index = union_obj.zir_index.resolve(ip).?;
518557
519 assert(union_obj.layout != .@"packed");
520
521 try sema.declareDependency(.{ .src_hash = union_obj.zir_index });
522
523558 var block: Block = .{
524559 .parent = null,
525560 .sema = sema,
......@@ -532,48 +567,169 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
532567 };
533568 defer assert(block.instructions.items.len == 0);
534569
535 const zir_union = sema.code.getUnionDecl(zir_index);
536 var field_it = zir_union.iterateFields();
537 while (field_it.next()) |zir_field| {
538 const field_ty_src: LazySrcLoc = .{
539 .base_node_inst = union_obj.zir_index,
540 .offset = .{ .container_field_type = zir_field.idx },
541 };
542 const field_align_src: LazySrcLoc = .{
543 .base_node_inst = union_obj.zir_index,
544 .offset = .{ .container_field_align = zir_field.idx },
570 // MLUGG TODO: this is fucking ugly bro
571 const explicit_enum_tag_ty: ?Type = if (union_obj.is_reified) ty: {
572 break :ty switch (union_obj.enum_tag_mode) {
573 .explicit => .fromInterned(union_obj.enum_tag_type),
574 .auto => null,
545575 };
576 } else ty: {
577 const zir_union = sema.code.getUnionDecl(zir_index);
578 if (zir_union.kind != .tagged_explicit) {
579 break :ty null; // enum tag type will be automatically generated
580 }
581 // Explicitly specified, so evaluate the enum tag type expression.
582 const tag_type_body = zir_union.arg_type_body.?;
583 const tag_type_src = block.src(.container_arg);
584 block.comptime_reason = .{ .reason = .{
585 .src = tag_type_src,
586 .r = .{ .simple = .union_enum_tag_type },
587 } };
588 const type_ref = try sema.resolveInlineBody(&block, tag_type_body, zir_index);
589 break :ty try sema.analyzeAsType(&block, tag_type_src, .union_enum_tag_type, type_ref);
590 };
591 const enum_tag_ty: Type = if (explicit_enum_tag_ty) |enum_tag_ty| ty: {
592 if (enum_tag_ty.zigTypeTag(zcu) != .@"enum") return sema.fail(
593 &block,
594 block.src(.container_arg),
595 "expected enum tag type, found '{f}'",
596 .{enum_tag_ty.fmt(pt)},
597 );
598 break :ty enum_tag_ty;
599 } else switch (try ip.getGeneratedEnumTagType(gpa, io, pt.tid, .{
600 .union_type = union_ty.toIntern(),
601 // MLUGG TODO: a bit hacky icl
602 .int_tag_mode = mode: {
603 if (union_obj.is_reified) break :mode .auto;
604 const zir_union = sema.code.getUnionDecl(zir_index);
605 if (zir_union.kind != .tagged_enum_explicit) break :mode .auto;
606 break :mode .explicit;
607 },
608 .fields_len = @intCast(union_obj.field_types.len),
609 })) {
610 .existing => |tag_ty| .fromInterned(tag_ty),
611 .wip => |wip| tag_ty: {
612 errdefer wip.cancel(ip, pt.tid);
613 _ = wip.setName(ip, try ip.getOrPutStringFmt(
614 gpa,
615 io,
616 pt.tid,
617 "@typeInfo({f}).@\"union\".tag_type.?",
618 .{union_obj.name.fmt(ip)},
619 .no_embedded_nulls,
620 ), .none);
621 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
622 .parent = union_obj.namespace.toOptional(),
623 .owner_type = wip.index,
624 .file_scope = zcu.namespacePtr(union_obj.namespace).file_scope,
625 .generation = zcu.generation,
626 });
627 if (comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
628 try zcu.outdated.ensureUnusedCapacity(gpa, 1);
629 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1);
630 errdefer comptime unreachable; // because we don't remove the `outdated` entry
631 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0);
632 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {});
633 break :tag_ty .fromInterned(wip.finish(ip, new_namespace_index));
634 },
635 };
546636
547 const field_ty: Type = field_ty: {
548 block.comptime_reason = .{ .reason = .{
549 .src = field_ty_src,
550 .r = .{ .simple = .union_field_types },
551 } };
552 const type_body = zir_field.type_body orelse break :field_ty .void;
553 const type_ref = try sema.resolveInlineBody(&block, type_body, zir_index);
554 break :field_ty try sema.analyzeAsType(&block, field_ty_src, type_ref);
555 };
556 assert(!field_ty.isGenericPoison());
557 union_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern();
558
559 try sema.ensureLayoutResolved(field_ty);
637 try sema.ensureLayoutResolved(enum_tag_ty);
638 const enum_obj = ip.loadEnumType(enum_tag_ty.toIntern());
639
640 if (union_obj.is_reified) {
641 // We have field names in `union_obj.reified_field_names`, but we haven't
642 // checked them against the backing type yet.
643 const union_field_names = union_obj.reified_field_names.get(ip);
644 match_fields: {
645 // We can efficiently *check* if the fields match...
646 if (union_field_names.len == enum_obj.field_names.len) {
647 for (union_field_names, enum_obj.field_names.get(ip)) |union_field_name, enum_field_name| {
648 if (!std.mem.eql(u8, union_field_name.toSlice(ip), enum_field_name.toSlice(ip))) break;
649 } else {
650 break :match_fields;
651 }
652 }
653 // ...but if they don't, reporting a nice error is a little more involved. If some field
654 // is present in the enum but not the union, or vice versa, we will report that instead
655 // of a generic "field order mismatch" error. Of course, this error is impossible for a
656 // generated tag type, because we populated that from the union ZIR!
657 assert(enum_obj.owner_union != union_ty.toIntern());
658 return failUnionFieldMismatch(sema, &block, union_field_names, enum_tag_ty, &enum_obj);
659 }
660 } else {
661 // Declared unions do not have field types or aligns populated yet.
662 // We also need to check the field names match the backing enum.
663 try sema.declareDependency(.{ .src_hash = union_obj.zir_index });
664 const zir_union = sema.code.getUnionDecl(zir_index);
560665
561 const explicit_field_align: Alignment = a: {
562 block.comptime_reason = .{ .reason = .{
563 .src = field_align_src,
564 .r = .{ .simple = .union_field_attrs },
565 } };
566 const align_body = zir_field.align_body orelse break :a .none;
567 const align_ref = try sema.resolveInlineBody(&block, align_body, zir_index);
568 break :a try sema.analyzeAsAlign(&block, field_align_src, align_ref);
569 };
666 // We'll first check the field names against the backing enum, and only analyze the types
667 // once we know the fields match one-to-one.
668 match_fields: {
669 // We can efficiently *check* if the fields match...
670 if (zir_union.field_names.len == enum_obj.field_names.len) {
671 for (zir_union.field_names, enum_obj.field_names.get(ip)) |union_field_name_zir, enum_field_name| {
672 const union_field_name_slice = sema.code.nullTerminatedString(union_field_name_zir);
673 if (!std.mem.eql(u8, union_field_name_slice, enum_field_name.toSlice(ip))) break;
674 } else {
675 break :match_fields;
676 }
677 }
678 // ...but if they don't, reporting a nice error is a little more involved. If some field
679 // is present in the enum but not the union, or vice versa, we will report that instead
680 // of a generic "field order mismatch" error. Of course, this error is impossible for a
681 // generated tag type, because we populated that from the union ZIR!
682 assert(enum_obj.owner_union != union_ty.toIntern());
683 const union_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, zir_union.field_names.len);
684 for (zir_union.field_names, union_field_names) |name_zir, *name| {
685 name.* = try ip.getOrPutString(gpa, io, pt.tid, sema.code.nullTerminatedString(name_zir), .no_embedded_nulls);
686 }
687 return failUnionFieldMismatch(sema, &block, union_field_names, enum_tag_ty, &enum_obj);
688 }
570689
571 if (union_obj.field_aligns.len != 0) {
572 union_obj.field_aligns.get(ip)[zir_field.idx] = explicit_field_align;
573 } else {
574 assert(explicit_field_align == .none);
690 // Field names okay; populate types and aligns.
691 var field_it = zir_union.iterateFields();
692 while (field_it.next()) |zir_field| {
693 const field_ty_src = block.src(.{ .container_field_type = zir_field.idx });
694 const field_ty: Type = field_ty: {
695 block.comptime_reason = .{ .reason = .{
696 .src = field_ty_src,
697 .r = .{ .simple = .union_field_types },
698 } };
699 const type_body = zir_field.type_body orelse break :field_ty .void;
700 const type_ref = try sema.resolveInlineBody(&block, type_body, zir_index);
701 break :field_ty try sema.analyzeAsType(&block, field_ty_src, .union_field_types, type_ref);
702 };
703 union_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern();
704
705 const field_align_src = block.src(.{ .container_field_align = zir_field.idx });
706 const explicit_field_align: Alignment = a: {
707 block.comptime_reason = .{ .reason = .{
708 .src = field_align_src,
709 .r = .{ .simple = .union_field_attrs },
710 } };
711 const align_body = zir_field.align_body orelse break :a .none;
712 const align_ref = try sema.resolveInlineBody(&block, align_body, zir_index);
713 break :a try sema.analyzeAsAlign(&block, field_align_src, align_ref);
714 };
715 if (union_obj.field_aligns.len != 0) {
716 union_obj.field_aligns.get(ip)[zir_field.idx] = explicit_field_align;
717 } else {
718 assert(explicit_field_align == .none);
719 }
575720 }
721 }
576722
723 if (union_obj.layout == .@"packed") {
724 return resolvePackedUnionLayout(sema, &block, union_ty, &union_obj, enum_tag_ty);
725 }
726
727 // Resolve the layout of all fields, and check their types are allowed.
728 for (union_obj.field_types.get(ip), 0..) |field_ty_ip, field_index| {
729 const field_ty: Type = .fromInterned(field_ty_ip);
730 assert(!field_ty.isGenericPoison());
731 const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) });
732 try sema.ensureLayoutResolved(field_ty);
577733 if (field_ty.zigTypeTag(zcu) == .@"opaque") {
578734 return sema.failWithOwnedErrorMsg(&block, msg: {
579735 const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in union", .{field_ty.fmt(pt)});
......@@ -583,7 +739,7 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
583739 break :msg msg;
584740 });
585741 }
586 if (union_obj.layout == .@"extern" and !try sema.validateExternType(field_ty, .union_field)) {
742 if (union_obj.layout == .@"extern" and !field_ty.validateExtern(.union_field, zcu)) {
587743 return sema.failWithOwnedErrorMsg(&block, msg: {
588744 const msg = try sema.errMsg(field_ty_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
589745 errdefer msg.destroy(gpa);
......@@ -594,36 +750,11 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
594750 }
595751 }
596752
597 try finishUnionLayout(
598 sema,
599 &block,
600 union_ty.srcLoc(zcu),
601 union_ty.toIntern(),
602 &union_obj,
603 .fromInterned(union_obj.enum_tag_type),
604 );
605}
606
607/// Called after populating field types and alignments; populates overall union layout
608/// information (size, alignment, comptime-only state, etc).
609pub fn finishUnionLayout(
610 sema: *Sema,
611 /// Only used to report compile errors.
612 block: *Block,
613 union_src: LazySrcLoc,
614 union_ty: InternPool.Index,
615 union_obj: *const InternPool.LoadedUnionType,
616 enum_tag_ty: Type,
617) SemaError!void {
618 const pt = sema.pt;
619 const zcu = pt.zcu;
620 const comp = zcu.comp;
621 const io = comp.io;
622 const ip = &zcu.intern_pool;
623
753 // Fields are okay. Now we need to resolve the union's overall layout (size, alignment, etc).
624754 var payload_align: Alignment = .@"1";
625755 var payload_size: u64 = 0;
626756 var comptime_only = false;
757 var has_runtime_bits = union_obj.runtime_tag != .none and enum_tag_ty.hasRuntimeBits(zcu);
627758 var possible_values: enum { none, one, many } = .none;
628759 for (0..union_obj.field_types.len) |field_idx| {
629760 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_idx]);
......@@ -637,6 +768,7 @@ pub fn finishUnionLayout(
637768 payload_align = payload_align.maxStrict(field_align);
638769 payload_size = @max(payload_size, field_ty.abiSize(zcu));
639770 if (field_ty.comptimeOnly(zcu)) comptime_only = true;
771 if (field_ty.hasRuntimeBits(zcu)) has_runtime_bits = true;
640772 if (!field_ty.isNoReturn(zcu)) {
641773 if (try field_ty.onePossibleValue(pt) != null) {
642774 possible_values = .many; // this field alone has many possible values
......@@ -664,78 +796,100 @@ pub fn finishUnionLayout(
664796 };
665797
666798 const casted_size = std.math.cast(u32, size) orelse return sema.fail(
667 block,
668 union_src,
799 &block,
800 union_ty.srcLoc(zcu),
669801 "union layout requires size {d}, this compiler implementation supports up to {d}",
670802 .{ size, std.math.maxInt(u32) },
671803 );
672804 ip.resolveUnionLayout(
673805 io,
674 union_ty,
806 union_ty.toIntern(),
807 enum_tag_ty.toIntern(),
675808 casted_size,
676809 @intCast(padding), // okay because padding is no greater than size
677810 alignment,
678811 possible_values == .none, // MLUGG TODO: make sure queries use `LoadedUnionType.has_no_possible_value`!
679812 possible_values == .one,
680813 comptime_only,
814 has_runtime_bits,
681815 );
682816}
683
684pub fn resolvePackedUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
817fn failUnionFieldMismatch(sema: *Sema, block: *Block, union_field_names: []const InternPool.NullTerminatedString, enum_tag_ty: Type, enum_obj: *const InternPool.LoadedEnumType) CompileError {
685818 const pt = sema.pt;
686819 const zcu = pt.zcu;
687820 const comp = zcu.comp;
688821 const gpa = comp.gpa;
689822 const ip = &zcu.intern_pool;
690
691 assert(sema.owner.unwrap().type_layout == union_ty.toIntern());
692
693 const union_obj = ip.loadUnionType(union_ty.toIntern());
694 const zir_index = union_obj.zir_index.resolve(ip).?;
695
696 assert(union_obj.layout == .@"packed");
697
698 try sema.declareDependency(.{ .src_hash = union_obj.zir_index });
699
700 var block: Block = .{
701 .parent = null,
702 .sema = sema,
703 .namespace = union_obj.namespace,
704 .instructions = .{},
705 .inlining = null,
706 .comptime_reason = undefined, // always set before using `block`
707 .src_base_inst = union_obj.zir_index,
708 .type_name_ctx = union_obj.name,
709 };
710 defer assert(block.instructions.items.len == 0);
711
712 const zir_union = sema.code.getUnionDecl(zir_index);
713 var field_it = zir_union.iterateFields();
714 while (field_it.next()) |zir_field| {
715 const field_ty_src: LazySrcLoc = .{
716 .base_node_inst = union_obj.zir_index,
717 .offset = .{ .container_field_type = zir_field.idx },
823 const enum_to_union_map = try sema.arena.alloc(?u32, enum_obj.field_names.len);
824 @memset(enum_to_union_map, null);
825 for (union_field_names, 0..) |field_name, union_field_index| {
826 if (enum_obj.nameIndex(ip, field_name)) |enum_field_index| {
827 enum_to_union_map[enum_field_index] = @intCast(union_field_index);
828 continue;
829 }
830 const union_field_src = block.src(.{ .container_field_name = @intCast(union_field_index) });
831 return sema.failWithOwnedErrorMsg(block, msg: {
832 const msg = try sema.errMsg(union_field_src, "no field named '{f}' in enum '{f}'", .{ field_name.fmt(ip), enum_tag_ty.fmt(pt) });
833 errdefer msg.destroy(gpa);
834 try sema.addDeclaredHereNote(msg, enum_tag_ty);
835 break :msg msg;
836 });
837 }
838 for (enum_to_union_map, 0..) |union_field_index, enum_field_index| {
839 if (union_field_index != null) continue;
840 const field_name_ip = enum_obj.field_names.get(ip)[enum_field_index];
841 const enum_field_src: LazySrcLoc = .{
842 .base_node_inst = enum_tag_ty.typeDeclInstAllowGeneratedTag(zcu).?,
843 .offset = .{ .container_field_name = @intCast(enum_field_index) },
718844 };
719 const field_ty: Type = field_ty: {
720 block.comptime_reason = .{ .reason = .{
721 .src = field_ty_src,
722 .r = .{ .simple = .union_field_types },
723 } };
724 // MLUGG TODO: i think this should probably be a compile error? (if so, it's an astgen one, right?)
725 const type_body = zir_field.type_body orelse break :field_ty .void;
726 const type_ref = try sema.resolveInlineBody(&block, type_body, zir_index);
727 break :field_ty try sema.analyzeAsType(&block, field_ty_src, type_ref);
845 return sema.failWithOwnedErrorMsg(block, msg: {
846 const msg = try sema.errMsg(block.nodeOffset(.zero), "enum field '{f}' missing from union", .{field_name_ip.fmt(ip)});
847 errdefer msg.destroy(gpa);
848 try sema.errNote(enum_field_src, msg, "enum field here", .{});
849 break :msg msg;
850 });
851 }
852 // The only problem is the field ordering.
853 for (enum_to_union_map, 0..) |union_field_index, enum_field_index| {
854 if (union_field_index.? == enum_field_index) continue;
855 const field_name = enum_obj.field_names.get(ip)[enum_field_index];
856 const union_field_src = block.src(.{ .container_field_name = union_field_index.? });
857 const enum_field_src: LazySrcLoc = .{
858 .base_node_inst = enum_tag_ty.typeDeclInstAllowGeneratedTag(zcu).?,
859 .offset = .{ .container_field_name = @intCast(enum_field_index) },
728860 };
729 assert(!field_ty.isGenericPoison());
730 union_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern();
731
732 assert(zir_field.align_body == null); // packed union fields cannot be aligned
733 assert(zir_field.value_body == null); // packed union fields cannot have tag values
861 return sema.failWithOwnedErrorMsg(block, msg: {
862 const msg = try sema.errMsg(block.nodeOffset(.zero), "union field order does not match tag enum field order", .{});
863 errdefer msg.destroy(gpa);
864 try sema.errNote(union_field_src, msg, "union field '{f}' is index {d}", .{ field_name.fmt(ip), union_field_index.? });
865 try sema.errNote(enum_field_src, msg, "enum field '{f}' is index {d}", .{ field_name.fmt(ip), enum_field_index });
866 break :msg msg;
867 });
868 }
869 unreachable; // we already determined that *something* is wrong
870}
871fn resolvePackedUnionLayout(
872 sema: *Sema,
873 block: *Block,
874 union_ty: Type,
875 union_obj: *const InternPool.LoadedUnionType,
876 enum_tag_ty: Type,
877) CompileError!void {
878 const pt = sema.pt;
879 const zcu = pt.zcu;
880 const comp = zcu.comp;
881 const io = comp.io;
882 const gpa = comp.gpa;
883 const ip = &zcu.intern_pool;
734884
885 // Resolve the layout of all fields, and check their types are allowed.
886 for (union_obj.field_types.get(ip), 0..) |field_ty_ip, field_index| {
887 const field_ty: Type = .fromInterned(field_ty_ip);
888 assert(!field_ty.isGenericPoison());
889 const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) });
735890 try sema.ensureLayoutResolved(field_ty);
736
737891 if (field_ty.zigTypeTag(zcu) == .@"opaque") {
738 return sema.failWithOwnedErrorMsg(&block, msg: {
892 return sema.failWithOwnedErrorMsg(block, msg: {
739893 const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in union", .{field_ty.fmt(pt)});
740894 errdefer msg.destroy(gpa);
741895 try sema.errNote(field_ty_src, msg, "opaque types have unknown size", .{});
......@@ -743,132 +897,109 @@ pub fn resolvePackedUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
743897 break :msg msg;
744898 });
745899 }
746 if (!field_ty.packable(zcu)) {
747 return sema.failWithOwnedErrorMsg(&block, msg: {
748 const msg = try sema.errMsg(field_ty_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
900 if (field_ty.unpackable(zcu)) |reason| return sema.failWithOwnedErrorMsg(block, msg: {
901 const msg = try sema.errMsg(field_ty_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
902 errdefer msg.destroy(gpa);
903 try sema.explainWhyTypeIsUnpackable(msg, field_ty_src, reason);
904 try sema.addDeclaredHereNote(msg, field_ty);
905 break :msg msg;
906 });
907 assert(!field_ty.comptimeOnly(zcu)); // packable types are not comptime-only
908 }
909
910 const explicit_backing_int_ty: ?Type = if (union_obj.is_reified) ty: {
911 switch (union_obj.packed_backing_mode) {
912 .explicit => break :ty .fromInterned(union_obj.packed_backing_int_type),
913 .auto => break :ty null,
914 }
915 } else ty: {
916 const zir_index = union_obj.zir_index.resolve(ip).?;
917 const zir_union = sema.code.getUnionDecl(zir_index);
918 const backing_int_type_body = zir_union.arg_type_body orelse {
919 break :ty null; // inferred backing type
920 };
921 // Explicitly specified, so evaluate the backing int type expression.
922 const backing_int_type_src = block.src(.container_arg);
923 block.comptime_reason = .{ .reason = .{
924 .src = backing_int_type_src,
925 .r = .{ .simple = .packed_union_backing_int_type },
926 } };
927 const type_ref = try sema.resolveInlineBody(block, backing_int_type_body, zir_index);
928 break :ty try sema.analyzeAsType(block, backing_int_type_src, .packed_union_backing_int_type, type_ref);
929 };
930
931 // Finally, either validate or infer the backing int type.
932 const backing_int_ty: Type = if (explicit_backing_int_ty) |backing_ty| ty: {
933 const backing_int_bits = backing_ty.intInfo(zcu).bits;
934 for (union_obj.field_types.get(ip), 0..) |field_type_ip, field_idx| {
935 const field_type: Type = .fromInterned(field_type_ip);
936 const field_bits = field_type.bitSize(zcu);
937 if (field_bits != backing_int_bits) return sema.failWithOwnedErrorMsg(block, msg: {
938 const field_ty_src = block.src(.{ .container_field_type = @intCast(field_idx) });
939 const msg = try sema.errMsg(field_ty_src, "field bit width does not match backing integer", .{});
749940 errdefer msg.destroy(gpa);
750 try sema.explainWhyTypeIsNotPackable(msg, field_ty_src, field_ty);
751 try sema.addDeclaredHereNote(msg, field_ty);
941 try sema.errNote(field_ty_src, msg, "field type '{f}' has bit width '{d}'", .{ field_type.fmt(pt), field_bits });
942 try sema.errNote(field_ty_src, msg, "backing integer '{f}' has bit width '{d}'", .{ backing_ty.fmt(pt), backing_int_bits });
943 try sema.errNote(field_ty_src, msg, "all fields in a packed union must have the same bit width", .{});
752944 break :msg msg;
753945 });
754946 }
755 assert(!field_ty.comptimeOnly(zcu)); // packable types are not comptime-only
756 }
757
758 try resolvePackedUnionBackingInt(sema, &block, union_ty, &union_obj, false);
947 break :ty backing_ty;
948 } else if (union_obj.field_types.len == 0) ty: {
949 // Special case: there is no first field to infer the type from. Treat the union as empty (zero-bit).
950 break :ty .u0;
951 } else ty: {
952 const field_types = union_obj.field_types.get(ip);
953 const first_field_type: Type = .fromInterned(field_types[0]);
954 const first_field_bits = first_field_type.bitSize(zcu);
955 for (field_types[1..], 1..) |field_type_ip, field_idx| {
956 const field_type: Type = .fromInterned(field_type_ip);
957 const field_bits = field_type.bitSize(zcu);
958 if (field_bits != first_field_bits) return sema.failWithOwnedErrorMsg(block, msg: {
959 const first_field_ty_src = block.src(.{ .container_field_type = 0 });
960 const field_ty_src = block.src(.{ .container_field_type = @intCast(field_idx) });
961 const msg = try sema.errMsg(field_ty_src, "field bit width does not match earlier field", .{});
962 errdefer msg.destroy(gpa);
963 try sema.errNote(field_ty_src, msg, "field type '{f}' has bit width '{d}'", .{ field_type.fmt(pt), field_bits });
964 try sema.errNote(first_field_ty_src, msg, "other field type '{f}' has bit width '{d}'", .{ first_field_type.fmt(pt), first_field_bits });
965 try sema.errNote(field_ty_src, msg, "all fields in a packed union must have the same bit width", .{});
966 break :msg msg;
967 });
968 }
969 const backing_int_bits = std.math.cast(u16, first_field_bits) orelse return sema.fail(
970 block,
971 union_ty.srcLoc(zcu),
972 "packed union bit width '{d}' exceeds maximum bit width of 65535",
973 .{first_field_bits},
974 );
975 break :ty try pt.intType(.unsigned, backing_int_bits);
976 };
977 ip.resolvePackedUnionLayout(
978 io,
979 union_ty.toIntern(),
980 enum_tag_ty.toIntern(),
981 backing_int_ty.toIntern(),
982 );
759983}
760984
761/// MLUGG TODO doc comment; asserts all fields are resolved or whatever
762pub fn resolvePackedUnionBackingInt(
763 sema: *Sema,
764 block: *Block,
765 union_ty: Type,
766 union_obj: *const InternPool.LoadedUnionType,
767 is_reified: bool,
768) SemaError!void {
985pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void {
769986 const pt = sema.pt;
770987 const zcu = pt.zcu;
771988 const comp = zcu.comp;
772 const gpa = comp.gpa;
773989 const io = comp.io;
774 const ip = &zcu.intern_pool;
775 switch (union_obj.packed_backing_mode) {
776 .explicit => {
777 const backing_int_type: Type = .fromInterned(union_obj.packed_backing_int_type);
778 const backing_int_bits = backing_int_type.intInfo(zcu).bits;
779 for (union_obj.field_types.get(ip), 0..) |field_type_ip, field_idx| {
780 const field_type: Type = .fromInterned(field_type_ip);
781 const field_bits = field_type.bitSize(zcu);
782 if (field_bits != backing_int_bits) return sema.failWithOwnedErrorMsg(block, msg: {
783 const field_ty_src: LazySrcLoc = .{
784 .base_node_inst = union_obj.zir_index,
785 .offset = if (is_reified)
786 .nodeOffset(.zero)
787 else
788 .{ .container_field_type = @intCast(field_idx) },
789 };
790 const msg = try sema.errMsg(field_ty_src, "field bit width does not match backing integer", .{});
791 errdefer msg.destroy(gpa);
792 try sema.errNote(field_ty_src, msg, "field type '{f}' has bit width '{d}'", .{ field_type.fmt(pt), field_bits });
793 try sema.errNote(field_ty_src, msg, "backing integer '{f}' has bit width '{d}'", .{ backing_int_type.fmt(pt), backing_int_bits });
794 try sema.errNote(field_ty_src, msg, "all fields in a packed union must have the same bit width", .{});
795 break :msg msg;
796 });
797 }
798 },
799 .auto => switch (union_obj.field_types.len) {
800 0 => ip.resolvePackedUnionBackingInt(io, union_ty.toIntern(), .u0_type),
801 else => {
802 const field_types = union_obj.field_types.get(ip);
803 const first_field_type: Type = .fromInterned(field_types[0]);
804 const first_field_bits = first_field_type.bitSize(zcu);
805 for (field_types[1..], 1..) |field_type_ip, field_idx| {
806 const field_type: Type = .fromInterned(field_type_ip);
807 const field_bits = field_type.bitSize(zcu);
808 if (field_bits != first_field_bits) return sema.failWithOwnedErrorMsg(block, msg: {
809 const first_field_ty_src: LazySrcLoc = .{
810 .base_node_inst = union_obj.zir_index,
811 .offset = if (is_reified)
812 .nodeOffset(.zero)
813 else
814 .{ .container_field_type = 0 },
815 };
816 const field_ty_src: LazySrcLoc = .{
817 .base_node_inst = union_obj.zir_index,
818 .offset = if (is_reified)
819 .nodeOffset(.zero)
820 else
821 .{ .container_field_type = @intCast(field_idx) },
822 };
823 const msg = try sema.errMsg(field_ty_src, "field bit width does not match earlier field", .{});
824 errdefer msg.destroy(gpa);
825 try sema.errNote(field_ty_src, msg, "field type '{f}' has bit width '{d}'", .{ field_type.fmt(pt), field_bits });
826 try sema.errNote(first_field_ty_src, msg, "other field type '{f}' has bit width '{d}'", .{ first_field_type.fmt(pt), first_field_bits });
827 try sema.errNote(field_ty_src, msg, "all fields in a packed union must have the same bit width", .{});
828 break :msg msg;
829 });
830 }
831 const backing_int_bits = std.math.cast(u16, first_field_bits) orelse return sema.fail(
832 block,
833 block.nodeOffset(.zero),
834 "packed union bit width '{d}' exceeds maximum bit width of 65535",
835 .{first_field_bits},
836 );
837 const backing_int_type = try pt.intType(.unsigned, backing_int_bits);
838 ip.resolvePackedUnionBackingInt(io, union_ty.toIntern(), backing_int_type.toIntern());
839 },
840 },
841 }
842}
843
844/// Asserts that `enum_ty` is an enum and that `sema.owner` is that type.
845/// This function *does* register the `src_hash` dependency on the enum.
846pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void {
847 const pt = sema.pt;
848 const zcu = pt.zcu;
849 const comp = zcu.comp;
850990 const gpa = comp.gpa;
851991 const ip = &zcu.intern_pool;
852992
853 assert(sema.owner.unwrap().type_inits == enum_ty.toIntern());
993 assert(sema.owner.unwrap().type_layout == enum_ty.toIntern());
854994
855995 const enum_obj = ip.loadEnumType(enum_ty.toIntern());
856996
857 // We'll populate this map.
858 const field_value_map = enum_obj.field_value_map.unwrap() orelse {
859 // The enum has an automatically generated tag and is auto-numbered. We know that we have
860 // generated a suitably large type in `analyzeEnumDecl`, so we have no work to do.
861 return;
862 };
863
864997 const maybe_parent_union_obj: ?InternPool.LoadedUnionType = un: {
865998 if (enum_obj.owner_union == .none) break :un null;
866999 break :un ip.loadUnionType(enum_obj.owner_union);
8671000 };
868 const tracked_inst = enum_obj.zir_index.unwrap() orelse maybe_parent_union_obj.?.zir_index;
869 const zir_index = tracked_inst.resolve(ip).?;
8701001
871 try sema.declareDependency(.{ .src_hash = tracked_inst });
1002 const tracked_inst = enum_obj.zir_index.unwrap() orelse maybe_parent_union_obj.?.zir_index;
8721003
8731004 var block: Block = .{
8741005 .parent = null,
......@@ -882,7 +1013,139 @@ pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void {
8821013 };
8831014 defer assert(block.instructions.items.len == 0);
8841015
885 const int_tag_ty: Type = .fromInterned(enum_obj.int_tag_type);
1016 // There may be old field names in the map from a previous update.
1017 enum_obj.field_name_map.get(ip).clearRetainingCapacity();
1018
1019 if (maybe_parent_union_obj) |*union_obj| {
1020 if (union_obj.is_reified) {
1021 // In the case of reification, the union stores the field names, just for us to copy.
1022 @memcpy(enum_obj.field_names.get(ip), union_obj.reified_field_names.get(ip));
1023 // The list of field names is now populated, but we haven't checked for duplicates yet,
1024 // nor have we populated the hash map.
1025 for (0..enum_obj.field_names.len) |field_index| {
1026 const name = enum_obj.field_names.get(ip)[field_index];
1027 if (ip.addFieldName(enum_obj.field_names, enum_obj.field_name_map, name)) |prev_field_index| {
1028 return sema.failWithOwnedErrorMsg(&block, msg: {
1029 const src = block.nodeOffset(.zero);
1030 const msg = try sema.errMsg(src, "duplicate union field '{f}' at index '{d}", .{ name.fmt(ip), field_index });
1031 errdefer msg.destroy(gpa);
1032 try sema.errNote(src, msg, "previous field at index '{d}'", .{prev_field_index});
1033 break :msg msg;
1034 });
1035 }
1036 }
1037 } else {
1038 // Generated tag enums for declared unions do not yet have field names populated. It is
1039 // our job to populate them now.
1040 try sema.declareDependency(.{ .src_hash = union_obj.zir_index });
1041 const zir_union = sema.code.getUnionDecl(union_obj.zir_index.resolve(ip).?);
1042 for (zir_union.field_names) |zir_field_name| {
1043 const name_slice = sema.code.nullTerminatedString(zir_field_name);
1044 const name = try ip.getOrPutString(gpa, io, pt.tid, name_slice, .no_embedded_nulls);
1045 assert(ip.addFieldName(enum_obj.field_names, enum_obj.field_name_map, name) == null); // AstGen validated this for us
1046 }
1047 }
1048 } else {
1049 if (enum_obj.is_reified) {
1050 // The field names are populated, but we haven't checked for duplicates (nor populated the map) yet.
1051 for (0..enum_obj.field_names.len) |field_index| {
1052 const name = enum_obj.field_names.get(ip)[field_index];
1053 if (ip.addFieldName(enum_obj.field_names, enum_obj.field_name_map, name)) |prev_field_index| {
1054 return sema.failWithOwnedErrorMsg(&block, msg: {
1055 const src = block.nodeOffset(.zero);
1056 const msg = try sema.errMsg(src, "duplicate enum field '{f}' at index '{d}", .{ name.fmt(ip), field_index });
1057 errdefer msg.destroy(gpa);
1058 try sema.errNote(src, msg, "previous field at index '{d}'", .{prev_field_index});
1059 break :msg msg;
1060 });
1061 }
1062 }
1063 } else {
1064 // Declared enums do not yet have field names populated. It is our job to populate them now.
1065 try sema.declareDependency(.{ .src_hash = enum_obj.zir_index.unwrap().? });
1066 const zir_enum = sema.code.getEnumDecl(enum_obj.zir_index.unwrap().?.resolve(ip).?);
1067 for (zir_enum.field_names) |zir_field_name| {
1068 const name_slice = sema.code.nullTerminatedString(zir_field_name);
1069 const name = try ip.getOrPutString(gpa, io, pt.tid, name_slice, .no_embedded_nulls);
1070 assert(ip.addFieldName(enum_obj.field_names, enum_obj.field_name_map, name) == null); // AstGen validated this for us
1071 }
1072 }
1073 }
1074
1075 // Field names populated; now deal with the backing integer type. If explicitly provided,
1076 // validate it; otherwise, infer it.
1077
1078 const explicit_int_tag_ty: ?Type = if (enum_obj.is_reified) ty: {
1079 break :ty switch (enum_obj.int_tag_mode) {
1080 .explicit => .fromInterned(enum_obj.int_tag_type),
1081 .auto => null,
1082 };
1083 } else if (maybe_parent_union_obj) |*union_obj| ty: {
1084 if (union_obj.is_reified) {
1085 // Reification has no equivalent of 'union(enum(T))'.
1086 break :ty null;
1087 }
1088 const zir_index = union_obj.zir_index.resolve(ip).?;
1089 const zir_union = sema.code.getUnionDecl(zir_index);
1090 if (zir_union.kind != .tagged_enum_explicit) {
1091 break :ty null; // int tag type will be inferred
1092 }
1093 // Explicitly specified, so evaluate the int tag type expression.
1094 const tag_type_body = zir_union.arg_type_body.?;
1095 const tag_type_src = block.src(.container_arg);
1096 block.comptime_reason = .{ .reason = .{
1097 .src = tag_type_src,
1098 .r = .{ .simple = .enum_int_tag_type },
1099 } };
1100 const type_ref = try sema.resolveInlineBody(&block, tag_type_body, zir_index);
1101 break :ty try sema.analyzeAsType(&block, tag_type_src, .enum_int_tag_type, type_ref);
1102 } else ty: {
1103 const zir_index = enum_obj.zir_index.unwrap().?.resolve(ip).?;
1104 const zir_enum = sema.code.getEnumDecl(zir_index);
1105 const tag_type_body = zir_enum.tag_type_body orelse {
1106 break :ty null; // int tag type will be inferred
1107 };
1108 // Explicitly specified, so evaluate the int tag type expression.
1109 const tag_type_src = block.src(.container_arg);
1110 block.comptime_reason = .{ .reason = .{
1111 .src = tag_type_src,
1112 .r = .{ .simple = .enum_int_tag_type },
1113 } };
1114 const type_ref = try sema.resolveInlineBody(&block, tag_type_body, zir_index);
1115 break :ty try sema.analyzeAsType(&block, tag_type_src, .enum_int_tag_type, type_ref);
1116 };
1117 const int_tag_ty: Type = if (explicit_int_tag_ty) |int_tag_ty| ty: {
1118 if (int_tag_ty.zigTypeTag(zcu) != .int) return sema.fail(
1119 &block,
1120 block.src(.container_arg),
1121 "expected integer tag type, found '{f}'",
1122 .{int_tag_ty.fmt(pt)},
1123 );
1124 break :ty int_tag_ty;
1125 } else ty: {
1126 // Infer the int tag type from the field count
1127 const bits = Type.smallestUnsignedBits(enum_obj.field_names.len -| 1);
1128 break :ty try pt.intType(.unsigned, bits);
1129 };
1130
1131 ip.resolveEnumLayout(io, enum_ty.toIntern(), int_tag_ty.toIntern());
1132
1133 // Finally, deal with field values. For declared types we need to analyze the expressions, while
1134 // reified types already have them populated; but either way, we need to populate the hash map
1135 // (and validate the values along the way).
1136
1137 // We'll populate this map.
1138 const field_value_map = enum_obj.field_value_map.unwrap() orelse {
1139 // The enum is auto-numbered with an inferred tag type. We know that the tag type generated
1140 // earlier is sufficient for the number of fields, so we have nothing more to do.
1141 assert(enum_obj.int_tag_mode == .auto);
1142 return;
1143 };
1144
1145 // There may be old field values in here from a previous update.
1146 field_value_map.get(ip).clearRetainingCapacity();
1147
1148 const zir_index = tracked_inst.resolve(ip).?;
8861149
8871150 // Map the enum (or union) decl instruction to provide the tag type as the result type
8881151 try sema.inst_map.ensureSpaceForInstructions(gpa, &.{zir_index});
......@@ -891,36 +1154,38 @@ pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void {
8911154
8921155 // First, populate any explicitly provided values. This is the part that actually depends on
8931156 // the ZIR, and hence depends on whether this is a declared or generated enum. If any explicit
894 // value is invalid, we'll emit an error here.
1157 // value is straight-up invalid, we'll emit an error here.
8951158 if (maybe_parent_union_obj) |union_obj| {
896 const zir_union = sema.code.getUnionDecl(zir_index);
897 var field_it = zir_union.iterateFields();
898 while (field_it.next()) |zir_field| {
899 const field_val_src: LazySrcLoc = .{
900 .base_node_inst = union_obj.zir_index,
901 .offset = .{ .container_field_value = zir_field.idx },
902 };
903 block.comptime_reason = .{ .reason = .{
904 .src = field_val_src,
905 .r = .{ .simple = .enum_field_values },
906 } };
907 const value_body = zir_field.value_body orelse {
908 enum_obj.field_values.get(ip)[zir_field.idx] = .none;
909 continue;
910 };
911 const uncoerced = try sema.resolveInlineBody(&block, value_body, zir_index);
912 const coerced = try sema.coerce(&block, int_tag_ty, uncoerced, field_val_src);
913 const val = try sema.resolveConstValue(&block, field_val_src, coerced, null);
914 enum_obj.field_values.get(ip)[zir_field.idx] = val.toIntern();
1159 if (union_obj.is_reified) {
1160 // Generated tag type for reified union; values already populated.
1161 } else {
1162 // Generated tag type for declared union; evaluate the expressions given in the union declaration.
1163 const zir_union = sema.code.getUnionDecl(zir_index);
1164 var field_it = zir_union.iterateFields();
1165 while (field_it.next()) |zir_field| {
1166 const field_val_src = block.src(.{ .container_field_value = zir_field.idx });
1167 block.comptime_reason = .{ .reason = .{
1168 .src = field_val_src,
1169 .r = .{ .simple = .enum_field_values },
1170 } };
1171 const value_body = zir_field.value_body orelse {
1172 enum_obj.field_values.get(ip)[zir_field.idx] = .none;
1173 continue;
1174 };
1175 const uncoerced = try sema.resolveInlineBody(&block, value_body, zir_index);
1176 const coerced = try sema.coerce(&block, int_tag_ty, uncoerced, field_val_src);
1177 const val = try sema.resolveConstValue(&block, field_val_src, coerced, null);
1178 enum_obj.field_values.get(ip)[zir_field.idx] = val.toIntern();
1179 }
9151180 }
1181 } else if (enum_obj.is_reified) {
1182 // Reified enum; values already populated.
9161183 } else {
1184 // Declared enum; evaluate the expressions given in the enum declaration.
9171185 const zir_enum = sema.code.getEnumDecl(zir_index);
9181186 var field_it = zir_enum.iterateFields();
9191187 while (field_it.next()) |zir_field| {
920 const field_val_src: LazySrcLoc = .{
921 .base_node_inst = enum_obj.zir_index.unwrap().?,
922 .offset = .{ .container_field_value = zir_field.idx },
923 };
1188 const field_val_src = block.src(.{ .container_field_value = zir_field.idx });
9241189 block.comptime_reason = .{ .reason = .{
9251190 .src = field_val_src,
9261191 .r = .{ .simple = .enum_field_values },
......@@ -940,14 +1205,14 @@ pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void {
9401205 // field values. This is also where we'll detect duplicates.
9411206
9421207 for (0..enum_obj.field_names.len) |field_idx| {
943 const field_val_src: LazySrcLoc = .{
944 .base_node_inst = tracked_inst,
945 .offset = .{ .container_field_value = @intCast(field_idx) },
946 };
1208 const field_val_src = block.src(.{ .container_field_value = @intCast(field_idx) });
9471209 // If the field value was not specified, compute the implicit value.
9481210 const field_val = val: {
9491211 const explicit_val = enum_obj.field_values.get(ip)[field_idx];
950 if (explicit_val != .none) break :val explicit_val;
1212 if (explicit_val != .none) {
1213 assert(ip.typeOf(explicit_val) == int_tag_ty.toIntern());
1214 break :val explicit_val;
1215 }
9511216 if (field_idx == 0) {
9521217 // Implicit value is 0, which is valid for every integer type.
9531218 const val = (try pt.intValue(int_tag_ty, 0)).toIntern();
......@@ -967,23 +1232,23 @@ pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void {
9671232 enum_obj.field_values.get(ip)[field_idx] = val;
9681233 break :val val;
9691234 };
970 const adapter: InternPool.Index.Adapter = .{ .indexes = enum_obj.field_values.get(ip)[0..field_idx] };
971 const gop = field_value_map.get(ip).getOrPutAssumeCapacityAdapted(field_val, adapter);
972 if (!gop.found_existing) continue;
973 const prev_field_val_src: LazySrcLoc = .{
974 .base_node_inst = tracked_inst,
975 .offset = .{ .container_field_value = @intCast(gop.index) },
976 };
977 return sema.failWithOwnedErrorMsg(&block, msg: {
978 const msg = try sema.errMsg(field_val_src, "enum tag value '{f}' already taken", .{
979 Value.fromInterned(field_val).fmtValueSema(pt, sema),
1235 if (ip.addFieldTagValue(enum_obj.field_values, field_value_map, field_val)) |prev_field_index| {
1236 return sema.failWithOwnedErrorMsg(&block, msg: {
1237 const prev_field_val_src = block.src(.{ .container_field_value = prev_field_index });
1238 const msg = try sema.errMsg(field_val_src, "enum tag value '{f}' for field '{f}' already taken", .{
1239 Value.fromInterned(field_val).fmtValueSema(pt, sema),
1240 enum_obj.field_names.get(ip)[field_idx].fmt(ip),
1241 });
1242 errdefer msg.destroy(gpa);
1243 try sema.errNote(prev_field_val_src, msg, "previous occurrence in field '{f}'", .{
1244 enum_obj.field_names.get(ip)[prev_field_index].fmt(ip),
1245 });
1246 break :msg msg;
9801247 });
981 errdefer msg.destroy(gpa);
982 try sema.errNote(prev_field_val_src, msg, "previous occurrence here", .{});
983 break :msg msg;
984 });
1248 }
9851249 }
9861250
1251 // MLUGG TODO: fate of this line rests on whether comptime_int is a valid int tag type
9871252 if (enum_obj.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) {
9881253 const fields_len = enum_obj.field_names.len;
9891254 if (fields_len >= 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(zcu)) {
src/Type.zig+250-123
......@@ -437,6 +437,7 @@ pub fn toValue(self: Type) Value {
437437/// - an enum with an explicit tag type has the ABI size of the integer tag type,
438438/// making it one-possible-value only if the integer tag type has 0 bits.
439439pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool {
440 ty.assertHasLayout(zcu);
440441 const ip = &zcu.intern_pool;
441442 return switch (ip.indexToKey(ty.toIntern())) {
442443 .int_type => |int_type| int_type.bits != 0,
......@@ -499,14 +500,18 @@ pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool {
499500 .generic_poison => unreachable,
500501 },
501502 .struct_type => {
502 // TODO MLUGG: memoize this state when resolving struct?
503503 const struct_obj = ip.loadStructType(ty.toIntern());
504 for (struct_obj.field_types.get(ip), 0..) |field_ty_ip, field_idx| {
505 if (struct_obj.field_is_comptime_bits.get(ip, field_idx)) continue;
506 const field_ty: Type = .fromInterned(field_ty_ip);
507 if (field_ty.hasRuntimeBits(zcu)) return true;
504 switch (struct_obj.layout) {
505 .auto, .@"extern" => return struct_obj.has_runtime_bits,
506 .@"packed" => return Type.fromInterned(struct_obj.packed_backing_int_type).hasRuntimeBits(zcu),
507 }
508 },
509 .union_type => {
510 const union_obj = ip.loadUnionType(ty.toIntern());
511 switch (union_obj.layout) {
512 .auto, .@"extern" => return union_obj.has_runtime_bits,
513 .@"packed" => return Type.fromInterned(union_obj.packed_backing_int_type).hasRuntimeBits(zcu),
508514 }
509 return false;
510515 },
511516 .tuple_type => |tuple| {
512517 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
......@@ -515,23 +520,8 @@ pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool {
515520 }
516521 return false;
517522 },
518 .union_type => {
519 // TODO MLUGG: memoize this state when resolving union?
520 const union_obj = ip.loadUnionType(ty.toIntern());
521 switch (union_obj.runtime_tag) {
522 .none => {},
523 .safety, .tagged => {
524 if (Type.fromInterned(union_obj.enum_tag_type).hasRuntimeBits(zcu)) return true;
525 },
526 }
527 for (union_obj.field_types.get(ip)) |field_ty_ip| {
528 const field_ty: Type = .fromInterned(field_ty_ip);
529 if (field_ty.hasRuntimeBits(zcu)) return true;
530 }
531 return false;
532 },
533523
534 // MLUGG TODO: i think this can go away and the assert move to the defer?
524 // MLUGG TODO: this answer was already here but... does it actually make sense?
535525 .opaque_type => true,
536526 .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).hasRuntimeBits(zcu),
537527
......@@ -618,17 +608,18 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool {
618608 .generic_poison,
619609 => false,
620610 },
621 .struct_type => ip.loadStructType(ty.toIntern()).layout != .auto,
622 .union_type => {
623 const union_obj = ip.loadUnionType(ty.toIntern());
624 if (union_obj.layout == .auto) return false;
625 return switch (union_obj.runtime_tag) {
626 .none => true,
627 .tagged => false,
628 .safety => unreachable, // well-defined layout can't have a safety tag
629 };
611 .struct_type => switch (ip.loadStructType(ty.toIntern()).layout) {
612 .auto => false,
613 .@"extern", .@"packed" => true,
614 },
615 .union_type => switch (ip.loadUnionType(ty.toIntern()).layout) {
616 .auto => false,
617 .@"extern", .@"packed" => true,
618 },
619 .enum_type => switch (ip.loadEnumType(ty.toIntern()).int_tag_mode) {
620 .explicit => true,
621 .auto => false,
630622 },
631 .enum_type => ip.loadEnumType(ty.toIntern()).int_tag_is_explicit,
632623
633624 // values, not types
634625 .undef,
......@@ -664,28 +655,29 @@ pub fn fnHasRuntimeBits(fn_ty: Type, zcu: *Zcu) bool {
664655 if (param_ty == .generic_poison_type) return false;
665656 if (Type.fromInterned(param_ty).comptimeOnly(zcu)) return false;
666657 }
658 const ret_ty: Type = .fromInterned(fn_info.return_type);
659 if (ret_ty.toIntern() == .generic_poison_type) {
660 return false;
661 }
662 if (ret_ty.zigTypeTag(zcu) == .error_union and
663 ret_ty.errorUnionPayload(zcu).toIntern() == .generic_poison_type)
664 {
665 return false;
666 }
667667 if (fn_info.return_type == .generic_poison_type) return false;
668668 if (Type.fromInterned(fn_info.return_type).comptimeOnly(zcu)) return false;
669669 if (fn_info.cc == .@"inline") return false;
670670 return true;
671671}
672672
673pub fn isFnOrHasRuntimeBits(ty: Type, zcu: *Zcu) bool {
673/// Like `hasRuntimeBits`, but also returns `true` for runtime functions.
674pub fn isRuntimeFnOrHasRuntimeBits(ty: Type, zcu: *Zcu) bool {
674675 switch (ty.zigTypeTag(zcu)) {
675676 .@"fn" => return ty.fnHasRuntimeBits(zcu),
676677 else => return ty.hasRuntimeBits(zcu),
677678 }
678679}
679680
680/// Same as `isFnOrHasRuntimeBits` but comptime-only types may return a false positive.
681/// MLUGG TODO: this function is a bit silly now...
682pub fn isFnOrHasRuntimeBitsIgnoreComptime(ty: Type, zcu: *Zcu) bool {
683 return switch (ty.zigTypeTag(zcu)) {
684 .@"fn" => true,
685 else => return ty.hasRuntimeBits(zcu),
686 };
687}
688
689681pub fn isNoReturn(ty: Type, zcu: *const Zcu) bool {
690682 return zcu.intern_pool.isNoReturn(ty.toIntern());
691683}
......@@ -711,7 +703,6 @@ pub fn ptrAddressSpace(ty: Type, zcu: *const Zcu) std.builtin.AddressSpace {
711703}
712704
713705/// Never returns `none`. Asserts that all necessary type resolution is already done.
714/// MLUGG TODO: check that it really does never return `.none`
715706pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {
716707 const ip = &zcu.intern_pool;
717708 const target = zcu.getTarget();
......@@ -810,7 +801,7 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {
810801 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
811802 if (val != .none) continue; // comptime field
812803 const field_align = Type.fromInterned(field_ty).abiAlignment(zcu);
813 big_align = big_align.max(field_align);
804 big_align = big_align.maxStrict(field_align);
814805 }
815806 return big_align;
816807 },
......@@ -818,14 +809,20 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {
818809 const struct_obj = ip.loadStructType(ty.toIntern());
819810 switch (struct_obj.layout) {
820811 .@"packed" => return Type.fromInterned(struct_obj.packed_backing_int_type).abiAlignment(zcu),
821 .auto, .@"extern" => return struct_obj.alignment,
812 .auto, .@"extern" => {
813 assert(struct_obj.alignment != .none);
814 return struct_obj.alignment;
815 },
822816 }
823817 },
824818 .union_type => {
825819 const union_obj = ip.loadUnionType(ty.toIntern());
826820 switch (union_obj.layout) {
827821 .@"packed" => return Type.fromInterned(union_obj.packed_backing_int_type).abiAlignment(zcu),
828 .auto, .@"extern" => return getUnionLayout(union_obj, zcu).abi_align,
822 .auto, .@"extern" => {
823 assert(union_obj.alignment != .none);
824 return union_obj.alignment;
825 },
829826 }
830827 },
831828 .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).abiAlignment(zcu),
......@@ -1277,38 +1274,17 @@ pub fn nullablePtrElem(ty: Type, zcu: *const Zcu) Type {
12771274 }
12781275}
12791276
1280/// Given that `ty` is an indexable pointer, returns its element type. Specifically:
1281/// * for `*[n]T`, returns `T`
1282/// * for `*@Vector(n, T)`, returns `T`
1283/// * for `[]T`, returns `T`
1284/// * for `[*]T`, returns `T`
1285/// * for `[*c]T`, returns `T`
1286///
1287/// Tuples are not supported because they do not have a single element type.
1277/// Asserts that `ty` is an indexable type, and returns its element type. Tuples (and pointers to
1278/// tuples) are not supported because they do not have a single element type.
12881279///
1289/// MLUGG TODO: should i even have this one? it's a subset of indexableElem
1290pub fn indexablePtrElem(ty: Type, zcu: *const Zcu) Type {
1291 const ip = &zcu.intern_pool;
1292 const ptr_type = ip.indexToKey(ty.toIntern()).ptr_type;
1293 return switch (ptr_type.flags.size) {
1294 .many, .slice, .c => return .fromInterned(ptr_type.child),
1295 .one => switch (ip.indexToKey(ptr_type.child)) {
1296 inline .array_type, .vector_type => |arr| return .fromInterned(arr.child),
1297 else => unreachable,
1298 },
1299 };
1300}
1301
1302/// Given that `ty` is an indexable type, returns its element type. Specifically:
1303/// * for `[n]T`, returns `T`
1304/// * for `@Vector(n, T)`, returns `T`
1305/// * for `*[n]T`, returns `T`
1306/// * for `*@Vector(n, T)`, returns `T`
1307/// * for `[]T`, returns `T`
1308/// * for `[*]T`, returns `T`
1309/// * for `[*c]T`, returns `T`
1310///
1311/// Tuples are not supported because they do not have a single element type.
1280/// Returns `T` for each of the following types:
1281/// * `[n]T`
1282/// * `@Vector(n, T)`
1283/// * `*[n]T`
1284/// * `*@Vector(n, T)`
1285/// * `[]T`
1286/// * `[*]T`
1287/// * `[*c]T`
13121288pub fn indexableElem(ty: Type, zcu: *const Zcu) Type {
13131289 const ip = &zcu.intern_pool;
13141290 return switch (ip.indexToKey(ty.toIntern())) {
......@@ -1348,6 +1324,7 @@ pub fn optionalChild(ty: Type, zcu: *const Zcu) Type {
13481324/// Returns the tag type of a union, if the type is a union and it has a tag type.
13491325/// Otherwise, returns `null`.
13501326pub fn unionTagType(ty: Type, zcu: *const Zcu) ?Type {
1327 assertHasLayout(ty, zcu);
13511328 const ip = &zcu.intern_pool;
13521329 switch (ip.indexToKey(ty.toIntern())) {
13531330 .union_type => {},
......@@ -1363,6 +1340,7 @@ pub fn unionTagType(ty: Type, zcu: *const Zcu) ?Type {
13631340/// Same as `unionTagType` but includes safety tag.
13641341/// Codegen should use this version.
13651342pub fn unionTagTypeSafety(ty: Type, zcu: *const Zcu) ?Type {
1343 assertHasLayout(ty, zcu);
13661344 const ip = &zcu.intern_pool;
13671345 return switch (ip.indexToKey(ty.toIntern())) {
13681346 .union_type => {
......@@ -1377,11 +1355,13 @@ pub fn unionTagTypeSafety(ty: Type, zcu: *const Zcu) ?Type {
13771355/// Asserts the type is a union; returns the tag type, even if the tag will
13781356/// not be stored at runtime.
13791357pub fn unionTagTypeHypothetical(ty: Type, zcu: *const Zcu) Type {
1358 assertHasLayout(ty, zcu);
13801359 const union_obj = zcu.typeToUnion(ty).?;
13811360 return Type.fromInterned(union_obj.enum_tag_type);
13821361}
13831362
13841363pub fn unionFieldType(ty: Type, enum_tag: Value, zcu: *const Zcu) ?Type {
1364 assertHasLayout(ty, zcu);
13851365 const ip = &zcu.intern_pool;
13861366 const union_obj = zcu.typeToUnion(ty).?;
13871367 const union_fields = union_obj.field_types.get(ip);
......@@ -1390,17 +1370,20 @@ pub fn unionFieldType(ty: Type, enum_tag: Value, zcu: *const Zcu) ?Type {
13901370}
13911371
13921372pub fn unionFieldTypeByIndex(ty: Type, index: usize, zcu: *const Zcu) Type {
1373 assertHasLayout(ty, zcu);
13931374 const ip = &zcu.intern_pool;
13941375 const union_obj = zcu.typeToUnion(ty).?;
13951376 return Type.fromInterned(union_obj.field_types.get(ip)[index]);
13961377}
13971378
13981379pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 {
1380 assertHasLayout(ty, zcu);
13991381 const union_obj = zcu.typeToUnion(ty).?;
14001382 return zcu.unionTagFieldIndex(union_obj, enum_tag);
14011383}
14021384
14031385pub fn unionHasAllZeroBitFieldTypes(ty: Type, zcu: *Zcu) bool {
1386 assertHasLayout(ty, zcu);
14041387 const ip = &zcu.intern_pool;
14051388 const union_obj = zcu.typeToUnion(ty).?;
14061389 for (union_obj.field_types.get(ip)) |field_ty| {
......@@ -1413,14 +1396,17 @@ pub fn unionHasAllZeroBitFieldTypes(ty: Type, zcu: *Zcu) bool {
14131396/// Asserts the type is either an extern or packed union.
14141397pub fn unionBackingType(ty: Type, pt: Zcu.PerThread) !Type {
14151398 const zcu = pt.zcu;
1416 return switch (ty.containerLayout(zcu)) {
1399 assertHasLayout(ty, zcu);
1400 const loaded_union = zcu.intern_pool.loadUnionType(ty.toIntern());
1401 return switch (loaded_union.layout) {
14171402 .@"extern" => try pt.arrayType(.{ .len = ty.abiSize(zcu), .child = .u8_type }),
1418 .@"packed" => try pt.intType(.unsigned, @intCast(ty.bitSize(zcu))),
1403 .@"packed" => .fromInterned(loaded_union.packed_backing_int_type),
14191404 .auto => unreachable,
14201405 };
14211406}
14221407
14231408pub fn unionGetLayout(ty: Type, zcu: *const Zcu) Zcu.UnionLayout {
1409 assertHasLayout(ty, zcu);
14241410 const union_obj = zcu.intern_pool.loadUnionType(ty.toIntern());
14251411 return Type.getUnionLayout(union_obj, zcu);
14261412}
......@@ -1865,11 +1851,8 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value {
18651851 for (field_vals, 0..) |*field_val, i_usize| {
18661852 const i: u32 = @intCast(i_usize);
18671853 if (struct_obj.field_is_comptime_bits.get(ip, i)) {
1868 // MLUGG TODO: this is kinda a problem... we don't necessarily know the opv field vals!
1869 // for now i'm just not letting structs with comptime fields be opv :)
1870 if (true) return null;
1871 assertHasInits(ty, zcu);
18721854 field_val.* = struct_obj.field_defaults.get(ip)[i];
1855 assert(field_val.* != .none);
18731856 continue;
18741857 }
18751858 const field_ty = Type.fromInterned(struct_obj.field_types.get(ip)[i]);
......@@ -2257,19 +2240,23 @@ pub fn errorSetNames(ty: Type, zcu: *const Zcu) InternPool.NullTerminatedString.
22572240}
22582241
22592242pub fn enumFields(ty: Type, zcu: *const Zcu) InternPool.NullTerminatedString.Slice {
2243 assertHasLayout(ty, zcu);
22602244 return zcu.intern_pool.loadEnumType(ty.toIntern()).field_names;
22612245}
22622246
22632247pub fn enumFieldCount(ty: Type, zcu: *const Zcu) usize {
2248 assertHasLayout(ty, zcu);
22642249 return zcu.intern_pool.loadEnumType(ty.toIntern()).field_names.len;
22652250}
22662251
22672252pub fn enumFieldName(ty: Type, field_index: usize, zcu: *const Zcu) InternPool.NullTerminatedString {
2253 assertHasLayout(ty, zcu);
22682254 const ip = &zcu.intern_pool;
22692255 return ip.loadEnumType(ty.toIntern()).field_names.get(ip)[field_index];
22702256}
22712257
22722258pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, zcu: *const Zcu) ?u32 {
2259 assertHasLayout(ty, zcu);
22732260 const ip = &zcu.intern_pool;
22742261 const enum_type = ip.loadEnumType(ty.toIntern());
22752262 return enum_type.nameIndex(ip, field_name);
......@@ -2279,6 +2266,7 @@ pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, zcu
22792266/// an integer which represents the enum value. Returns the field index in
22802267/// declaration order, or `null` if `enum_tag` does not match any field.
22812268pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 {
2269 assertHasLayout(ty, zcu);
22822270 const ip = &zcu.intern_pool;
22832271 const enum_type = ip.loadEnumType(ty.toIntern());
22842272 const int_tag = switch (ip.indexToKey(enum_tag.toIntern())) {
......@@ -2293,28 +2281,40 @@ pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 {
22932281/// Returns none in the case of a tuple which uses the integer index as the field name.
22942282pub fn structFieldName(ty: Type, index: usize, zcu: *const Zcu) InternPool.OptionalNullTerminatedString {
22952283 const ip = &zcu.intern_pool;
2296 return switch (ip.indexToKey(ty.toIntern())) {
2297 .struct_type => ip.loadStructType(ty.toIntern()).field_names.get(ip)[index].toOptional(),
2298 .tuple_type => .none,
2284 switch (ip.indexToKey(ty.toIntern())) {
2285 .struct_type => {
2286 assertHasLayout(ty, zcu);
2287 return ip.loadStructType(ty.toIntern()).field_names.get(ip)[index].toOptional();
2288 },
2289 .tuple_type => return .none,
22992290 else => unreachable,
2300 };
2291 }
23012292}
23022293
23032294pub fn structFieldCount(ty: Type, zcu: *const Zcu) u32 {
23042295 const ip = &zcu.intern_pool;
2305 return switch (ip.indexToKey(ty.toIntern())) {
2306 .struct_type => ip.loadStructType(ty.toIntern()).field_types.len,
2307 .tuple_type => |tuple| tuple.types.len,
2296 switch (ip.indexToKey(ty.toIntern())) {
2297 .struct_type => {
2298 assertHasLayout(ty, zcu);
2299 return ip.loadStructType(ty.toIntern()).field_types.len;
2300 },
2301 .tuple_type => |tuple| return tuple.types.len,
23082302 else => unreachable,
2309 };
2303 }
23102304}
23112305
23122306/// Returns the field type. Supports structs and unions.
23132307pub fn fieldType(ty: Type, index: usize, zcu: *const Zcu) Type {
23142308 const ip = &zcu.intern_pool;
23152309 const types = switch (ip.indexToKey(ty.toIntern())) {
2316 .struct_type => ip.loadStructType(ty.toIntern()).field_types,
2317 .union_type => ip.loadUnionType(ty.toIntern()).field_types,
2310 .struct_type => types: {
2311 assertHasLayout(ty, zcu);
2312 break :types ip.loadStructType(ty.toIntern()).field_types;
2313 },
2314 .union_type => types: {
2315 assertHasLayout(ty, zcu);
2316 break :types ip.loadUnionType(ty.toIntern()).field_types;
2317 },
23182318 .tuple_type => |tuple| tuple.types,
23192319 else => unreachable,
23202320 };
......@@ -2335,11 +2335,13 @@ pub fn resolvedFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment
23352335 return switch (ip.indexToKey(ty.toIntern())) {
23362336 .tuple_type => |tuple| Type.fromInterned(tuple.types.get(ip)[index]).abiAlignment(zcu),
23372337 .struct_type => {
2338 assertHasLayout(ty, zcu);
23382339 const struct_obj = ip.loadStructType(ty.toIntern());
23392340 const field_ty: Type = .fromInterned(struct_obj.field_types.get(ip)[index]);
23402341 return field_ty.defaultStructFieldAlignment(struct_obj.layout, zcu);
23412342 },
23422343 .union_type => {
2344 assertHasLayout(ty, zcu);
23432345 const union_obj = ip.loadUnionType(ty.toIntern());
23442346 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[index]);
23452347 return field_ty.abiAlignment(zcu);
......@@ -2353,12 +2355,14 @@ pub fn explicitFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment
23532355 return switch (ip.indexToKey(ty.toIntern())) {
23542356 .tuple_type => .none,
23552357 .struct_type => {
2358 assertHasLayout(ty, zcu);
23562359 const struct_obj = ip.loadStructType(ty.toIntern());
23572360 assert(struct_obj.layout != .@"packed");
23582361 if (struct_obj.field_aligns.len == 0) return .none;
23592362 return struct_obj.field_aligns.get(ip)[index];
23602363 },
23612364 .union_type => {
2365 assertHasLayout(ty, zcu);
23622366 const union_obj = ip.loadUnionType(ty.toIntern());
23632367 assert(union_obj.layout != .@"packed");
23642368 if (union_obj.field_aligns.len == 0) return .none;
......@@ -2413,7 +2417,6 @@ pub fn structFieldValueComptime(ty: Type, pt: Zcu.PerThread, index: usize) !?Val
24132417 .struct_type => {
24142418 const struct_type = ip.loadStructType(ty.toIntern());
24152419 if (struct_type.field_is_comptime_bits.get(ip, index)) {
2416 assertHasInits(ty, zcu);
24172420 return .fromInterned(struct_type.field_defaults.get(ip)[index]);
24182421 } else {
24192422 return Type.fromInterned(struct_type.field_types.get(ip)[index]).onePossibleValue(pt);
......@@ -2433,11 +2436,14 @@ pub fn structFieldValueComptime(ty: Type, pt: Zcu.PerThread, index: usize) !?Val
24332436
24342437pub fn structFieldIsComptime(ty: Type, index: usize, zcu: *const Zcu) bool {
24352438 const ip = &zcu.intern_pool;
2436 return switch (ip.indexToKey(ty.toIntern())) {
2437 .struct_type => ip.loadStructType(ty.toIntern()).field_is_comptime_bits.get(ip, index),
2438 .tuple_type => |tuple| tuple.values.get(ip)[index] != .none,
2439 switch (ip.indexToKey(ty.toIntern())) {
2440 .struct_type => {
2441 assertHasLayout(ty, zcu);
2442 return ip.loadStructType(ty.toIntern()).field_is_comptime_bits.get(ip, index);
2443 },
2444 .tuple_type => |tuple| return tuple.values.get(ip)[index] != .none,
24392445 else => unreachable,
2440 };
2446 }
24412447}
24422448
24432449pub const FieldOffset = struct {
......@@ -2850,34 +2856,166 @@ pub fn isNullFromType(ty: Type, zcu: *const Zcu) ?bool {
28502856 return null;
28512857}
28522858
2853/// Returns true if `ty` is allowed in packed types.
2854pub fn packable(ty: Type, zcu: *const Zcu) bool {
2859pub const UnpackableReason = union(enum) {
2860 comptime_only,
2861 pointer,
2862 enum_inferred_int_tag: Type,
2863 non_packed_struct: Type,
2864 non_packed_union: Type,
2865 other,
2866};
2867
2868/// Returns `null` iff `ty` is allowed in packed types.
2869pub fn unpackable(ty: Type, zcu: *const Zcu) ?UnpackableReason {
28552870 return switch (ty.zigTypeTag(zcu)) {
2871 .void,
2872 .bool,
2873 .float,
2874 .int,
2875 => null,
2876
28562877 .type,
28572878 .comptime_float,
28582879 .comptime_int,
28592880 .enum_literal,
28602881 .undefined,
28612882 .null,
2883 => .comptime_only,
2884
2885 .noreturn,
2886 .@"opaque",
28622887 .error_union,
28632888 .error_set,
28642889 .frame,
2865 .noreturn,
2866 .@"opaque",
28672890 .@"anyframe",
28682891 .@"fn",
28692892 .array,
2893 .vector,
2894 => .other,
2895
2896 .optional => if (ty.isPtrLikeOptional(zcu))
2897 .pointer
2898 else
2899 .other,
2900
2901 .pointer => .pointer,
2902
2903 .@"enum" => switch (zcu.intern_pool.loadEnumType(ty.toIntern()).int_tag_mode) {
2904 .explicit => null,
2905 .auto => .{ .enum_inferred_int_tag = ty },
2906 },
2907
2908 .@"struct" => switch (ty.containerLayout(zcu)) {
2909 .@"packed" => null,
2910 .auto, .@"extern" => .{ .non_packed_struct = ty },
2911 },
2912 .@"union" => switch (ty.containerLayout(zcu)) {
2913 .@"packed" => null,
2914 .auto, .@"extern" => .{ .non_packed_union = ty },
2915 },
2916 };
2917}
2918
2919pub const ExternPosition = enum {
2920 ret_ty,
2921 param_ty,
2922 union_field,
2923 struct_field,
2924 element,
2925 other,
2926};
2927
2928/// Returns true if `ty` is allowed in extern types.
2929/// Does not require `ty` to be resolved in any way.
2930/// Keep in sync with `Sema.explainWhyTypeIsNotExtern`.
2931pub fn validateExtern(ty: Type, position: ExternPosition, zcu: *const Zcu) bool {
2932 return switch (ty.zigTypeTag(zcu)) {
2933 .type,
2934 .comptime_float,
2935 .comptime_int,
2936 .enum_literal,
2937 .undefined,
2938 .null,
2939 .error_union,
2940 .error_set,
2941 .frame,
28702942 => false,
2871 .optional => return ty.isPtrLikeOptional(zcu),
2872 .void,
2943
2944 .void => switch (position) {
2945 .ret_ty,
2946 .union_field,
2947 .struct_field,
2948 .element,
2949 => true,
2950 .param_ty,
2951 .other,
2952 => false,
2953 },
2954
2955 .noreturn => position == .ret_ty,
2956
2957 .@"opaque",
28732958 .bool,
28742959 .float,
2875 .int,
2876 .vector,
2960 .@"anyframe",
28772961 => true,
2878 .@"enum" => zcu.intern_pool.loadEnumType(ty.toIntern()).int_tag_is_explicit,
2879 .pointer => !ty.isSlice(zcu),
2880 .@"struct", .@"union" => ty.containerLayout(zcu) == .@"packed",
2962
2963 .pointer => {
2964 if (ty.isSlice(zcu)) return false;
2965 const child_ty = ty.childType(zcu);
2966 if (child_ty.zigTypeTag(zcu) == .@"fn") {
2967 return ty.isConstPtr(zcu) and child_ty.validateExtern(.other, zcu);
2968 }
2969 return true;
2970 },
2971 .int => switch (ty.intInfo(zcu).bits) {
2972 0, 8, 16, 32, 64, 128 => true,
2973 else => false,
2974 },
2975 .@"fn" => {
2976 if (position != .other) return false;
2977 // For now we want to authorize PTX kernel to use zig objects, even if we end up exposing the ABI.
2978 // The goal is to experiment with more integrated CPU/GPU code.
2979 if (ty.fnCallingConvention(zcu) == .nvptx_kernel) {
2980 return true;
2981 }
2982 return !target_util.fnCallConvAllowsZigTypes(ty.fnCallingConvention(zcu));
2983 },
2984 .@"enum" => {
2985 const enum_obj = zcu.intern_pool.loadEnumType(ty.toIntern());
2986 return switch (enum_obj.int_tag_mode) {
2987 .auto => false,
2988 .explicit => Type.fromInterned(enum_obj.int_tag_type).validateExtern(position, zcu),
2989 };
2990 },
2991 .@"struct" => {
2992 const struct_obj = zcu.intern_pool.loadStructType(ty.toIntern());
2993 return switch (struct_obj.layout) {
2994 .auto => false,
2995 .@"extern" => true,
2996 .@"packed" => switch (struct_obj.packed_backing_mode) {
2997 .auto => false,
2998 .explicit => Type.fromInterned(struct_obj.packed_backing_int_type).validateExtern(position, zcu),
2999 },
3000 };
3001 },
3002 .@"union" => {
3003 const union_obj = zcu.intern_pool.loadUnionType(ty.toIntern());
3004 return switch (union_obj.layout) {
3005 .auto => false,
3006 .@"extern" => true,
3007 .@"packed" => switch (union_obj.packed_backing_mode) {
3008 .auto => false,
3009 .explicit => Type.fromInterned(union_obj.packed_backing_int_type).validateExtern(position, zcu),
3010 },
3011 };
3012 },
3013 .array => {
3014 if (position == .ret_ty or position == .param_ty) return false;
3015 return ty.childType(zcu).validateExtern(.element, zcu);
3016 },
3017 .vector => ty.childType(zcu).validateExtern(.element, zcu),
3018 .optional => ty.isPtrLikeOptional(zcu),
28813019 };
28823020}
28833021
......@@ -2889,7 +3027,6 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void {
28893027 .anyframe_type,
28903028 .simple_type,
28913029 .opaque_type,
2892 .enum_type,
28933030 .error_set_type,
28943031 .inferred_error_set_type,
28953032 => {},
......@@ -2906,12 +3043,11 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void {
29063043 .tuple_type => |tuple| for (tuple.types.get(&zcu.intern_pool)) |field_ty| {
29073044 assertHasLayout(.fromInterned(field_ty), zcu);
29083045 },
2909 .struct_type, .union_type => {
3046 .struct_type, .union_type, .enum_type => {
29103047 const unit: InternPool.AnalUnit = .wrap(.{ .type_layout = ty.toIntern() });
29113048 assert(!zcu.outdated.contains(unit));
29123049 assert(!zcu.potentially_outdated.contains(unit));
29133050 },
2914 else => unreachable, // assertion failure; not a struct or union
29153051
29163052 // values, not types
29173053 .simple_value,
......@@ -2930,23 +3066,13 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void {
29303066 .opt,
29313067 .aggregate,
29323068 .un,
3069 .undef,
29333070 // memoization, not types
29343071 .memoized_call,
29353072 => unreachable,
29363073 }
29373074}
29383075
2939/// Asserts that `ty` is an enum or struct type whose field values/defaults are resolved.
2940pub fn assertHasInits(ty: Type, zcu: *const Zcu) void {
2941 switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
2942 .struct_type, .enum_type => {},
2943 else => unreachable,
2944 }
2945 const unit: InternPool.AnalUnit = .wrap(.{ .type_inits = ty.toIntern() });
2946 assert(!zcu.outdated.contains(unit));
2947 assert(!zcu.potentially_outdated.contains(unit));
2948}
2949
29503076/// Recursively walks the type and marks for each subtype how many times it has been seen
29513077fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUnmanaged(Type, u16)) error{OutOfMemory}!void {
29523078 const zcu = pt.zcu;
......@@ -3116,6 +3242,7 @@ pub const Comparison = struct {
31163242 };
31173243};
31183244
3245pub const @"u0": Type = .{ .ip_index = .u0_type };
31193246pub const @"u1": Type = .{ .ip_index = .u1_type };
31203247pub const @"u8": Type = .{ .ip_index = .u8_type };
31213248pub const @"u16": Type = .{ .ip_index = .u16_type };
src/Value.zig+58-3
......@@ -2207,7 +2207,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
22072207
22082208 const ptr_ty_info = Type.fromInterned(ptr.ty).ptrInfo(zcu);
22092209 const need_child: Type = .fromInterned(ptr_ty_info.child);
2210 if (need_child.comptimeOnly(zcu)) {
2210 if (need_child.comptimeOnly(zcu) or need_child.zigTypeTag(zcu) == .@"opaque") {
22112211 // No refinement can happen - this pointer is presumably invalid.
22122212 // Just offset it.
22132213 const parent = try arena.create(PointerDeriveStep);
......@@ -2595,8 +2595,8 @@ pub fn uninterpret(val: anytype, ty: Type, pt: Zcu.PerThread) error{ OutOfMemory
25952595pub fn doPointersOverlap(ptr_val_a: Value, ptr_val_b: Value, elem_count: u64, zcu: *const Zcu) bool {
25962596 const ip = &zcu.intern_pool;
25972597
2598 const a_elem_ty = ptr_val_a.typeOf(zcu).indexablePtrElem(zcu);
2599 const b_elem_ty = ptr_val_b.typeOf(zcu).indexablePtrElem(zcu);
2598 const a_elem_ty = ptr_val_a.typeOf(zcu).indexableElem(zcu);
2599 const b_elem_ty = ptr_val_b.typeOf(zcu).indexableElem(zcu);
26002600
26012601 const a_ptr = ip.indexToKey(ptr_val_a.toIntern()).ptr;
26022602 const b_ptr = ip.indexToKey(ptr_val_b.toIntern()).ptr;
......@@ -2682,3 +2682,58 @@ pub fn eqlScalarNum(lhs: Value, rhs: Value, zcu: *Zcu) bool {
26822682 const rhs_bigint = rhs.toBigInt(&rhs_bigint_space, zcu);
26832683 return lhs_bigint.eql(rhs_bigint);
26842684}
2685
2686/// Asserts the value is an integer, and the destination type is ComptimeInt or Int.
2687/// Vectors are also accepted. Vector results are reduced with AND.
2688///
2689/// If provided, `vector_index` reports the first element that failed the range check.
2690pub fn intFitsInType(
2691 val: Value,
2692 ty: Type,
2693 vector_index: ?*usize,
2694 zcu: *const Zcu,
2695) bool {
2696 if (ty.toIntern() == .comptime_int_type) return true;
2697 const info = ty.intInfo(zcu);
2698 switch (val.toIntern()) {
2699 .zero_usize, .zero_u8 => return true,
2700 else => switch (zcu.intern_pool.indexToKey(val.toIntern())) {
2701 .undef => return true,
2702 .variable, .@"extern", .func, .ptr => {
2703 const target = zcu.getTarget();
2704 const ptr_bits = target.ptrBitWidth();
2705 return switch (info.signedness) {
2706 .signed => info.bits > ptr_bits,
2707 .unsigned => info.bits >= ptr_bits,
2708 };
2709 },
2710 .int => |int| {
2711 var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined;
2712 const big_int = int.storage.toBigInt(&buffer);
2713 return big_int.fitsInTwosComp(info.signedness, info.bits);
2714 },
2715 .aggregate => |aggregate| {
2716 assert(ty.zigTypeTag(zcu) == .vector);
2717 return switch (aggregate.storage) {
2718 .bytes => |bytes| for (bytes.toSlice(ty.vectorLen(zcu), &zcu.intern_pool), 0..) |byte, i| {
2719 if (byte == 0) continue;
2720 const actual_needed_bits = std.math.log2(byte) + 1 + @intFromBool(info.signedness == .signed);
2721 if (info.bits >= actual_needed_bits) continue;
2722 if (vector_index) |vi| vi.* = i;
2723 break false;
2724 } else true,
2725 .elems, .repeated_elem => for (switch (aggregate.storage) {
2726 .bytes => unreachable,
2727 .elems => |elems| elems,
2728 .repeated_elem => |elem| @as(*const [1]InternPool.Index, &elem),
2729 }, 0..) |elem, i| {
2730 if (Value.fromInterned(elem).intFitsInType(ty.scalarType(zcu), null, zcu)) continue;
2731 if (vector_index) |vi| vi.* = i;
2732 break false;
2733 } else true,
2734 };
2735 },
2736 else => unreachable,
2737 },
2738 }
2739}
src/Zcu.zig+113-121
......@@ -1912,40 +1912,6 @@ pub const SrcLoc = struct {
19121912 const full = tree.fullPtrType(parent_node).?;
19131913 return tree.nodeToSpan(full.ast.bit_range_end.unwrap().?);
19141914 },
1915 .node_offset_container_tag => |node_off| {
1916 const tree = try src_loc.file_scope.getTree(zcu);
1917 const parent_node = node_off.toAbsolute(src_loc.base_node);
1918
1919 switch (tree.nodeTag(parent_node)) {
1920 .container_decl_arg, .container_decl_arg_trailing => {
1921 const full = tree.containerDeclArg(parent_node);
1922 const arg_node = full.ast.arg.unwrap().?;
1923 return tree.nodeToSpan(arg_node);
1924 },
1925 .tagged_union_enum_tag, .tagged_union_enum_tag_trailing => {
1926 const full = tree.taggedUnionEnumTag(parent_node);
1927 const arg_node = full.ast.arg.unwrap().?;
1928
1929 return tree.tokensToSpan(
1930 tree.firstToken(arg_node) - 2,
1931 tree.lastToken(arg_node) + 1,
1932 tree.nodeMainToken(arg_node),
1933 );
1934 },
1935 else => unreachable,
1936 }
1937 },
1938 .node_offset_field_default => |node_off| {
1939 const tree = try src_loc.file_scope.getTree(zcu);
1940 const parent_node = node_off.toAbsolute(src_loc.base_node);
1941
1942 const full: Ast.full.ContainerField = switch (tree.nodeTag(parent_node)) {
1943 .container_field => tree.containerField(parent_node),
1944 .container_field_init => tree.containerFieldInit(parent_node),
1945 else => unreachable,
1946 };
1947 return tree.nodeToSpan(full.ast.value_expr.unwrap().?);
1948 },
19491915 .node_offset_init_ty => |node_off| {
19501916 const tree = try src_loc.file_scope.getTree(zcu);
19511917 const parent_node = node_off.toAbsolute(src_loc.base_node);
......@@ -2021,6 +1987,14 @@ pub const SrcLoc = struct {
20211987 }
20221988 return tree.nodeToSpan(node);
20231989 },
1990 .container_arg => {
1991 const tree = try src_loc.file_scope.getTree(zcu);
1992 const node = src_loc.base_node;
1993 var buf: [2]Ast.Node.Index = undefined;
1994 const container_decl = tree.fullContainerDecl(&buf, node) orelse return tree.nodeToSpan(node);
1995 const arg_node = container_decl.ast.arg.unwrap() orelse return tree.nodeToSpan(node);
1996 return tree.nodeToSpan(arg_node);
1997 },
20241998 .container_field_name,
20251999 .container_field_value,
20262000 .container_field_type,
......@@ -2262,7 +2236,11 @@ pub const SrcLoc = struct {
22622236 var param_it = full.iterate(tree);
22632237 for (0..param_idx) |_| assert(param_it.next() != null);
22642238 const param = param_it.next().?;
2265 return tree.nodeToSpan(param.type_expr.?);
2239 if (param.anytype_ellipsis3) |tok| {
2240 return tree.tokenToSpan(tok);
2241 } else {
2242 return tree.nodeToSpan(param.type_expr.?);
2243 }
22662244 },
22672245 }
22682246 }
......@@ -2484,10 +2462,6 @@ pub const LazySrcLoc = struct {
24842462 node_offset_ptr_bitoffset: Ast.Node.Offset,
24852463 /// The source location points to the host size of a pointer.
24862464 node_offset_ptr_hostsize: Ast.Node.Offset,
2487 /// The source location points to the tag type of an union or an enum.
2488 node_offset_container_tag: Ast.Node.Offset,
2489 /// The source location points to the default value of a field.
2490 node_offset_field_default: Ast.Node.Offset,
24912465 /// The source location points to the type of an array or struct initializer.
24922466 node_offset_init_ty: Ast.Node.Offset,
24932467 /// The source location points to the LHS of an assignment (or assign-op, e.g. `+=`).
......@@ -2532,6 +2506,11 @@ pub const LazySrcLoc = struct {
25322506 fn_proto_param_type: FnProtoParam,
25332507 array_cat_lhs: ArrayCat,
25342508 array_cat_rhs: ArrayCat,
2509 /// The source location points to the backing or tag type expression of
2510 /// the container type declaration at the base node.
2511 ///
2512 /// For 'union(enum(T))', this points to 'T', not 'enum(T)'.
2513 container_arg,
25352514 /// The source location points to the name of the field at the given index
25362515 /// of the container type declaration at the base node.
25372516 container_field_name: u32,
......@@ -3149,7 +3128,7 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
31493128 .nav_val => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_val = nav }),
31503129 .nav_ty => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_ty = nav }),
31513130 .type_layout => |ty| try zcu.markPoDependeeUpToDate(.{ .type_layout = ty }),
3152 .type_inits => |ty| try zcu.markPoDependeeUpToDate(.{ .type_inits = ty }),
3131 .struct_defaults => |ty| try zcu.markPoDependeeUpToDate(.{ .struct_defaults = ty }),
31533132 .func => |func| try zcu.markPoDependeeUpToDate(.{ .func_ies = func }),
31543133 .memoized_state => |stage| try zcu.markPoDependeeUpToDate(.{ .memoized_state = stage }),
31553134 }
......@@ -3165,7 +3144,7 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni
31653144 .nav_val => |nav| .{ .nav_val = nav },
31663145 .nav_ty => |nav| .{ .nav_ty = nav },
31673146 .type_layout => |ty| .{ .type_layout = ty },
3168 .type_inits => |ty| .{ .type_inits = ty },
3147 .struct_defaults => |ty| .{ .struct_defaults = ty },
31693148 .func => |func_index| .{ .func_ies = func_index },
31703149 .memoized_state => |stage| .{ .memoized_state = stage },
31713150 };
......@@ -3195,88 +3174,44 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni
31953174 }
31963175}
31973176
3177/// Selects an outdated `AnalUnit` to analyze next. Called from the main semantic analysis loop when
3178/// there is no work immediately queued. The unit is chosen such that it is unlikely to require any
3179/// recursive analysis (all of its previously-marked dependencies are already up-to-date), because
3180/// recursive analysis can cause over-analysis on incremental updates.
31983181pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
31993182 if (!zcu.comp.config.incremental) return null;
32003183
3201 if (zcu.outdated.count() == 0) {
3202 // Any units in `potentially_outdated` must just be stuck in loops with one another: none of those
3203 // units have had any outdated dependencies so far, and all of their remaining PO deps are triggered
3204 // by other units in `potentially_outdated`. So, we can safety assume those units up-to-date.
3205 zcu.potentially_outdated.clearRetainingCapacity();
3206 log.debug("findOutdatedToAnalyze: no outdated depender", .{});
3207 return null;
3208 }
3209
3210 // Our goal is to find an outdated AnalUnit which itself has no outdated or
3211 // PO dependencies. Most of the time, such an AnalUnit will exist - we track
3212 // them in the `outdated_ready` set for efficiency. However, this is not
3213 // necessarily the case, since the Decl dependency graph may contain loops
3214 // via mutually recursive definitions:
3215 // pub const A = struct { b: *B };
3216 // pub const B = struct { b: *A };
3217 // In this case, we must defer to more complex logic below.
3218
32193184 if (zcu.outdated_ready.count() > 0) {
32203185 const unit = zcu.outdated_ready.keys()[0];
3221 log.debug("findOutdatedToAnalyze: trivial {f}", .{zcu.fmtAnalUnit(unit)});
3186 log.debug("findOutdatedToAnalyze: {f}", .{zcu.fmtAnalUnit(unit)});
32223187 return unit;
32233188 }
32243189
3225 // There is no single AnalUnit which is ready for re-analysis. Instead, we must assume that some
3226 // AnalUnit with PO dependencies is outdated -- e.g. in the above example we arbitrarily pick one of
3227 // A or B. We should definitely not select a function, since a function can't be responsible for the
3228 // loop (IES dependencies can't have loops). We should also, of course, not select a `comptime`
3229 // declaration, since you can't depend on those!
3230
3231 // The choice of this unit could have a big impact on how much total analysis we perform, since
3232 // if analysis concludes any dependencies on its result are up-to-date, then other PO AnalUnit
3233 // may be resolved as up-to-date. To hopefully avoid doing too much work, let's find a unit
3234 // which the most things depend on - the idea is that this will resolve a lot of loops (but this
3235 // is only a heuristic).
3236
3237 log.debug("findOutdatedToAnalyze: no trivial ready, using heuristic; {d} outdated, {d} PO", .{
3238 zcu.outdated.count(),
3239 zcu.potentially_outdated.count(),
3240 });
3241
3242 const ip = &zcu.intern_pool;
3243
3244 var chosen_unit: ?AnalUnit = null;
3245 var chosen_unit_dependers: u32 = undefined;
3246
3247 // MLUGG TODO: i'm 99% sure this is now impossible. check!!!
3248 inline for (.{ zcu.outdated.keys(), zcu.potentially_outdated.keys() }) |outdated_units| {
3249 for (outdated_units) |unit| {
3250 var n: u32 = 0;
3251 var it = ip.dependencyIterator(switch (unit.unwrap()) {
3252 .func => continue, // a `func` definitely can't be causing the loop so it is a bad choice
3253 .@"comptime" => continue, // a `comptime` block can't even be depended on so it is a terrible choice
3254 .type_layout => |ty| .{ .type_layout = ty },
3255 .type_inits => |ty| .{ .type_inits = ty },
3256 .nav_val => |nav| .{ .nav_val = nav },
3257 .nav_ty => |nav| .{ .nav_ty = nav },
3258 .memoized_state => {
3259 // If we've hit a loop and some `.memoized_state` is outdated, we should make that choice eagerly.
3260 // In general, it's good to resolve this early on, since -- for instance -- almost every function
3261 // references the panic handler.
3262 return unit;
3263 },
3264 });
3265 while (it.next()) |_| n += 1;
3190 // Usually, getting here means that everything is up-to-date, so there is no more work to do. We
3191 // will see that `zcu.outdated` and `zcu.potentially_outdated` are both empty.
3192 //
3193 // However, if a previous update had a dependency loop compile error, there is a cycle in the
3194 // dependency graph (which is usually acyclic), which can cause a scenario where no unit appears
3195 // to be ready, because they're all waiting for the next in the loop to be up-to-date. In that
3196 // case, we usually have to just bite the bullet and analyze one of them. An exception is if
3197 // `zcu.outdated` is empty but `zcu.potentially_outdated` is non-empty: in that case, the only
3198 // possible situation is a cycle where everything is actually up-to-date, so we can clear out
3199 // `zcu.potentially_outdated` and we are done.
32663200
3267 if (chosen_unit == null or n > chosen_unit_dependers) {
3268 chosen_unit = unit;
3269 chosen_unit_dependers = n;
3270 }
3271 }
3201 if (zcu.outdated.count() == 0) {
3202 // Everything is up-to-date. There could be lingering entries in `zcu.potentially_outdated`
3203 // from a dependency loop on a previous update.
3204 zcu.potentially_outdated.clearRetainingCapacity();
3205 log.debug("findOutdatedToAnalyze: all up-to-date", .{});
3206 return null;
32723207 }
32733208
3274 log.debug("findOutdatedToAnalyze: heuristic returned '{f}' ({d} dependers)", .{
3275 zcu.fmtAnalUnit(chosen_unit.?),
3276 chosen_unit_dependers,
3209 const unit = zcu.outdated.keys()[0];
3210 log.debug("findOutdatedToAnalyze: dependency loop affecting {d} units, selected {f}", .{
3211 zcu.outdated.count(),
3212 zcu.fmtAnalUnit(unit),
32773213 });
3278
3279 return chosen_unit.?;
3214 return unit;
32803215}
32813216
32823217/// During an incremental update, before semantic analysis, call this to flush all values from
......@@ -3356,12 +3291,59 @@ pub fn mapOldZirToNew(
33563291 }
33573292
33583293 while (match_stack.pop()) |match_item| {
3359 // First, a check: if the number of captures of this type has changed, we can't map it, because
3360 // we wouldn't know how to correlate type information with the last update.
3361 // Synchronizes with logic in `Zcu.PerThread.recreateStructType` etc.
3362 if (old_zir.typeCapturesLen(match_item.old_inst) != new_zir.typeCapturesLen(match_item.new_inst)) {
3363 // Don't map this type or anything within it.
3364 continue;
3294 // There are some properties of type declarations which cannot change across incremental
3295 // updates. If they have, we need to ignore this mapping. These properties are essentially
3296 // everything passed into `InternPool.getDeclaredStructType` (likewise for unions, enums,
3297 // and opaques).
3298 const old_tag = old_zir.instructions.items(.data)[@intFromEnum(match_item.old_inst)].extended.opcode;
3299 const new_tag = new_zir.instructions.items(.data)[@intFromEnum(match_item.new_inst)].extended.opcode;
3300 if (old_tag != new_tag) continue;
3301 switch (old_tag) {
3302 .struct_decl => {
3303 const old = old_zir.getStructDecl(match_item.old_inst);
3304 const new = new_zir.getStructDecl(match_item.new_inst);
3305 if (old.captures.len != new.captures.len) continue;
3306 if (old.field_names.len != new.field_names.len) continue;
3307 if (old.layout != new.layout) continue;
3308 const old_any_field_aligns = old.field_align_body_lens != null;
3309 const old_any_field_defaults = old.field_default_body_lens != null;
3310 const old_any_comptime_fields = old.field_comptime_bits != null;
3311 const old_explicit_backing_int = old.backing_int_type_body != null;
3312 const new_any_field_aligns = new.field_align_body_lens != null;
3313 const new_any_field_defaults = new.field_default_body_lens != null;
3314 const new_any_comptime_fields = new.field_comptime_bits != null;
3315 const new_explicit_backing_int = new.backing_int_type_body != null;
3316 if (old_any_field_aligns != new_any_field_aligns) continue;
3317 if (old_any_field_defaults != new_any_field_defaults) continue;
3318 if (old_any_comptime_fields != new_any_comptime_fields) continue;
3319 if (old_explicit_backing_int != new_explicit_backing_int) continue;
3320 },
3321 .union_decl => {
3322 const old = old_zir.getUnionDecl(match_item.old_inst);
3323 const new = new_zir.getUnionDecl(match_item.new_inst);
3324 if (old.captures.len != new.captures.len) continue;
3325 if (old.field_names.len != new.field_names.len) continue;
3326 if (old.kind != new.kind) continue;
3327 const old_any_field_aligns = old.field_align_body_lens != null;
3328 const new_any_field_aligns = new.field_align_body_lens != null;
3329 if (old_any_field_aligns != new_any_field_aligns) continue;
3330 },
3331 .enum_decl => {
3332 const old = old_zir.getEnumDecl(match_item.old_inst);
3333 const new = new_zir.getEnumDecl(match_item.new_inst);
3334 if (old.captures.len != new.captures.len) continue;
3335 if (old.field_names.len != new.field_names.len) continue;
3336 if (old.nonexhaustive != new.nonexhaustive) continue;
3337 const old_explicit_tag_type = old.tag_type_body != null;
3338 const new_explicit_tag_type = new.tag_type_body != null;
3339 if (old_explicit_tag_type != new_explicit_tag_type) continue;
3340 },
3341 .opaque_decl => {
3342 const old = old_zir.getOpaqueDecl(match_item.old_inst);
3343 const new = new_zir.getOpaqueDecl(match_item.new_inst);
3344 if (old.captures.len != new.captures.len) continue;
3345 },
3346 else => unreachable,
33653347 }
33663348
33673349 // Match the namespace declaration itself
......@@ -4068,7 +4050,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R
40684050 }
40694051 if (has_inits) {
40704052 // this should only be referenced by the type
4071 const unit: AnalUnit = .wrap(.{ .type_inits = ty });
4053 const unit: AnalUnit = .wrap(.{ .struct_defaults = ty });
40724054 try units.putNoClobber(gpa, unit, referencer);
40734055 }
40744056
......@@ -4184,7 +4166,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R
41844166 const other: AnalUnit = .wrap(switch (unit.unwrap()) {
41854167 .nav_val => |n| .{ .nav_ty = n },
41864168 .nav_ty => |n| .{ .nav_val = n },
4187 .@"comptime", .type_layout, .type_inits, .func, .memoized_state => break :queue_paired,
4169 .@"comptime", .type_layout, .struct_defaults, .func, .memoized_state => break :queue_paired,
41884170 });
41894171 const gop = try units.getOrPut(gpa, other);
41904172 if (gop.found_existing) break :queue_paired;
......@@ -4305,6 +4287,16 @@ pub fn navFileScope(zcu: *Zcu, nav: InternPool.Nav.Index) *File {
43054287 return zcu.fileByIndex(zcu.navFileScopeIndex(nav));
43064288}
43074289
4290pub fn navAlignment(zcu: *Zcu, nav_index: InternPool.Nav.Index) InternPool.Alignment {
4291 const ty: Type, const alignment = switch (zcu.intern_pool.getNav(nav_index).status) {
4292 .unresolved => unreachable,
4293 .type_resolved => |r| .{ .fromInterned(r.type), r.alignment },
4294 .fully_resolved => |r| .{ Value.fromInterned(r.val).typeOf(zcu), r.alignment },
4295 };
4296 if (alignment != .none) return alignment;
4297 return ty.abiAlignment(zcu);
4298}
4299
43084300pub fn fmtAnalUnit(zcu: *Zcu, unit: AnalUnit) std.fmt.Alt(FormatAnalUnit, formatAnalUnit) {
43094301 return .{ .data = .{ .unit = unit, .zcu = zcu } };
43104302}
......@@ -4331,7 +4323,7 @@ fn formatAnalUnit(data: FormatAnalUnit, writer: *Io.Writer) Io.Writer.Error!void
43314323 }
43324324 },
43334325 .nav_val, .nav_ty => |nav, tag| return writer.print("{t}('{f}' [{}])", .{ tag, ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }),
4334 .type_layout, .type_inits => |ty, tag| return writer.print("{t}('{f}' [{}])", .{ tag, Type.fromInterned(ty).containerTypeName(ip).fmt(ip), @intFromEnum(ty) }),
4326 .type_layout, .struct_defaults => |ty, tag| return writer.print("{t}('{f}' [{}])", .{ tag, Type.fromInterned(ty).containerTypeName(ip).fmt(ip), @intFromEnum(ty) }),
43354327 .func => |func| {
43364328 const nav = zcu.funcInfo(func).owner_nav;
43374329 return writer.print("func('{f}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(func) });
......@@ -4357,7 +4349,7 @@ fn formatDependee(data: FormatDependee, writer: *Io.Writer) Io.Writer.Error!void
43574349 const fqn = ip.getNav(nav).fqn;
43584350 return writer.print("{t}('{f}')", .{ tag, fqn.fmt(ip) });
43594351 },
4360 .type_layout, .type_inits => |ip_index, tag| {
4352 .type_layout, .struct_defaults => |ip_index, tag| {
43614353 const name = Type.fromInterned(ip_index).containerTypeName(ip);
43624354 return writer.print("{t}('{f}')", .{ tag, name.fmt(ip) });
43634355 },
src/Zcu/PerThread.zig+67-88
......@@ -695,20 +695,46 @@ pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) (Alloca
695695 .file = file_index,
696696 .inst = .main_struct_inst,
697697 });
698 const file_root_type = try Sema.analyzeStructDecl(
699 pt,
700 file_index,
701 &file.zir.?,
702 .none,
703 tracked_inst,
704 &struct_decl,
705 null,
706 &.{},
707 .{ .exact = .{
708 .name = try file.internFullyQualifiedName(pt),
709 .nav = .none,
710 } },
711 );
698 const wip: InternPool.WipContainerType = switch (try ip.getDeclaredStructType(gpa, io, pt.tid, .{
699 .zir_index = tracked_inst,
700 .captures = &.{},
701 .fields_len = @intCast(struct_decl.field_names.len),
702 .layout = struct_decl.layout,
703 .any_comptime_fields = struct_decl.field_comptime_bits != null,
704 .any_field_defaults = struct_decl.field_default_body_lens != null,
705 .any_field_aligns = struct_decl.field_align_body_lens != null,
706 .packed_backing_mode = if (struct_decl.backing_int_type_body != null) .explicit else .auto,
707 })) {
708 .existing => unreachable, // it would have been set as `zcu.fileRootType` already
709 .wip => |wip| wip,
710 };
711 errdefer wip.cancel(ip, pt.tid);
712
713 wip.setName(ip, try file.internFullyQualifiedName(pt), .none);
714 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
715 .parent = .none,
716 .owner_type = wip.index,
717 .file_scope = file_index,
718 .generation = zcu.generation,
719 });
720 errdefer pt.destroyNamespace(new_namespace_index);
721 try pt.scanNamespace(new_namespace_index, struct_decl.decls);
722 // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind
723 try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) });
724 try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .struct_defaults = wip.index }) });
725
726 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
727
728 try zcu.outdated.ensureUnusedCapacity(gpa, 2);
729 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 2);
730 errdefer comptime unreachable; // because we don't remove the `outdated` entries
731 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0);
732 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .struct_defaults = wip.index }), 0);
733 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {});
734 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .struct_defaults = wip.index }), {});
735
736 const file_root_type: Type = .fromInterned(wip.finish(ip, new_namespace_index));
737
712738 zcu.setFileRootType(file_index, file_root_type.toIntern());
713739 if (zcu.comp.time_report) |*tr| tr.stats.n_imported_files += 1;
714740}
......@@ -1048,11 +1074,6 @@ pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void
10481074
10491075 assert(!zcu.analysis_in_progress.contains(anal_unit));
10501076
1051 // Determine whether or not this type is outdated. For this kind of `AnalUnit`, that's
1052 // the only indicator as to whether or not analysis is required; when a struct/union is
1053 // first created, it's marked as outdated.
1054 // MLUGG TODO: make that actually true, it's a good strategy here!
1055
10561077 const was_outdated = zcu.outdated.swapRemove(anal_unit) or
10571078 zcu.potentially_outdated.swapRemove(anal_unit);
10581079
......@@ -1113,17 +1134,11 @@ pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void
11131134 };
11141135 defer sema.deinit();
11151136
1116 const result = switch (ty.containerLayout(zcu)) {
1117 .auto, .@"extern" => switch (ty.zigTypeTag(zcu)) {
1118 .@"struct" => Sema.type_resolution.resolveStructLayout(&sema, ty),
1119 .@"union" => Sema.type_resolution.resolveUnionLayout(&sema, ty),
1120 else => unreachable,
1121 },
1122 .@"packed" => switch (ty.zigTypeTag(zcu)) {
1123 .@"struct" => Sema.type_resolution.resolvePackedStructLayout(&sema, ty),
1124 .@"union" => Sema.type_resolution.resolvePackedUnionLayout(&sema, ty),
1125 else => unreachable,
1126 },
1137 const result = switch (ty.zigTypeTag(zcu)) {
1138 .@"enum" => Sema.type_resolution.resolveEnumLayout(&sema, ty),
1139 .@"struct" => Sema.type_resolution.resolveStructLayout(&sema, ty),
1140 .@"union" => Sema.type_resolution.resolveUnionLayout(&sema, ty),
1141 else => unreachable,
11271142 };
11281143 result catch |err| switch (err) {
11291144 error.AnalysisFail => {
......@@ -1145,36 +1160,31 @@ pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void
11451160 sema.flushExports() catch |err| switch (err) {
11461161 error.OutOfMemory => |e| return e,
11471162 };
1148
1149 codegen_type: {
1150 if (zcu.comp.config.use_llvm) break :codegen_type;
1151 if (file.mod.?.strip) break :codegen_type;
1152 zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
1153 try zcu.comp.queueJob(.{ .link_type = ty.toIntern() });
1154 }
11551163}
11561164
1157/// Ensures that the default/tag values of the given `struct` or `enum` type are fully up-to-date,
1158/// performing re-analysis if necessary. Asserts that `ty` is a struct (not a tuple!) or an enum.
1159/// Returns `error.AnalysisFail` if an analysis error is encountered during resolution; the caller
1160/// is free to ignore this, since the error is already registered.
1161pub fn ensureTypeInitsUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void {
1165/// Ensures that the default values of the given "declared" (not reified) `struct` type are fully
1166/// up-to-date, performing re-analysis if necessary. Asserts that `ty` is a struct (not tuple) type.
1167/// Returns `error.AnalysisFail` if an analysis error is encountered while resolving the default
1168/// field values; the caller is free to ignore this, since the error is already registered.
1169pub fn ensureStructDefaultsUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void {
11621170 const tracy = trace(@src());
11631171 defer tracy.end();
11641172
11651173 const zcu = pt.zcu;
11661174 const gpa = zcu.gpa;
11671175
1168 const anal_unit: AnalUnit = .wrap(.{ .type_inits = ty.toIntern() });
1176 assert(ty.zigTypeTag(zcu) == .@"struct");
1177 assert(!ty.isTuple(zcu));
1178
1179 const anal_unit: AnalUnit = .wrap(.{ .struct_defaults = ty.toIntern() });
11691180
1170 log.debug("ensureTypeInitsUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)});
1181 log.debug("ensureStructDefaultsUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)});
11711182
11721183 assert(!zcu.analysis_in_progress.contains(anal_unit));
11731184
11741185 // Determine whether or not this type is outdated. For this kind of `AnalUnit`, that's
11751186 // the only indicator as to whether or not analysis is required; when a struct/enum is
11761187 // first created, it's marked as outdated.
1177 // MLUGG TODO: make that actually true, it's a good strategy here!
11781188
11791189 const was_outdated = zcu.outdated.swapRemove(anal_unit) or
11801190 zcu.potentially_outdated.swapRemove(anal_unit);
......@@ -1194,7 +1204,7 @@ pub fn ensureTypeInitsUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void {
11941204 }
11951205 // For types, we already know that we have to invalidate all dependees.
11961206 // TODO: we actually *could* detect whether everything was the same. should we bother?
1197 try zcu.markDependeeOutdated(.marked_po, .{ .type_inits = ty.toIntern() });
1207 try zcu.markDependeeOutdated(.marked_po, .{ .struct_defaults = ty.toIntern() });
11981208 } else {
11991209 // We can trust the current information about this unit.
12001210 if (zcu.failed_analysis.contains(anal_unit)) return error.AnalysisFail;
......@@ -1236,12 +1246,7 @@ pub fn ensureTypeInitsUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void {
12361246 };
12371247 defer sema.deinit();
12381248
1239 const result = switch (ty.zigTypeTag(zcu)) {
1240 .@"struct" => Sema.type_resolution.resolveStructDefaults(&sema, ty),
1241 .@"enum" => Sema.type_resolution.resolveEnumValues(&sema, ty),
1242 else => unreachable,
1243 };
1244 result catch |err| switch (err) {
1249 Sema.type_resolution.resolveStructDefaults(&sema, ty) catch |err| switch (err) {
12451250 error.AnalysisFail => {
12461251 if (!zcu.failed_analysis.contains(anal_unit)) {
12471252 // If this unit caused the error, it would have an entry in `failed_analysis`.
......@@ -1270,20 +1275,6 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu
12701275 const tracy = trace(@src());
12711276 defer tracy.end();
12721277
1273 // TODO: document this elsewhere mlugg!
1274 // For my own benefit, here's how a namespace update for a normal (non-file-root) type works:
1275 // `const S = struct { ... };`
1276 // We are adding or removing a declaration within this `struct`.
1277 // * `S` registers a dependency on `.{ .src_hash = (declaration of S) }`
1278 // * Any change to the `struct` body -- including changing a declaration -- invalidates this
1279 // * `S` is re-analyzed, but notes:
1280 // * there is an existing struct instance (at this `TrackedInst` with these captures)
1281 // * the struct's resolution is up-to-date (because nothing about the fields changed)
1282 // * so, it uses the same `struct`
1283 // * but this doesn't stop it from updating the namespace!
1284 // * we basically do `scanDecls`, updating the namespace as needed
1285 // * so everyone lived happily ever after
1286
12871278 const zcu = pt.zcu;
12881279 const gpa = zcu.gpa;
12891280 const ip = &zcu.intern_pool;
......@@ -3033,7 +3024,7 @@ fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.Sem
30333024 const zir = file.zir.?;
30343025
30353026 try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, {});
3036 errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
3027 defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));
30373028
30383029 func.setAnalyzed(ip, io);
30393030 if (func.analysisUnordered(ip).inferred_error_set) {
......@@ -3231,9 +3222,6 @@ fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.Sem
32313222 func.setResolvedErrorSet(ip, io, ies.resolved);
32323223 }
32333224
3234 // MLUGG TODO: i think this can go away and the assert move to the defer?
3235 assert(zcu.analysis_in_progress.swapRemove(anal_unit));
3236
32373225 try sema.flushExports();
32383226
32393227 defer {
......@@ -3835,7 +3823,6 @@ pub fn enumValue(pt: Zcu.PerThread, ty: Type, tag_int: InternPool.Index) Allocat
38353823/// declaration order.
38363824pub fn enumValueFieldIndex(pt: Zcu.PerThread, ty: Type, field_index: u32) Allocator.Error!Value {
38373825 const ip = &pt.zcu.intern_pool;
3838 ty.assertHasInits(pt.zcu);
38393826 const enum_type = ip.loadEnumType(ty.toIntern());
38403827
38413828 assert(field_index < enum_type.field_names.len);
......@@ -3859,7 +3846,9 @@ pub fn enumValueFieldIndex(pt: Zcu.PerThread, ty: Type, field_index: u32) Alloca
38593846
38603847pub fn undefValue(pt: Zcu.PerThread, ty: Type) Allocator.Error!Value {
38613848 if (std.debug.runtime_safety) {
3862 assert(try ty.onePossibleValue(pt) == null);
3849 if (try ty.onePossibleValue(pt)) |opv| {
3850 assert(opv.isUndef(pt.zcu));
3851 }
38633852 }
38643853 return .fromInterned(try pt.intern(.{ .undef = ty.toIntern() }));
38653854}
......@@ -3941,7 +3930,10 @@ pub fn aggregateValue(pt: Zcu.PerThread, ty: Type, elems: []const InternPool.Ind
39413930 for (elems) |elem| {
39423931 if (!Value.fromInterned(elem).isUndef(pt.zcu)) break;
39433932 } else if (elems.len > 0) {
3944 return pt.undefValue(ty); // all-undef
3933 // All undef, so return an undef struct. However, don't use `undefValue`, because its
3934 // non-OPV assertion can loop on `[1]@TypeOf(undefined)`: that type has an OPV of
3935 // `.{undefined}`, which here we normalize to `undefined`.
3936 return .fromInterned(try pt.intern(.{ .undef = ty.toIntern() }));
39453937 }
39463938 return .fromInterned(try pt.intern(.{ .aggregate = .{
39473939 .ty = ty.toIntern(),
......@@ -4096,19 +4088,6 @@ pub fn getExtern(pt: Zcu.PerThread, key: InternPool.Key.Extern) Allocator.Error!
40964088 return result.index;
40974089}
40984090
4099// TODO: this shouldn't need a `PerThread`! Fix the signature of `Type.abiAlignment`.
4100// MLUGG TODO: that's done, move it!
4101pub fn navAlignment(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) InternPool.Alignment {
4102 const zcu = pt.zcu;
4103 const ty: Type, const alignment = switch (zcu.intern_pool.getNav(nav_index).status) {
4104 .unresolved => unreachable,
4105 .type_resolved => |r| .{ .fromInterned(r.type), r.alignment },
4106 .fully_resolved => |r| .{ Value.fromInterned(r.val).typeOf(zcu), r.alignment },
4107 };
4108 if (alignment != .none) return alignment;
4109 return ty.abiAlignment(zcu);
4110}
4111
41124091/// Given a namespace, re-scan its declarations from the type definition if they have not
41134092/// yet been re-scanned on this update.
41144093/// If the type declaration instruction has been lost, returns `error.AnalysisFail`.
......@@ -4393,7 +4372,7 @@ pub fn resolveTypeForCodegen(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void {
43934372 .@"struct" => switch (ip.indexToKey(ty.toIntern())) {
43944373 .struct_type => {
43954374 try pt.ensureTypeLayoutUpToDate(ty);
4396 try pt.ensureTypeInitsUpToDate(ty);
4375 try pt.ensureStructDefaultsUpToDate(ty);
43974376 },
43984377 .tuple_type => |tuple| for (0..tuple.types.len) |i| {
43994378 const field_is_comptime = tuple.values.get(ip)[i] != .none;
......@@ -4405,7 +4384,7 @@ pub fn resolveTypeForCodegen(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void {
44054384 },
44064385
44074386 .@"union" => try pt.ensureTypeLayoutUpToDate(ty),
4408 .@"enum" => try pt.ensureTypeInitsUpToDate(ty),
4387 .@"enum" => try pt.ensureTypeLayoutUpToDate(ty),
44094388 }
44104389}
44114390pub fn resolveValueTypesForCodegen(pt: Zcu.PerThread, val: Value) Zcu.SemaError!void {
src/codegen.zig+5-6
......@@ -347,7 +347,6 @@ pub fn generateSymbol(
347347 .void => unreachable, // non-runtime value
348348 .null => unreachable, // non-runtime value
349349 .@"unreachable" => unreachable, // non-runtime value
350 .empty_tuple => return,
351350 .false, .true => try w.writeByte(switch (simple_value) {
352351 .false => 0,
353352 .true => 1,
......@@ -1065,20 +1064,20 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo
10651064 const elem_ty = ty.childType(zcu);
10661065 const ptr = ip.indexToKey(val.toIntern()).ptr;
10671066 if (ptr.base_addr == .int) return .{ .immediate = ptr.byte_offset };
1068 switch (ptr.base_addr) {
1067 if (ptr.byte_offset == 0) switch (ptr.base_addr) {
10691068 .int => unreachable, // handled above
10701069
1071 .nav => |nav| if (elem_ty.isFnOrHasRuntimeBits(zcu)) {
1070 .nav => |nav| if (elem_ty.isRuntimeFnOrHasRuntimeBits(zcu)) {
10721071 return .{ .lea_nav = nav };
10731072 } else {
10741073 // Create the 0xaa bit pattern...
10751074 const undef_ptr_bits: u64 = @intCast((@as(u66, 1) << @intCast(target.ptrBitWidth() + 1)) / 3);
10761075 // ...but align the pointer
1077 const alignment = pt.navAlignment(nav);
1076 const alignment = zcu.navAlignment(nav);
10781077 return .{ .immediate = alignment.forward(undef_ptr_bits) };
10791078 },
10801079
1081 .uav => |uav| if (elem_ty.isFnOrHasRuntimeBits(zcu)) {
1080 .uav => |uav| if (elem_ty.isRuntimeFnOrHasRuntimeBits(zcu)) {
10821081 return .{ .lea_uav = uav };
10831082 } else {
10841083 // Create the 0xaa bit pattern...
......@@ -1089,7 +1088,7 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo
10891088 },
10901089
10911090 else => {},
1092 }
1091 };
10931092 },
10941093 },
10951094 .int => {
src/codegen/aarch64/Select.zig+7-7
......@@ -6594,7 +6594,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
65946594 if (try isel.hasRepeatedByteRepr(.fromInterned(fill_val))) |fill_byte|
65956595 break :fill_byte .{ .constant = fill_byte };
65966596 }
6597 switch (dst_ty.indexablePtrElem(zcu).abiSize(zcu)) {
6597 switch (dst_ty.indexableElem(zcu).abiSize(zcu)) {
65986598 0 => unreachable,
65996599 1 => break :fill_byte .{ .value = bin_op.rhs },
66006600 2, 4, 8 => |size| {
......@@ -7217,7 +7217,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
72177217 const ptr_ra = try ptr_vi.value.defReg(isel) orelse break :unused;
72187218
72197219 const ty_nav = air.data(air.inst_index).ty_nav;
7220 if (ZigType.fromInterned(ip.getNav(ty_nav.nav).typeOf(ip)).isFnOrHasRuntimeBits(zcu)) switch (true) {
7220 if (ZigType.fromInterned(ip.getNav(ty_nav.nav).typeOf(ip)).isRuntimeFnOrHasRuntimeBits(zcu)) switch (true) {
72217221 false => {
72227222 try isel.nav_relocs.append(gpa, .{
72237223 .nav = ty_nav.nav,
......@@ -7240,7 +7240,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
72407240 });
72417241 try isel.emit(.adrp(ptr_ra.x(), 0));
72427242 },
7243 } else try isel.movImmediate(ptr_ra.x(), isel.pt.navAlignment(ty_nav.nav).forward(0xaaaaaaaaaaaaaaaa));
7243 } else try isel.movImmediate(ptr_ra.x(), zcu.navAlignment(ty_nav.nav).forward(0xaaaaaaaaaaaaaaaa));
72447244 }
72457245 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
72467246 },
......@@ -10738,7 +10738,7 @@ pub const Value = struct {
1073810738 } }),
1073910739 }),
1074010740 .simple_value => |simple_value| switch (simple_value) {
10741 .undefined, .void, .null, .empty_tuple, .@"unreachable" => unreachable,
10741 .undefined, .void, .null, .@"unreachable" => unreachable,
1074210742 .true => continue :constant_key .{ .int = .{
1074310743 .ty = .bool_type,
1074410744 .storage = .{ .u64 = 1 },
......@@ -10931,7 +10931,7 @@ pub const Value = struct {
1093110931 .ptr => |ptr| {
1093210932 assert(offset == 0 and size == 8);
1093310933 break :free switch (ptr.base_addr) {
10934 .nav => |nav| if (ZigType.fromInterned(ip.getNav(nav).typeOf(ip)).isFnOrHasRuntimeBits(zcu)) switch (true) {
10934 .nav => |nav| if (ZigType.fromInterned(ip.getNav(nav).typeOf(ip)).isRuntimeFnOrHasRuntimeBits(zcu)) switch (true) {
1093510935 false => {
1093610936 try isel.nav_relocs.append(zcu.gpa, .{
1093710937 .nav = nav,
......@@ -10965,9 +10965,9 @@ pub const Value = struct {
1096510965 },
1096610966 } else continue :constant_key .{ .int = .{
1096710967 .ty = .usize_type,
10968 .storage = .{ .u64 = isel.pt.navAlignment(nav).forward(0xaaaaaaaaaaaaaaaa) },
10968 .storage = .{ .u64 = zcu.navAlignment(nav).forward(0xaaaaaaaaaaaaaaaa) },
1096910969 } },
10970 .uav => |uav| if (ZigType.fromInterned(ip.typeOf(uav.val)).isFnOrHasRuntimeBits(zcu)) switch (true) {
10970 .uav => |uav| if (ZigType.fromInterned(ip.typeOf(uav.val)).isRuntimeFnOrHasRuntimeBits(zcu)) switch (true) {
1097110971 false => {
1097210972 try isel.uav_relocs.append(zcu.gpa, .{
1097310973 .uav = uav,
src/codegen/c.zig+8-9
......@@ -789,7 +789,7 @@ pub const DeclGen = struct {
789789
790790 // Render an undefined pointer if we have a pointer to a zero-bit or comptime type.
791791 const ptr_ty: Type = .fromInterned(uav.orig_ty);
792 if (ptr_ty.isPtrAtRuntime(zcu) and !uav_ty.isFnOrHasRuntimeBits(zcu)) {
792 if (ptr_ty.isPtrAtRuntime(zcu) and !uav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) {
793793 return dg.writeCValue(w, .{ .undef = ptr_ty });
794794 }
795795
......@@ -862,7 +862,7 @@ pub const DeclGen = struct {
862862 // Render an undefined pointer if we have a pointer to a zero-bit or comptime type.
863863 const nav_ty: Type = .fromInterned(ip.getNav(owner_nav).typeOf(ip));
864864 const ptr_ty = try pt.navPtrType(owner_nav);
865 if (!nav_ty.isFnOrHasRuntimeBits(zcu)) {
865 if (!nav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) {
866866 return dg.writeCValue(w, .{ .undef = ptr_ty });
867867 }
868868
......@@ -1043,7 +1043,6 @@ pub const DeclGen = struct {
10431043 .undefined => unreachable,
10441044 .void => unreachable,
10451045 .null => unreachable,
1046 .empty_tuple => unreachable,
10471046 .@"unreachable" => unreachable,
10481047
10491048 .false => try w.writeAll("false"),
......@@ -3077,7 +3076,7 @@ pub fn genDecl(o: *Object) Error!void {
30773076 const nav = ip.getNav(o.dg.pass.nav);
30783077 const nav_ty: Type = .fromInterned(nav.typeOf(ip));
30793078
3080 if (!nav_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return;
3079 if (!nav_ty.hasRuntimeBits(zcu)) return;
30813080 switch (ip.indexToKey(nav.status.fully_resolved.val)) {
30823081 .@"extern" => |@"extern"| {
30833082 if (!ip.isFunctionType(nav_ty.toIntern())) return o.dg.renderFwdDecl(o.dg.pass.nav, .{
......@@ -3676,7 +3675,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
36763675
36773676 const inst_ty = f.typeOfIndex(inst);
36783677 const ptr_ty = f.typeOf(bin_op.lhs);
3679 const elem_has_bits = ptr_ty.indexablePtrElem(zcu).hasRuntimeBitsIgnoreComptime(zcu);
3678 const elem_has_bits = ptr_ty.indexableElem(zcu).hasRuntimeBitsIgnoreComptime(zcu);
36803679
36813680 const ptr = try f.resolveInst(bin_op.lhs);
36823681 const index = try f.resolveInst(bin_op.rhs);
......@@ -3792,7 +3791,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
37923791 const zcu = pt.zcu;
37933792 const inst_ty = f.typeOfIndex(inst);
37943793 const elem_ty = inst_ty.childType(zcu);
3795 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return .{ .undef = inst_ty };
3794 if (!elem_ty.hasRuntimeBits(zcu)) return .{ .undef = inst_ty };
37963795
37973796 const local = try f.allocLocalValue(.{
37983797 .ctype = try f.ctypeFromType(elem_ty, .complete),
......@@ -3829,7 +3828,7 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
38293828 const zcu = pt.zcu;
38303829 const inst_ty = f.typeOfIndex(inst);
38313830 const elem_ty = inst_ty.childType(zcu);
3832 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return .{ .undef = inst_ty };
3831 if (!elem_ty.hasRuntimeBits(zcu)) return .{ .undef = inst_ty };
38333832
38343833 const local = try f.allocLocalValue(.{
38353834 .ctype = try f.ctypeFromType(elem_ty, .complete),
......@@ -4502,7 +4501,7 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
45024501
45034502 const inst_ty = f.typeOfIndex(inst);
45044503 const inst_scalar_ty = inst_ty.scalarType(zcu);
4505 const elem_ty = inst_scalar_ty.indexablePtrElem(zcu);
4504 const elem_ty = inst_scalar_ty.indexableElem(zcu);
45064505 if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) return f.moveCValue(inst, inst_ty, lhs);
45074506 const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete);
45084507
......@@ -7037,7 +7036,7 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index, function_paren: []const u8) !CV
70377036 try w.writeAll(", ");
70387037 try writeArrayLen(f, dest_ptr, dest_ty);
70397038 try w.writeAll(" * sizeof(");
7040 try f.renderType(w, dest_ty.indexablePtrElem(zcu));
7039 try f.renderType(w, dest_ty.indexableElem(zcu));
70417040 try w.writeAll("));");
70427041 try f.object.newline();
70437042
src/codegen/llvm.zig+7-8
......@@ -3725,7 +3725,6 @@ pub const Object = struct {
37253725 .undefined => unreachable, // non-runtime value
37263726 .void => unreachable, // non-runtime value
37273727 .null => unreachable, // non-runtime value
3728 .empty_tuple => unreachable, // non-runtime value
37293728 .@"unreachable" => unreachable, // non-runtime value
37303729
37313730 .false => .false,
......@@ -4604,7 +4603,7 @@ pub const NavGen = struct {
46044603 _ = try o.resolveLlvmFunction(pt, owner_nav);
46054604 } else {
46064605 const variable_index = try o.resolveGlobalNav(pt, nav_index);
4607 variable_index.setAlignment(pt.navAlignment(nav_index).toLlvm(), &o.builder);
4606 variable_index.setAlignment(zcu.navAlignment(nav_index).toLlvm(), &o.builder);
46084607 if (resolved.@"linksection".toSlice(ip)) |section|
46094608 variable_index.setSection(try o.builder.string(section), &o.builder);
46104609 if (is_const) variable_index.setMutability(.constant, &o.builder);
......@@ -5953,7 +5952,7 @@ pub const FuncGen = struct {
59535952 return .none;
59545953 }
59555954
5956 const have_block_result = inst_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu);
5955 const have_block_result = inst_ty.hasRuntimeBits(zcu);
59575956
59585957 var breaks: BreakList = if (have_block_result) .{ .list = .{} } else .{ .len = 0 };
59595958 defer if (have_block_result) breaks.list.deinit(self.gpa);
......@@ -6000,7 +5999,7 @@ pub const FuncGen = struct {
60005999
60016000 // Add the values to the lists only if the break provides a value.
60026001 const operand_ty = self.typeOf(branch.operand);
6003 if (operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {
6002 if (operand_ty.hasRuntimeBits(zcu)) {
60046003 const val = try self.resolveInst(branch.operand);
60056004
60066005 // For the phi node, we need the basic blocks and the values of the
......@@ -9581,7 +9580,7 @@ pub const FuncGen = struct {
95819580 const zcu = pt.zcu;
95829581 const ptr_ty = self.typeOfIndex(inst);
95839582 const pointee_type = ptr_ty.childType(zcu);
9584 if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime(zcu))
9583 if (!pointee_type.hasRuntimeBits(zcu))
95859584 return (try o.lowerPtrToVoid(pt, ptr_ty)).toValue();
95869585
95879586 const pointee_llvm_ty = try o.lowerType(pt, pointee_type);
......@@ -9595,7 +9594,7 @@ pub const FuncGen = struct {
95959594 const zcu = pt.zcu;
95969595 const ptr_ty = self.typeOfIndex(inst);
95979596 const ret_ty = ptr_ty.childType(zcu);
9598 if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu))
9597 if (!ret_ty.hasRuntimeBits(zcu))
95999598 return (try o.lowerPtrToVoid(pt, ptr_ty)).toValue();
96009599 if (self.ret_ptr != .none) return self.ret_ptr;
96019600 const ret_llvm_ty = try o.lowerType(pt, ret_ty);
......@@ -9897,7 +9896,7 @@ pub const FuncGen = struct {
98979896 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
98989897 const ptr_ty = self.typeOf(bin_op.lhs);
98999898 const operand_ty = ptr_ty.childType(zcu);
9900 if (!operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return .none;
9899 if (!operand_ty.hasRuntimeBits(zcu)) return .none;
99019900 const ptr = try self.resolveInst(bin_op.lhs);
99029901 var element = try self.resolveInst(bin_op.rhs);
99039902 const llvm_abi_ty = try o.getAtomicAbiType(pt, operand_ty, false);
......@@ -11478,7 +11477,7 @@ pub const FuncGen = struct {
1147811477 const zcu = pt.zcu;
1147911478 const info = ptr_ty.ptrInfo(zcu);
1148011479 const elem_ty = Type.fromInterned(info.child);
11481 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {
11480 if (!elem_ty.hasRuntimeBits(zcu)) {
1148211481 return;
1148311482 }
1148411483 const ptr_alignment = ptr_ty.ptrAlignment(zcu).toLlvm();
src/codegen/riscv64/CodeGen.zig+2-2
......@@ -2673,7 +2673,7 @@ fn genBinOp(
26732673 defer func.register_manager.unlockReg(tmp_lock);
26742674
26752675 // RISC-V has no immediate mul, so we copy the size to a temporary register
2676 const elem_size = lhs_ty.indexablePtrElem(zcu).abiSize(zcu);
2676 const elem_size = lhs_ty.indexableElem(zcu).abiSize(zcu);
26772677 const elem_size_reg = try func.copyToTmpRegister(Type.u64, .{ .immediate = elem_size });
26782678
26792679 try func.genBinOp(
......@@ -3913,7 +3913,7 @@ fn airPtrElemVal(func: *Func, inst: Air.Inst.Index) !void {
39133913 const base_ptr_ty = func.typeOf(bin_op.lhs);
39143914
39153915 const result: MCValue = if (!is_volatile and func.liveness.isUnused(inst)) .unreach else result: {
3916 const elem_ty = base_ptr_ty.indexablePtrElem(zcu);
3916 const elem_ty = base_ptr_ty.indexableElem(zcu);
39173917 if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none;
39183918 const base_ptr_mcv = try func.resolveInst(bin_op.lhs);
39193919 const base_ptr_lock: ?RegisterLock = switch (base_ptr_mcv) {
src/codegen/spirv/CodeGen.zig+6-7
......@@ -821,7 +821,6 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
821821 .undefined,
822822 .void,
823823 .null,
824 .empty_tuple,
825824 .@"unreachable",
826825 => unreachable, // non-runtime values
827826
......@@ -1150,7 +1149,7 @@ fn constantUavRef(
11501149 }
11511150
11521151 // const is_fn_body = decl_ty.zigTypeTag(zcu) == .@"fn";
1153 if (!uav_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {
1152 if (!uav_ty.hasRuntimeBits(zcu)) {
11541153 // Pointer to nothing - return undefined
11551154 return cg.module.constUndef(ty_id);
11561155 }
......@@ -1196,7 +1195,7 @@ fn constantNavRef(cg: *CodeGen, ty: Type, nav_index: InternPool.Nav.Index) !Id {
11961195 },
11971196 }
11981197
1199 if (!nav_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {
1198 if (!nav_ty.hasRuntimeBits(zcu)) {
12001199 // Pointer to nothing - return undefined.
12011200 return cg.module.constUndef(ty_id);
12021201 }
......@@ -4381,7 +4380,7 @@ fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
43814380fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id {
43824381 const zcu = cg.module.zcu;
43834382 // Construct new pointer type for the resulting pointer
4384 const elem_ty = ptr_ty.indexablePtrElem(zcu);
4383 const elem_ty = ptr_ty.indexableElem(zcu);
43854384 const elem_ty_id = try cg.resolveType(elem_ty, .indirect);
43864385 const elem_ptr_ty_id = try cg.module.ptrType(elem_ty_id, cg.module.storageClass(ptr_ty.ptrAddressSpace(zcu)));
43874386 if (ptr_ty.isSinglePointer(zcu)) {
......@@ -5028,7 +5027,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
50285027 const gpa = cg.module.gpa;
50295028 const zcu = cg.module.zcu;
50305029 const ty = cg.typeOfIndex(inst);
5031 const have_block_result = ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu);
5030 const have_block_result = ty.hasRuntimeBits(zcu);
50325031
50335032 const cf = switch (cg.control_flow) {
50345033 .structured => |*cf| cf,
......@@ -5166,7 +5165,7 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
51665165
51675166 switch (cg.control_flow) {
51685167 .structured => |*cf| {
5169 if (operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {
5168 if (operand_ty.hasRuntimeBits(zcu)) {
51705169 const operand_id = try cg.resolve(br.operand);
51715170 const block_result_var_id = cf.block_results.get(br.block_inst).?;
51725171 try cg.store(operand_ty, block_result_var_id, operand_id, .{});
......@@ -5177,7 +5176,7 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
51775176 },
51785177 .unstructured => |cf| {
51795178 const block = cf.blocks.get(br.block_inst).?;
5180 if (operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {
5179 if (operand_ty.hasRuntimeBits(zcu)) {
51815180 const operand_id = try cg.resolve(br.operand);
51825181 // block_label should not be undefined here, lest there
51835182 // is a br or br_void in the function's body.
src/codegen/wasm/CodeGen.zig+1-2
......@@ -2099,7 +2099,7 @@ fn airRetPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
20992099 const child_type = cg.typeOfIndex(inst).childType(zcu);
21002100
21012101 const result = result: {
2102 if (!child_type.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {
2102 if (!child_type.hasRuntimeBits(zcu)) {
21032103 break :result try cg.allocStack(Type.usize); // create pointer to void
21042104 }
21052105
......@@ -3161,7 +3161,6 @@ fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue {
31613161 .undefined,
31623162 .void,
31633163 .null,
3164 .empty_tuple,
31653164 .@"unreachable",
31663165 => unreachable, // non-runtime values
31673166 .false, .true => return .{ .imm32 = switch (simple_value) {
src/codegen/x86_64/CodeGen.zig+7-7
......@@ -104121,7 +104121,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
104121104121 },
104122104122 .slice_elem_val, .ptr_elem_val => {
104123104123 const bin_op = air_datas[@intFromEnum(inst)].bin_op;
104124 const res_ty = cg.typeOf(bin_op.lhs).indexablePtrElem(zcu);
104124 const res_ty = cg.typeOf(bin_op.lhs).indexableElem(zcu);
104125104125 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
104126104126 try ops[0].toSlicePtr(cg);
104127104127 var res: [1]Temp = undefined;
......@@ -188179,8 +188179,8 @@ const Select = struct {
188179188179 .signed => false,
188180188180 .unsigned => size.bitSize(cg.target) >= int_info.bits,
188181188181 } else false,
188182 .elem_size_is => |size| size == ty.indexablePtrElem(zcu).abiSize(zcu),
188183 .po2_elem_size => std.math.isPowerOfTwo(ty.indexablePtrElem(zcu).abiSize(zcu)),
188182 .elem_size_is => |size| size == ty.indexableElem(zcu).abiSize(zcu),
188183 .po2_elem_size => std.math.isPowerOfTwo(ty.indexableElem(zcu).abiSize(zcu)),
188184188184 };
188185188185 }
188186188186 };
......@@ -189941,9 +189941,9 @@ const Select = struct {
189941189941 op.flags.base.ref.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu),
189942189942 @divExact(op.flags.base.size.bitSize(s.cg.target), 8),
189943189943 )),
189944 .elem_size => @intCast(op.flags.base.ref.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)),
189945 .src0_elem_size => @intCast(Select.Operand.Ref.src0.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)),
189946 .dst0_elem_size => @intCast(Select.Operand.Ref.dst0.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)),
189944 .elem_size => @intCast(op.flags.base.ref.typeOf(s).indexableElem(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)),
189945 .src0_elem_size => @intCast(Select.Operand.Ref.src0.typeOf(s).indexableElem(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)),
189946 .dst0_elem_size => @intCast(Select.Operand.Ref.dst0.typeOf(s).indexableElem(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)),
189947189947 .src0_elem_size_mul_src1 => @intCast(Select.Operand.Ref.src0.typeOf(s).indexableElem(s.cg.pt.zcu).abiSize(s.cg.pt.zcu) *
189948189948 Select.Operand.Ref.src1.valueOf(s).immediate),
189949189949 .vector_index => switch (op.flags.base.ref.typeOf(s).ptrInfo(s.cg.pt.zcu).flags.vector_index) {
......@@ -189953,7 +189953,7 @@ const Select = struct {
189953189953 .src1 => @intCast(Select.Operand.Ref.src1.valueOf(s).immediate),
189954189954 .src1_sub_bit_size => @as(SignedImm, @intCast(Select.Operand.Ref.src1.valueOf(s).immediate)) -
189955189955 @as(SignedImm, @intCast(s.cg.nonBoolScalarBitSize(op.flags.base.ref.typeOf(s)))),
189956 .log2_src0_elem_size => @intCast(std.math.log2(Select.Operand.Ref.src0.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu))),
189956 .log2_src0_elem_size => @intCast(std.math.log2(Select.Operand.Ref.src0.typeOf(s).indexableElem(s.cg.pt.zcu).abiSize(s.cg.pt.zcu))),
189957189957 .elem_mask => @as(u8, std.math.maxInt(u8)) >> @intCast(
189958189958 8 - ((s.cg.unalignedSize(op.flags.base.ref.typeOf(s)) - 1) %
189959189959 @divExact(op.flags.base.size.bitSize(s.cg.target), 8) + 1 >>
src/link/Coff.zig+1-1
......@@ -1552,7 +1552,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
15521552 const sec_si = try coff.navSection(zcu, nav.status.fully_resolved);
15531553 try coff.nodes.ensureUnusedCapacity(gpa, 1);
15541554 const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{
1555 .alignment = pt.navAlignment(nav_index).toStdMem(),
1555 .alignment = zcu.navAlignment(nav_index).toStdMem(),
15561556 .moved = true,
15571557 });
15581558 coff.nodes.appendAssumeCapacity(.{ .nav = nmi });
src/link/Elf/ZigObject.zig+1-1
......@@ -1479,7 +1479,7 @@ fn updateTlv(
14791479
14801480 log.debug("updateTlv {f}({d})", .{ nav.fqn.fmt(ip), nav_index });
14811481
1482 const required_alignment = pt.navAlignment(nav_index);
1482 const required_alignment = zcu.navAlignment(nav_index);
14831483
14841484 const sym = self.symbol(sym_index);
14851485 const esym = &self.symtab.items(.elf_sym)[sym.esym_index];
src/link/Elf2.zig+1-1
......@@ -2906,7 +2906,7 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
29062906 try elf.nodes.ensureUnusedCapacity(gpa, 1);
29072907 const sec_si = elf.navSection(ip, nav.status.fully_resolved);
29082908 const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{
2909 .alignment = pt.navAlignment(nav_index).toStdMem(),
2909 .alignment = zcu.navAlignment(nav_index).toStdMem(),
29102910 .moved = true,
29112911 });
29122912 elf.nodes.appendAssumeCapacity(.{ .nav = nmi });
src/link/MachO/ZigObject.zig+4-4
......@@ -925,7 +925,7 @@ pub fn updateNav(
925925
926926 const sect_index = try self.getNavOutputSection(macho_file, zcu, nav_index, code);
927927 if (isThreadlocal(macho_file, nav_index))
928 try self.updateTlv(macho_file, pt, nav_index, sym_index, sect_index, code)
928 try self.updateTlv(macho_file, zcu, nav_index, sym_index, sect_index, code)
929929 else
930930 try self.updateNavCode(macho_file, pt, nav_index, sym_index, sect_index, code);
931931
......@@ -1030,13 +1030,13 @@ fn updateNavCode(
10301030fn updateTlv(
10311031 self: *ZigObject,
10321032 macho_file: *MachO,
1033 pt: Zcu.PerThread,
1033 zcu: *Zcu,
10341034 nav_index: InternPool.Nav.Index,
10351035 sym_index: Symbol.Index,
10361036 sect_index: u8,
10371037 code: []const u8,
10381038) !void {
1039 const ip = &pt.zcu.intern_pool;
1039 const ip = &zcu.intern_pool;
10401040 const nav = ip.getNav(nav_index);
10411041
10421042 log.debug("updateTlv {f} (0x{x})", .{ nav.fqn.fmt(ip), nav_index });
......@@ -1045,7 +1045,7 @@ fn updateTlv(
10451045 const init_sym_index = try self.createTlvInitializer(
10461046 macho_file,
10471047 nav.fqn.toSlice(ip),
1048 pt.navAlignment(nav_index),
1048 zcu.navAlignment(nav_index),
10491049 sect_index,
10501050 code,
10511051 );
src/print_value.zig+26-12
......@@ -72,8 +72,13 @@ pub fn print(
7272 .undef => try writer.writeAll("undefined"),
7373 .simple_value => |simple_value| switch (simple_value) {
7474 .void => try writer.writeAll("{}"),
75 .empty_tuple => try writer.writeAll(".{}"),
76 else => try writer.writeAll(@tagName(simple_value)),
75
76 .undefined,
77 .null,
78 .true,
79 .false,
80 .@"unreachable",
81 => try writer.writeAll(@tagName(simple_value)),
7782 },
7883 .variable => try writer.writeAll("(variable)"),
7984 .@"extern" => |e| try writer.print("(extern '{f}')", .{e.name.fmt(ip)}),
......@@ -248,17 +253,26 @@ fn printAggregate(
248253 const len = ty.arrayLen(zcu);
249254
250255 if (is_ref) try writer.writeByte('&');
251 try writer.writeAll(".{ ");
252
253 const max_len = @min(len, max_aggregate_items);
254 for (0..max_len) |i| {
255 if (i != 0) try writer.writeAll(", ");
256 try print(try val.fieldValue(pt, i), writer, level - 1, pt, opt_sema);
257 }
258 if (len > max_aggregate_items) {
259 try writer.writeAll(", ...");
256 switch (len) {
257 0 => try writer.writeAll(".{}"),
258 1 => {
259 try writer.writeAll(".{");
260 try print(try val.fieldValue(pt, 0), writer, level - 1, pt, opt_sema);
261 try writer.writeByte('}');
262 },
263 else => {
264 try writer.writeAll(".{ ");
265 const max_len = @min(len, max_aggregate_items);
266 for (0..max_len) |i| {
267 if (i != 0) try writer.writeAll(", ");
268 try print(try val.fieldValue(pt, i), writer, level - 1, pt, opt_sema);
269 }
270 if (len > max_aggregate_items) {
271 try writer.writeAll(", ...");
272 }
273 try writer.writeAll(" }");
274 },
260275 }
261 return writer.writeAll(" }");
262276}
263277
264278fn printPtr(
src/print_zir.zig+15-11
......@@ -1439,10 +1439,10 @@ const Writer = struct {
14391439
14401440 try stream.print("{s}, ", .{@tagName(struct_decl.name_strategy)});
14411441
1442 if (struct_decl.backing_int_type != .none) {
1442 if (struct_decl.backing_int_type_body) |backing_int_type_body| {
14431443 assert(struct_decl.layout == .@"packed");
14441444 try stream.writeAll("packed(");
1445 try self.writeInstRef(stream, struct_decl.backing_int_type);
1445 try self.writeBracedDecl(stream, backing_int_type_body);
14461446 try stream.writeAll("), ");
14471447 } else {
14481448 try stream.print("{s}, ", .{@tagName(struct_decl.layout)});
......@@ -1507,18 +1507,18 @@ const Writer = struct {
15071507 .@"packed" => try stream.writeAll("packed, "),
15081508 .packed_explicit => {
15091509 try stream.writeAll("packed(");
1510 try self.writeInstRef(stream, union_decl.arg_type);
1510 try self.writeBracedDecl(stream, union_decl.arg_type_body.?);
15111511 try stream.writeAll("), ");
15121512 },
15131513 .tagged_explicit => {
1514 try stream.writeAll("auto(");
1515 try self.writeInstRef(stream, union_decl.arg_type);
1514 try stream.writeAll("tagged(");
1515 try self.writeBracedDecl(stream, union_decl.arg_type_body.?);
15161516 try stream.writeAll("), ");
15171517 },
1518 .tagged_enum => try stream.writeAll("auto(enum)"),
1518 .tagged_enum => try stream.writeAll("tagged(enum), "),
15191519 .tagged_enum_explicit => {
1520 try stream.writeAll("auto(enum(");
1521 try self.writeInstRef(stream, union_decl.arg_type);
1520 try stream.writeAll("tagged(enum(");
1521 try self.writeBracedDecl(stream, union_decl.arg_type_body.?);
15221522 try stream.writeAll(")), ");
15231523 },
15241524 }
......@@ -1577,7 +1577,11 @@ const Writer = struct {
15771577
15781578 try stream.print("{s}, ", .{@tagName(enum_decl.name_strategy)});
15791579 try self.writeFlag(stream, "nonexhaustive, ", enum_decl.nonexhaustive);
1580 try self.writeInstRef(stream, enum_decl.tag_type);
1580 if (enum_decl.tag_type_body) |tag_type_body| {
1581 try stream.writeAll("tag(");
1582 try self.writeBracedDecl(stream, tag_type_body);
1583 try stream.writeAll("), ");
1584 }
15811585
15821586 try self.writeCaptures(stream, enum_decl.captures, enum_decl.capture_names);
15831587 try stream.writeAll(", ");
......@@ -1585,9 +1589,9 @@ const Writer = struct {
15851589 try stream.writeAll(", ");
15861590
15871591 if (enum_decl.field_names.len == 0) {
1588 try stream.writeAll(", {}) ");
1592 try stream.writeAll("{}) ");
15891593 } else {
1590 try stream.writeAll(", {\n");
1594 try stream.writeAll("{\n");
15911595 self.indent += 2;
15921596
15931597 var it = enum_decl.iterateFields();