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) {...@@ -837,6 +837,10 @@ pub const SimpleComptimeReason = enum(u32) {
837 tuple_field_types,837 tuple_field_types,
838 enum_field_names,838 enum_field_names,
839 enum_field_values,839 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
841 // Evaluating at comptime because decl/field name must be comptime-known.845 // Evaluating at comptime because decl/field name must be comptime-known.
842 decl_name,846 decl_name,
...@@ -925,6 +929,11 @@ pub const SimpleComptimeReason = enum(u32) {...@@ -925,6 +929,11 @@ pub const SimpleComptimeReason = enum(u32) {
925 .enum_field_names => "enum field names must be comptime-known",929 .enum_field_names => "enum field names must be comptime-known",
926 .enum_field_values => "enum field values must be comptime-known",930 .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
928 .decl_name => "declaration name must be comptime-known",937 .decl_name => "declaration name must be comptime-known",
929 .field_name => "field name must be comptime-known",938 .field_name => "field name must be comptime-known",
930 .tuple_field_index => "tuple field index must be comptime-known",939 .tuple_field_index => "tuple field index must be comptime-known",
lib/std/zig/AstGen.zig+69-54
...@@ -4922,24 +4922,14 @@ fn structDeclInner(...@@ -4922,24 +4922,14 @@ fn structDeclInner(
49224922
4923 astgen.advanceSourceCursorToNode(node);4923 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
4935 const decl_inst = try gz.reserveInstructionIndex();4925 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) {
4938 try gz.setStruct(decl_inst, .{4928 try gz.setStruct(decl_inst, .{
4939 .src_node = node,4929 .src_node = node,
4940 .name_strat = name_strat,4930 .name_strat = name_strat,
4941 .layout = layout,4931 .layout = layout,
4942 .backing_int_type = .none,4932 .backing_int_type_body_len = null,
4943 .decls_len = 0,4933 .decls_len = 0,
4944 .fields_len = 0,4934 .fields_len = 0,
4945 .any_field_aligns = false,4935 .any_field_aligns = false,
...@@ -4993,6 +4983,22 @@ fn structDeclInner(...@@ -4993,6 +4983,22 @@ fn structDeclInner(
4993 );4983 );
4994 if (field_comptime_bits) |bits| @memset(bits.get(astgen), 0);4984 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
4996 const old_hasher = astgen.src_hasher;5002 const old_hasher = astgen.src_hasher;
4997 defer astgen.src_hasher = old_hasher;5003 defer astgen.src_hasher = old_hasher;
4998 astgen.src_hasher = .init(.{});5004 astgen.src_hasher = .init(.{});
...@@ -5076,7 +5082,7 @@ fn structDeclInner(...@@ -5076,7 +5082,7 @@ fn structDeclInner(
5076 .src_node = node,5082 .src_node = node,
5077 .name_strat = name_strat,5083 .name_strat = name_strat,
5078 .layout = layout,5084 .layout = layout,
5079 .backing_int_type = backing_int_type_ref,5085 .backing_int_type_body_len = backing_int_type_body_len,
5080 .decls_len = scan_result.decls_len,5086 .decls_len = scan_result.decls_len,
5081 .fields_len = scan_result.fields_len,5087 .fields_len = scan_result.fields_len,
5082 .any_field_aligns = scan_result.any_field_aligns,5088 .any_field_aligns = scan_result.any_field_aligns,
...@@ -5220,11 +5226,6 @@ fn unionDeclInner(...@@ -5220,11 +5226,6 @@ fn unionDeclInner(
52205226
5221 astgen.advanceSourceCursorToNode(node);5227 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
5228 const decl_inst = try gz.reserveInstructionIndex();5229 const decl_inst = try gz.reserveInstructionIndex();
52295230
5230 var namespace: Scope.Namespace = .{5231 var namespace: Scope.Namespace = .{
...@@ -5262,6 +5263,17 @@ fn unionDeclInner(...@@ -5262,6 +5263,17 @@ fn unionDeclInner(
5262 const field_align_body_lens = try scratch.addOptionalSlice(scan_result.any_field_aligns, scan_result.fields_len);5263 const field_align_body_lens = try scratch.addOptionalSlice(scan_result.any_field_aligns, scan_result.fields_len);
5263 const field_value_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, scan_result.fields_len);5264 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
5265 const old_hasher = astgen.src_hasher;5277 const old_hasher = astgen.src_hasher;
5266 defer astgen.src_hasher = old_hasher;5278 defer astgen.src_hasher = old_hasher;
5267 astgen.src_hasher = .init(.{});5279 astgen.src_hasher = .init(.{});
...@@ -5358,7 +5370,7 @@ fn unionDeclInner(...@@ -5358,7 +5370,7 @@ fn unionDeclInner(
5358 .@"extern" => .@"extern",5370 .@"extern" => .@"extern",
5359 .@"packed" => if (opt_arg_node != .none) .packed_explicit else .@"packed",5371 .@"packed" => if (opt_arg_node != .none) .packed_explicit else .@"packed",
5360 },5372 },
5361 .arg_type = arg_type_ref,5373 .arg_type_body_len = arg_type_body_len,
5362 .decls_len = scan_result.decls_len,5374 .decls_len = scan_result.decls_len,
5363 .fields_len = scan_result.fields_len,5375 .fields_len = scan_result.fields_len,
5364 .any_field_aligns = scan_result.any_field_aligns,5376 .any_field_aligns = scan_result.any_field_aligns,
...@@ -5420,11 +5432,6 @@ fn containerDecl(...@@ -5420,11 +5432,6 @@ fn containerDecl(
54205432
5421 astgen.advanceSourceCursorToNode(node);5433 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
5428 const decl_inst = try gz.reserveInstructionIndex();5435 const decl_inst = try gz.reserveInstructionIndex();
54295436
5430 var namespace: Scope.Namespace = .{5437 var namespace: Scope.Namespace = .{
...@@ -5461,6 +5468,17 @@ fn containerDecl(...@@ -5461,6 +5468,17 @@ fn containerDecl(
5461 const field_names = try scratch.addSlice(fields_len);5468 const field_names = try scratch.addSlice(fields_len);
5462 const field_value_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, fields_len);5469 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
5464 const old_hasher = astgen.src_hasher;5482 const old_hasher = astgen.src_hasher;
5465 defer astgen.src_hasher = old_hasher;5483 defer astgen.src_hasher = old_hasher;
5466 astgen.src_hasher = .init(.{});5484 astgen.src_hasher = .init(.{});
...@@ -5508,7 +5526,7 @@ fn containerDecl(...@@ -5508,7 +5526,7 @@ fn containerDecl(
5508 field_names.get(astgen)[field_idx] = @intFromEnum(try astgen.identAsString(member.ast.main_token));5526 field_names.get(astgen)[field_idx] = @intFromEnum(try astgen.identAsString(member.ast.main_token));
55095527
5510 if (member.ast.value_expr.unwrap()) |value_node| {5528 if (member.ast.value_expr.unwrap()) |value_node| {
5511 if (tag_type_ref == .none) {5529 if (tag_type_body_len == null) {
5512 return astgen.failNodeNotes(node, "explicitly valued enum missing integer tag type", .{}, &.{5530 return astgen.failNodeNotes(node, "explicitly valued enum missing integer tag type", .{}, &.{
5513 try astgen.errNoteNode(value_node, "tag value specified here", .{}),5531 try astgen.errNoteNode(value_node, "tag value specified here", .{}),
5514 });5532 });
...@@ -5535,7 +5553,7 @@ fn containerDecl(...@@ -5535,7 +5553,7 @@ fn containerDecl(
5535 try gz.setEnum(decl_inst, .{5553 try gz.setEnum(decl_inst, .{
5536 .src_node = node,5554 .src_node = node,
5537 .name_strat = name_strat,5555 .name_strat = name_strat,
5538 .tag_type = tag_type_ref,5556 .tag_type_body_len = tag_type_body_len,
5539 .nonexhaustive = scan_result.has_underscore_field,5557 .nonexhaustive = scan_result.has_underscore_field,
5540 .decls_len = scan_result.decls_len,5558 .decls_len = scan_result.decls_len,
5541 .fields_len = fields_len,5559 .fields_len = fields_len,
...@@ -12406,7 +12424,7 @@ const GenZir = struct {...@@ -12406,7 +12424,7 @@ const GenZir = struct {
12406 src_node: Ast.Node.Index,12424 src_node: Ast.Node.Index,
12407 name_strat: Zir.Inst.NameStrategy,12425 name_strat: Zir.Inst.NameStrategy,
12408 layout: std.builtin.Type.ContainerLayout,12426 layout: std.builtin.Type.ContainerLayout,
12409 backing_int_type: Zir.Inst.Ref,12427 backing_int_type_body_len: ?u32,
12410 decls_len: u32,12428 decls_len: u32,
12411 fields_len: u32,12429 fields_len: u32,
12412 any_field_aligns: bool,12430 any_field_aligns: bool,
...@@ -12430,7 +12448,7 @@ const GenZir = struct {...@@ -12430,7 +12448,7 @@ const GenZir = struct {
12430 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);12448 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);
1243112449
12432 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len +12450 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`
12434 captures_len * 2 + // `capture`, `capture_name`12452 captures_len * 2 + // `capture`, `capture_name`
12435 args.remaining.len);12453 args.remaining.len);
1243612454
...@@ -12446,7 +12464,7 @@ const GenZir = struct {...@@ -12446,7 +12464,7 @@ const GenZir = struct {
12446 if (captures_len != 0) astgen.extra.appendAssumeCapacity(captures_len);12464 if (captures_len != 0) astgen.extra.appendAssumeCapacity(captures_len);
12447 if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len);12465 if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len);
12448 if (args.fields_len != 0) astgen.extra.appendAssumeCapacity(args.fields_len);12466 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);
12450 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures));12468 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures));
12451 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names));12469 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names));
12452 astgen.extra.appendSliceAssumeCapacity(args.remaining);12470 astgen.extra.appendSliceAssumeCapacity(args.remaining);
...@@ -12461,7 +12479,7 @@ const GenZir = struct {...@@ -12461,7 +12479,7 @@ const GenZir = struct {
12461 .has_fields_len = args.fields_len != 0,12479 .has_fields_len = args.fields_len != 0,
12462 .name_strategy = args.name_strat,12480 .name_strategy = args.name_strat,
12463 .layout = args.layout,12481 .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,
12465 .any_field_aligns = args.any_field_aligns,12483 .any_field_aligns = args.any_field_aligns,
12466 .any_field_defaults = args.any_field_defaults,12484 .any_field_defaults = args.any_field_defaults,
12467 .any_comptime_fields = args.any_comptime_fields,12485 .any_comptime_fields = args.any_comptime_fields,
...@@ -12475,7 +12493,7 @@ const GenZir = struct {...@@ -12475,7 +12493,7 @@ const GenZir = struct {
12475 src_node: Ast.Node.Index,12493 src_node: Ast.Node.Index,
12476 name_strat: Zir.Inst.NameStrategy,12494 name_strat: Zir.Inst.NameStrategy,
12477 kind: Zir.Inst.UnionDecl.Kind,12495 kind: Zir.Inst.UnionDecl.Kind,
12478 arg_type: Zir.Inst.Ref,12496 arg_type_body_len: ?u32,
12479 decls_len: u32,12497 decls_len: u32,
12480 fields_len: u32,12498 fields_len: u32,
12481 any_field_aligns: bool,12499 any_field_aligns: bool,
...@@ -12497,7 +12515,7 @@ const GenZir = struct {...@@ -12497,7 +12515,7 @@ const GenZir = struct {
12497 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);12515 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);
1249812516
12499 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.UnionDecl).@"struct".fields.len +12517 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`
12501 captures_len * 2 + // `capture`, `capture_name`12519 captures_len * 2 + // `capture`, `capture_name`
12502 args.remaining.len);12520 args.remaining.len);
1250312521
...@@ -12514,10 +12532,9 @@ const GenZir = struct {...@@ -12514,10 +12532,9 @@ const GenZir = struct {
12514 if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len);12532 if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len);
12515 if (args.fields_len != 0) astgen.extra.appendAssumeCapacity(args.fields_len);12533 if (args.fields_len != 0) astgen.extra.appendAssumeCapacity(args.fields_len);
12516 if (args.kind.hasArgType()) {12534 if (args.kind.hasArgType()) {
12517 assert(args.arg_type != .none);12535 astgen.extra.appendAssumeCapacity(args.arg_type_body_len.?);
12518 astgen.extra.appendAssumeCapacity(@intFromEnum(args.arg_type));
12519 } else {12536 } else {
12520 assert(args.arg_type == .none);12537 assert(args.arg_type_body_len == null);
12521 }12538 }
12522 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures));12539 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures));
12523 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names));12540 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names));
...@@ -12525,28 +12542,26 @@ const GenZir = struct {...@@ -12525,28 +12542,26 @@ const GenZir = struct {
1252512542
12526 astgen.instructions.set(@intFromEnum(inst), .{12543 astgen.instructions.set(@intFromEnum(inst), .{
12527 .tag = .extended,12544 .tag = .extended,
12528 .data = .{12545 .data = .{ .extended = .{
12529 .extended = .{12546 .opcode = .union_decl,
12530 .opcode = .union_decl,12547 .small = @bitCast(Zir.Inst.UnionDecl.Small{
12531 .small = @bitCast(Zir.Inst.UnionDecl.Small{12548 .has_captures_len = captures_len != 0,
12532 .has_captures_len = captures_len != 0,12549 .has_decls_len = args.decls_len != 0,
12533 .has_decls_len = args.decls_len != 0,12550 .has_fields_len = args.fields_len != 0,
12534 .has_fields_len = args.fields_len != 0,12551 .name_strategy = args.name_strat,
12535 .name_strategy = args.name_strat,12552 .kind = args.kind,
12536 .kind = args.kind,12553 .any_field_aligns = args.any_field_aligns,
12537 .any_field_aligns = args.any_field_aligns,12554 .any_field_values = args.any_field_values,
12538 .any_field_values = args.any_field_values,12555 }),
12539 }),12556 .operand = payload_index,
12540 .operand = payload_index,12557 } },
12541 },
12542 },
12543 });12558 });
12544 }12559 }
1254512560
12546 fn setEnum(gz: *GenZir, inst: Zir.Inst.Index, args: struct {12561 fn setEnum(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
12547 src_node: Ast.Node.Index,12562 src_node: Ast.Node.Index,
12548 name_strat: Zir.Inst.NameStrategy,12563 name_strat: Zir.Inst.NameStrategy,
12549 tag_type: Zir.Inst.Ref,12564 tag_type_body_len: ?u32,
12550 nonexhaustive: bool,12565 nonexhaustive: bool,
12551 decls_len: u32,12566 decls_len: u32,
12552 fields_len: u32,12567 fields_len: u32,
...@@ -12568,7 +12583,7 @@ const GenZir = struct {...@@ -12568,7 +12583,7 @@ const GenZir = struct {
12568 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);12583 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);
1256912584
12570 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.EnumDecl).@"struct".fields.len +12585 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`
12572 captures_len * 2 + // `capture`, `capture_name`12587 captures_len * 2 + // `capture`, `capture_name`
12573 args.remaining.len);12588 args.remaining.len);
1257412589
...@@ -12584,7 +12599,7 @@ const GenZir = struct {...@@ -12584,7 +12599,7 @@ const GenZir = struct {
12584 if (captures_len != 0) astgen.extra.appendAssumeCapacity(captures_len);12599 if (captures_len != 0) astgen.extra.appendAssumeCapacity(captures_len);
12585 if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len);12600 if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len);
12586 if (args.fields_len != 0) astgen.extra.appendAssumeCapacity(args.fields_len);12601 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);
12588 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures));12603 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures));
12589 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names));12604 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names));
12590 astgen.extra.appendSliceAssumeCapacity(args.remaining);12605 astgen.extra.appendSliceAssumeCapacity(args.remaining);
...@@ -12598,7 +12613,7 @@ const GenZir = struct {...@@ -12598,7 +12613,7 @@ const GenZir = struct {
12598 .has_decls_len = args.decls_len != 0,12613 .has_decls_len = args.decls_len != 0,
12599 .has_fields_len = args.fields_len != 0,12614 .has_fields_len = args.fields_len != 0,
12600 .name_strategy = args.name_strat,12615 .name_strategy = args.name_strat,
12601 .has_tag_type = args.tag_type != .none,12616 .has_tag_type = args.tag_type_body_len != null,
12602 .nonexhaustive = args.nonexhaustive,12617 .nonexhaustive = args.nonexhaustive,
12603 .any_field_values = args.any_field_values,12618 .any_field_values = args.any_field_values,
12604 }),12619 }),
lib/std/zig/Zir.zig+42-36
...@@ -3465,7 +3465,7 @@ pub const Inst = struct {...@@ -3465,7 +3465,7 @@ pub const Inst = struct {
3465 /// 0. captures_len: u32 // if `has_captures_len`3465 /// 0. captures_len: u32 // if `has_captures_len`
3466 /// 1. decls_len: u32, // if `has_decls_len`3466 /// 1. decls_len: u32, // if `has_decls_len`
3467 /// 2. fields_len: u32, // if `has_fields_len`3467 /// 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`
3469 /// 4. capture: Capture // for every `captures_len`3469 /// 4. capture: Capture // for every `captures_len`
3470 /// 5. capture_name: NullTerminatedString // for every `captures_len`3470 /// 5. capture_name: NullTerminatedString // for every `captures_len`
3471 /// 6. decl: Index, // for every `decls_len`; points to a `declaration` instruction3471 /// 6. decl: Index, // for every `decls_len`; points to a `declaration` instruction
...@@ -3475,7 +3475,8 @@ pub const Inst = struct {...@@ -3475,7 +3475,8 @@ pub const Inst = struct {
3475 /// 10. field_default_body_len: u32 // for every `fields_len` if `any_field_defaults`3475 /// 10. field_default_body_len: u32 // for every `fields_len` if `any_field_defaults`
3476 /// 11. field_comptime_bits: u32 // one bit per `fields_len` if `any_comptime_fields`3476 /// 11. field_comptime_bits: u32 // one bit per `fields_len` if `any_comptime_fields`
3477 /// // LSB is first field, minimum number of `u32` needed3477 /// // 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 field3478 /// 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
3479 pub const StructDecl = struct {3480 pub const StructDecl = struct {
3480 // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.3481 // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.
3481 // This hash contains the source of all fields, and any specified attributes (`extern`, backing type, etc).3482 // This hash contains the source of all fields, and any specified attributes (`extern`, backing type, etc).
...@@ -3622,13 +3623,14 @@ pub const Inst = struct {...@@ -3622,13 +3623,14 @@ pub const Inst = struct {
3622 /// 0. captures_len: u32, // if has_captures_len3623 /// 0. captures_len: u32, // if has_captures_len
3623 /// 1. decls_len: u32, // if has_decls_len3624 /// 1. decls_len: u32, // if has_decls_len
3624 /// 2. fields_len: u32, // if has_fields_len3625 /// 2. fields_len: u32, // if has_fields_len
3625 /// 3. tag_type: Ref, // if has_tag_type3626 /// 3. tag_type_body_len: u32, // if has_tag_type
3626 /// 4. capture: Capture // for every `captures_len`3627 /// 4. capture: Capture // for every `captures_len`
3627 /// 5. capture_name: NullTerminatedString // for every `captures_len`3628 /// 5. capture_name: NullTerminatedString // for every `captures_len`
3628 /// 6. decl: Index, // for every `decls_len`; points to a `declaration` instruction3629 /// 6. decl: Index, // for every `decls_len`; points to a `declaration` instruction
3629 /// 7. field_name: NullTerminatedString // for every `fields_len`3630 /// 7. field_name: NullTerminatedString // for every `fields_len`
3630 /// 8. field_value_body_len: u32 // for every `fields_len` if `any_field_values`3631 /// 8. field_value_body_len: u32 // for every `fields_len` if `any_field_values`
3631 /// 9. body_inst: Inst.Index // value body for each field3632 /// 9. tag_type_body_inst: Inst.Index // for each `tag_type_body_len`
3633 /// 10. body_inst: Inst.Index // value body for each field
3632 pub const EnumDecl = struct {3634 pub const EnumDecl = struct {
3633 // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.3635 // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.
3634 // This hash contains the source of all fields, and the backing type if specified.3636 // This hash contains the source of all fields, and the backing type if specified.
...@@ -3656,7 +3658,7 @@ pub const Inst = struct {...@@ -3656,7 +3658,7 @@ pub const Inst = struct {
3656 /// 0. captures_len: u32 // if `has_captures_len`3658 /// 0. captures_len: u32 // if `has_captures_len`
3657 /// 1. decls_len: u32, // if `has_decls_len`3659 /// 1. decls_len: u32, // if `has_decls_len`
3658 /// 2. fields_len: u32, // if `has_fields_len`3660 /// 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()`
3660 /// 4. capture: Capture // for every `captures_len`3662 /// 4. capture: Capture // for every `captures_len`
3661 /// 5. capture_name: NullTerminatedString // for every `captures_len`3663 /// 5. capture_name: NullTerminatedString // for every `captures_len`
3662 /// 6. decl: Index, // for every `decls_len`; points to a `declaration` instruction3664 /// 6. decl: Index, // for every `decls_len`; points to a `declaration` instruction
...@@ -3664,7 +3666,8 @@ pub const Inst = struct {...@@ -3664,7 +3666,8 @@ pub const Inst = struct {
3664 /// 8. field_type_body_len: u32 // for every `fields_len`3666 /// 8. field_type_body_len: u32 // for every `fields_len`
3665 /// 9 . field_align_body_len: u32 // for every `fields_len` if `any_field_aligns`3667 /// 9 . field_align_body_len: u32 // for every `fields_len` if `any_field_aligns`
3666 /// 10. field_value_body_len: u32 // for every `fields_len` if `any_field_values`3668 /// 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 field3669 /// 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
3668 pub const UnionDecl = struct {3671 pub const UnionDecl = struct {
3669 // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.3672 // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.
3670 // This hash contains the source of all fields, and any specified attributes (`extern` etc).3673 // 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 {...@@ -5235,18 +5238,6 @@ pub fn assertTrackable(zir: Zir, inst_idx: Zir.Inst.Index) void {
5235 }5238 }
5236}5239}
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}
5250pub fn typeDecls(zir: Zir, type_decl: Inst.Index) []const Zir.Inst.Index {5241pub fn typeDecls(zir: Zir, type_decl: Inst.Index) []const Zir.Inst.Index {
5251 const inst = zir.instructions.get(@intFromEnum(type_decl));5242 const inst = zir.instructions.get(@intFromEnum(type_decl));
5252 assert(inst.tag == .extended);5243 assert(inst.tag == .extended);
...@@ -5281,11 +5272,11 @@ pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDe...@@ -5281,11 +5272,11 @@ pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDe
5281 extra_index += 1;5272 extra_index += 1;
5282 break :blk fields_len;5273 break :blk fields_len;
5283 } else 0;5274 } else 0;
5284 const backing_int_type: Inst.Ref = if (small.has_backing_int_type) ty: {5275 const backing_int_type_body_len: u32 = if (small.has_backing_int_type) len: {
5285 const ty = zir.extra[extra_index];5276 const body_len = zir.extra[extra_index];
5286 extra_index += 1;5277 extra_index += 1;
5287 break :ty @enumFromInt(ty);5278 break :len body_len;
5288 } else .none;5279 } else 0;
5289 const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]);5280 const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]);
5290 extra_index += captures_len;5281 extra_index += captures_len;
5291 const capture_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..captures_len]);5282 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...@@ -5312,6 +5303,11 @@ pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDe
5312 extra_index += bits_len;5303 extra_index += bits_len;
5313 break :bits bits;5304 break :bits bits;
5314 } else null;5305 } 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;
5315 const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]);5311 const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]);
5316 return .{5312 return .{
5317 .src_line = extra.data.src_line,5313 .src_line = extra.data.src_line,
...@@ -5321,7 +5317,7 @@ pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDe...@@ -5321,7 +5317,7 @@ pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDe
5321 .capture_names = capture_names,5317 .capture_names = capture_names,
5322 .decls = decls,5318 .decls = decls,
5323 .layout = small.layout,5319 .layout = small.layout,
5324 .backing_int_type = backing_int_type,5320 .backing_int_type_body = backing_int_type_body,
5325 .field_names = field_names,5321 .field_names = field_names,
5326 .field_type_body_lens = field_type_body_lens,5322 .field_type_body_lens = field_type_body_lens,
5327 .field_align_body_lens = field_align_body_lens,5323 .field_align_body_lens = field_align_body_lens,
...@@ -5341,7 +5337,7 @@ pub const UnwrappedStructDecl = struct {...@@ -5341,7 +5337,7 @@ pub const UnwrappedStructDecl = struct {
5341 decls: []const Inst.Index,5337 decls: []const Inst.Index,
53425338
5343 layout: std.builtin.Type.ContainerLayout,5339 layout: std.builtin.Type.ContainerLayout,
5344 backing_int_type: Inst.Ref,5340 backing_int_type_body: ?[]const Inst.Index,
53455341
5346 field_names: []const NullTerminatedString,5342 field_names: []const NullTerminatedString,
5347 field_type_body_lens: []const u32,5343 field_type_body_lens: []const u32,
...@@ -5427,11 +5423,11 @@ pub fn getUnionDecl(zir: *const Zir, union_decl: Inst.Index) UnwrappedUnionDecl...@@ -5427,11 +5423,11 @@ pub fn getUnionDecl(zir: *const Zir, union_decl: Inst.Index) UnwrappedUnionDecl
5427 extra_index += 1;5423 extra_index += 1;
5428 break :blk fields_len;5424 break :blk fields_len;
5429 } else 0;5425 } else 0;
5430 const arg_type: Inst.Ref = if (small.kind.hasArgType()) ty: {5426 const arg_type_body_len: u32 = if (small.kind.hasArgType()) len: {
5431 const ty = zir.extra[extra_index];5427 const body_len = zir.extra[extra_index];
5432 extra_index += 1;5428 extra_index += 1;
5433 break :ty @enumFromInt(ty);5429 break :len body_len;
5434 } else .none;5430 } else 0;
5435 const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]);5431 const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]);
5436 extra_index += captures_len;5432 extra_index += captures_len;
5437 const capture_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..captures_len]);5433 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...@@ -5452,6 +5448,11 @@ pub fn getUnionDecl(zir: *const Zir, union_decl: Inst.Index) UnwrappedUnionDecl
5452 extra_index += fields_len;5448 extra_index += fields_len;
5453 break :lens @ptrCast(lens);5449 break :lens @ptrCast(lens);
5454 } else null;5450 } 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;
5455 const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]);5456 const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]);
5456 return .{5457 return .{
5457 .src_line = extra.data.src_line,5458 .src_line = extra.data.src_line,
...@@ -5461,7 +5462,7 @@ pub fn getUnionDecl(zir: *const Zir, union_decl: Inst.Index) UnwrappedUnionDecl...@@ -5461,7 +5462,7 @@ pub fn getUnionDecl(zir: *const Zir, union_decl: Inst.Index) UnwrappedUnionDecl
5461 .capture_names = capture_names,5462 .capture_names = capture_names,
5462 .decls = decls,5463 .decls = decls,
5463 .kind = small.kind,5464 .kind = small.kind,
5464 .arg_type = arg_type,5465 .arg_type_body = arg_type_body,
5465 .field_names = field_names,5466 .field_names = field_names,
5466 .field_type_body_lens = field_type_body_lens,5467 .field_type_body_lens = field_type_body_lens,
5467 .field_align_body_lens = field_align_body_lens,5468 .field_align_body_lens = field_align_body_lens,
...@@ -5480,7 +5481,7 @@ pub const UnwrappedUnionDecl = struct {...@@ -5480,7 +5481,7 @@ pub const UnwrappedUnionDecl = struct {
5480 decls: []const Inst.Index,5481 decls: []const Inst.Index,
54815482
5482 kind: Inst.UnionDecl.Kind,5483 kind: Inst.UnionDecl.Kind,
5483 arg_type: Inst.Ref,5484 arg_type_body: ?[]const Inst.Index,
54845485
5485 field_names: []const NullTerminatedString,5486 field_names: []const NullTerminatedString,
5486 field_type_body_lens: []const u32,5487 field_type_body_lens: []const u32,
...@@ -5556,11 +5557,11 @@ pub fn getEnumDecl(zir: *const Zir, enum_decl: Inst.Index) UnwrappedEnumDecl {...@@ -5556,11 +5557,11 @@ pub fn getEnumDecl(zir: *const Zir, enum_decl: Inst.Index) UnwrappedEnumDecl {
5556 extra_index += 1;5557 extra_index += 1;
5557 break :blk fields_len;5558 break :blk fields_len;
5558 } else 0;5559 } else 0;
5559 const tag_type: Inst.Ref = if (small.has_tag_type) ty: {5560 const tag_type_body_len: u32 = if (small.has_tag_type) len: {
5560 const ty = zir.extra[extra_index];5561 const body_len = zir.extra[extra_index];
5561 extra_index += 1;5562 extra_index += 1;
5562 break :ty @enumFromInt(ty);5563 break :len body_len;
5563 } else .none;5564 } else 0;
5564 const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]);5565 const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]);
5565 extra_index += captures_len;5566 extra_index += captures_len;
5566 const capture_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..captures_len]);5567 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 {...@@ -5574,6 +5575,11 @@ pub fn getEnumDecl(zir: *const Zir, enum_decl: Inst.Index) UnwrappedEnumDecl {
5574 extra_index += fields_len;5575 extra_index += fields_len;
5575 break :lens @ptrCast(lens);5576 break :lens @ptrCast(lens);
5576 } else null;5577 } 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;
5577 const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]);5583 const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]);
5578 return .{5584 return .{
5579 .src_line = extra.data.src_line,5585 .src_line = extra.data.src_line,
...@@ -5582,7 +5588,7 @@ pub fn getEnumDecl(zir: *const Zir, enum_decl: Inst.Index) UnwrappedEnumDecl {...@@ -5582,7 +5588,7 @@ pub fn getEnumDecl(zir: *const Zir, enum_decl: Inst.Index) UnwrappedEnumDecl {
5582 .captures = captures,5588 .captures = captures,
5583 .capture_names = capture_names,5589 .capture_names = capture_names,
5584 .decls = decls,5590 .decls = decls,
5585 .tag_type = tag_type,5591 .tag_type_body = tag_type_body,
5586 .nonexhaustive = small.nonexhaustive,5592 .nonexhaustive = small.nonexhaustive,
5587 .field_names = field_names,5593 .field_names = field_names,
5588 .field_value_body_lens = field_value_body_lens,5594 .field_value_body_lens = field_value_body_lens,
...@@ -5599,7 +5605,7 @@ pub const UnwrappedEnumDecl = struct {...@@ -5599,7 +5605,7 @@ pub const UnwrappedEnumDecl = struct {
55995605
5600 decls: []const Inst.Index,5606 decls: []const Inst.Index,
56015607
5602 tag_type: Inst.Ref,5608 tag_type_body: ?[]const Inst.Index,
5603 nonexhaustive: bool,5609 nonexhaustive: bool,
56045610
5605 field_names: []const NullTerminatedString,5611 field_names: []const NullTerminatedString,
src/Compilation.zig+6-6
...@@ -3713,7 +3713,7 @@ const Header = extern struct {...@@ -3713,7 +3713,7 @@ const Header = extern struct {
3713 nav_val_deps_len: u32,3713 nav_val_deps_len: u32,
3714 nav_ty_deps_len: u32,3714 nav_ty_deps_len: u32,
3715 type_layout_deps_len: u32,3715 type_layout_deps_len: u32,
3716 type_inits_deps_len: u32,3716 struct_defaults_deps_len: u32,
3717 func_ies_deps_len: u32,3717 func_ies_deps_len: u32,
3718 zon_file_deps_len: u32,3718 zon_file_deps_len: u32,
3719 embed_file_deps_len: u32,3719 embed_file_deps_len: u32,
...@@ -3763,7 +3763,7 @@ pub fn saveState(comp: *Compilation) !void {...@@ -3763,7 +3763,7 @@ pub fn saveState(comp: *Compilation) !void {
3763 .nav_val_deps_len = @intCast(ip.nav_val_deps.count()),3763 .nav_val_deps_len = @intCast(ip.nav_val_deps.count()),
3764 .nav_ty_deps_len = @intCast(ip.nav_ty_deps.count()),3764 .nav_ty_deps_len = @intCast(ip.nav_ty_deps.count()),
3765 .type_layout_deps_len = @intCast(ip.type_layout_deps.count()),3765 .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()),
3767 .func_ies_deps_len = @intCast(ip.func_ies_deps.count()),3767 .func_ies_deps_len = @intCast(ip.func_ies_deps.count()),
3768 .zon_file_deps_len = @intCast(ip.zon_file_deps.count()),3768 .zon_file_deps_len = @intCast(ip.zon_file_deps.count()),
3769 .embed_file_deps_len = @intCast(ip.embed_file_deps.count()),3769 .embed_file_deps_len = @intCast(ip.embed_file_deps.count()),
...@@ -3800,8 +3800,8 @@ pub fn saveState(comp: *Compilation) !void {...@@ -3800,8 +3800,8 @@ pub fn saveState(comp: *Compilation) !void {
3800 addBuf(&bufs, @ptrCast(ip.nav_ty_deps.values()));3800 addBuf(&bufs, @ptrCast(ip.nav_ty_deps.values()));
3801 addBuf(&bufs, @ptrCast(ip.type_layout_deps.keys()));3801 addBuf(&bufs, @ptrCast(ip.type_layout_deps.keys()));
3802 addBuf(&bufs, @ptrCast(ip.type_layout_deps.values()));3802 addBuf(&bufs, @ptrCast(ip.type_layout_deps.values()));
3803 addBuf(&bufs, @ptrCast(ip.type_inits_deps.keys()));3803 addBuf(&bufs, @ptrCast(ip.struct_defaults_deps.keys()));
3804 addBuf(&bufs, @ptrCast(ip.type_inits_deps.values()));3804 addBuf(&bufs, @ptrCast(ip.struct_defaults_deps.values()));
3805 addBuf(&bufs, @ptrCast(ip.func_ies_deps.keys()));3805 addBuf(&bufs, @ptrCast(ip.func_ies_deps.keys()));
3806 addBuf(&bufs, @ptrCast(ip.func_ies_deps.values()));3806 addBuf(&bufs, @ptrCast(ip.func_ies_deps.values()));
3807 addBuf(&bufs, @ptrCast(ip.zon_file_deps.keys()));3807 addBuf(&bufs, @ptrCast(ip.zon_file_deps.keys()));
...@@ -4481,7 +4481,7 @@ pub fn addModuleErrorMsg(...@@ -4481,7 +4481,7 @@ pub fn addModuleErrorMsg(
4481 const root_name: ?[]const u8 = switch (ref.referencer.unwrap()) {4481 const root_name: ?[]const u8 = switch (ref.referencer.unwrap()) {
4482 .@"comptime" => "comptime",4482 .@"comptime" => "comptime",
4483 .nav_val, .nav_ty => |nav| ip.getNav(nav).name.toSlice(ip),4483 .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),
4485 .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),4485 .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),
4486 .memoized_state => null,4486 .memoized_state => null,
4487 };4487 };
...@@ -5251,7 +5251,7 @@ fn processOneJob(tid: Zcu.PerThread.Id, comp: *Compilation, job: Job) JobError!v...@@ -5251,7 +5251,7 @@ fn processOneJob(tid: Zcu.PerThread.Id, comp: *Compilation, job: Job) JobError!v
5251 .nav_ty => |nav| pt.ensureNavTypeUpToDate(nav),5251 .nav_ty => |nav| pt.ensureNavTypeUpToDate(nav),
5252 .nav_val => |nav| pt.ensureNavValUpToDate(nav),5252 .nav_val => |nav| pt.ensureNavValUpToDate(nav),
5253 .type_layout => |ty| pt.ensureTypeLayoutUpToDate(.fromInterned(ty)),5253 .type_layout => |ty| pt.ensureTypeLayoutUpToDate(.fromInterned(ty)),
5254 .type_inits => |ty| pt.ensureTypeInitsUpToDate(.fromInterned(ty)),5254 .struct_defaults => |ty| pt.ensureStructDefaultsUpToDate(.fromInterned(ty)),
5255 .memoized_state => |stage| pt.ensureMemoizedStateUpToDate(stage),5255 .memoized_state => |stage| pt.ensureMemoizedStateUpToDate(stage),
5256 .func => |func| pt.ensureFuncBodyUpToDate(func),5256 .func => |func| pt.ensureFuncBodyUpToDate(func),
5257 };5257 };
src/IncrementalDebugServer.zig+3-3
...@@ -307,7 +307,7 @@ fn handleCommand(zcu: *Zcu, w: *Io.Writer, cmd_str: []const u8, arg_str: []const...@@ -307,7 +307,7 @@ fn handleCommand(zcu: *Zcu, w: *Io.Writer, cmd_str: []const u8, arg_str: []const
307 switch (dependee) {307 switch (dependee) {
308 .src_hash, .namespace, .namespace_name, .zon_file, .embed_file => try w.print("{f}", .{zcu.fmtDependee(dependee)}),308 .src_hash, .namespace, .namespace_name, .zon_file, .embed_file => try w.print("{f}", .{zcu.fmtDependee(dependee)}),
309 .nav_val, .nav_ty => |nav| try w.print("{t} {d}", .{ dependee, @intFromEnum(nav) }),309 .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) }),
311 .memoized_state => |stage| try w.print("memoized_state {s}", .{@tagName(stage)}),311 .memoized_state => |stage| try w.print("memoized_state {s}", .{@tagName(stage)}),
312 }312 }
313 try w.writeByte('\n');313 try w.writeByte('\n');
...@@ -374,8 +374,8 @@ fn parseAnalUnit(str: []const u8) ?AnalUnit {...@@ -374,8 +374,8 @@ fn parseAnalUnit(str: []const u8) ?AnalUnit {
374 return .wrap(.{ .nav_ty = @enumFromInt(parseIndex(idx_str) orelse return null) });374 return .wrap(.{ .nav_ty = @enumFromInt(parseIndex(idx_str) orelse return null) });
375 } else if (std.mem.eql(u8, kind, "type_layout")) {375 } else if (std.mem.eql(u8, kind, "type_layout")) {
376 return .wrap(.{ .type_layout = @enumFromInt(parseIndex(idx_str) orelse return null) });376 return .wrap(.{ .type_layout = @enumFromInt(parseIndex(idx_str) orelse return null) });
377 } else if (std.mem.eql(u8, kind, "type_inits")) {377 } else if (std.mem.eql(u8, kind, "struct_defaults")) {
378 return .wrap(.{ .type_inits = @enumFromInt(parseIndex(idx_str) orelse return null) });378 return .wrap(.{ .struct_defaults = @enumFromInt(parseIndex(idx_str) orelse return null) });
379 } else if (std.mem.eql(u8, kind, "func")) {379 } else if (std.mem.eql(u8, kind, "func")) {
380 return .wrap(.{ .func = @enumFromInt(parseIndex(idx_str) orelse return null) });380 return .wrap(.{ .func = @enumFromInt(parseIndex(idx_str) orelse return null) });
381 } else if (std.mem.eql(u8, kind, "memoized_state")) {381 } 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),...@@ -50,12 +50,12 @@ nav_ty_deps: std.AutoArrayHashMapUnmanaged(Nav.Index, DepEntry.Index),
50/// Dependencies on a function's inferred error set. Key is the function body, not the IES.50/// Dependencies on a function's inferred error set. Key is the function body, not the IES.
51/// Value is index into `dep_entries` of the first dependency on this function's IES.51/// Value is index into `dep_entries` of the first dependency on this function's IES.
52func_ies_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index),52func_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.
54/// Value is index into `dep_entries` of the first dependency on this type's layout.54/// Value is index into `dep_entries` of the first dependency on this type's layout.
55type_layout_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index),55type_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.
57/// Value is index into `dep_entries` of the first dependency on this type's inits.57/// 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),
59/// Dependencies on a ZON file. Triggered by `@import` of ZON.59/// Dependencies on a ZON file. Triggered by `@import` of ZON.
60/// Value is index into `dep_entries` of the first dependency on this ZON file.60/// Value is index into `dep_entries` of the first dependency on this ZON file.
61zon_file_deps: std.AutoArrayHashMapUnmanaged(FileIndex, DepEntry.Index),61zon_file_deps: std.AutoArrayHashMapUnmanaged(FileIndex, DepEntry.Index),
...@@ -110,7 +110,7 @@ pub const empty: InternPool = .{...@@ -110,7 +110,7 @@ pub const empty: InternPool = .{
110 .nav_ty_deps = .empty,110 .nav_ty_deps = .empty,
111 .func_ies_deps = .empty,111 .func_ies_deps = .empty,
112 .type_layout_deps = .empty,112 .type_layout_deps = .empty,
113 .type_inits_deps = .empty,113 .struct_defaults_deps = .empty,
114 .zon_file_deps = .empty,114 .zon_file_deps = .empty,
115 .embed_file_deps = .empty,115 .embed_file_deps = .empty,
116 .namespace_deps = .empty,116 .namespace_deps = .empty,
...@@ -422,7 +422,7 @@ pub const AnalUnit = packed struct(u64) {...@@ -422,7 +422,7 @@ pub const AnalUnit = packed struct(u64) {
422 nav_val,422 nav_val,
423 nav_ty,423 nav_ty,
424 type_layout,424 type_layout,
425 type_inits,425 struct_defaults,
426 func,426 func,
427 memoized_state,427 memoized_state,
428 };428 };
...@@ -434,11 +434,10 @@ pub const AnalUnit = packed struct(u64) {...@@ -434,11 +434,10 @@ pub const AnalUnit = packed struct(u64) {
434 nav_val: Nav.Index,434 nav_val: Nav.Index,
435 /// This `AnalUnit` resolves the type of the given `Nav`.435 /// This `AnalUnit` resolves the type of the given `Nav`.
436 nav_ty: Nav.Index,436 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.
438 type_layout: InternPool.Index,438 type_layout: InternPool.Index,
439 /// This `AnalUnit` resolves the field inits of the given `struct` or `enum` type.439 /// This `AnalUnit` resolves the default field values of the given `struct` type.
440 /// The type may be a union's auto-generated tag enum, if the union has explicit field values.440 struct_defaults: InternPool.Index,
441 type_inits: InternPool.Index,
442 /// This `AnalUnit` analyzes the body of the given runtime function.441 /// This `AnalUnit` analyzes the body of the given runtime function.
443 func: InternPool.Index,442 func: InternPool.Index,
444 /// This `AnalUnit` resolves all state which is memoized in fields on `Zcu`.443 /// This `AnalUnit` resolves all state which is memoized in fields on `Zcu`.
...@@ -852,7 +851,7 @@ pub const Dependee = union(enum) {...@@ -852,7 +851,7 @@ pub const Dependee = union(enum) {
852 /// Index is the function, not its IES.851 /// Index is the function, not its IES.
853 func_ies: Index,852 func_ies: Index,
854 type_layout: Index,853 type_layout: Index,
855 type_inits: Index,854 struct_defaults: Index,
856 zon_file: FileIndex,855 zon_file: FileIndex,
857 embed_file: Zcu.EmbedFile.Index,856 embed_file: Zcu.EmbedFile.Index,
858 namespace: TrackedInst.Index,857 namespace: TrackedInst.Index,
...@@ -906,7 +905,7 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI...@@ -906,7 +905,7 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI
906 .nav_ty => |x| ip.nav_ty_deps.get(x),905 .nav_ty => |x| ip.nav_ty_deps.get(x),
907 .func_ies => |x| ip.func_ies_deps.get(x),906 .func_ies => |x| ip.func_ies_deps.get(x),
908 .type_layout => |x| ip.type_layout_deps.get(x),907 .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),
910 .zon_file => |x| ip.zon_file_deps.get(x),909 .zon_file => |x| ip.zon_file_deps.get(x),
911 .embed_file => |x| ip.embed_file_deps.get(x),910 .embed_file => |x| ip.embed_file_deps.get(x),
912 .namespace => |x| ip.namespace_deps.get(x),911 .namespace => |x| ip.namespace_deps.get(x),
...@@ -981,7 +980,7 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend...@@ -981,7 +980,7 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend
981 .nav_ty => ip.nav_ty_deps,980 .nav_ty => ip.nav_ty_deps,
982 .func_ies => ip.func_ies_deps,981 .func_ies => ip.func_ies_deps,
983 .type_layout => ip.type_layout_deps,982 .type_layout => ip.type_layout_deps,
984 .type_inits => ip.type_inits_deps,983 .struct_defaults => ip.struct_defaults_deps,
985 .zon_file => ip.zon_file_deps,984 .zon_file => ip.zon_file_deps,
986 .embed_file => ip.embed_file_deps,985 .embed_file => ip.embed_file_deps,
987 .namespace => ip.namespace_deps,986 .namespace => ip.namespace_deps,
...@@ -2248,10 +2247,6 @@ pub const Key = union(enum) {...@@ -2248,10 +2247,6 @@ pub const Key = union(enum) {
2248 pub const Declared = struct {2247 pub const Declared = struct {
2249 /// A `struct_decl`, `union_decl`, `enum_decl`, or `opaque_decl` instruction.2248 /// A `struct_decl`, `union_decl`, `enum_decl`, or `opaque_decl` instruction.
2250 zir_index: TrackedInst.Index,2249 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,
2255 /// The captured values of this type. These values must be fully resolved per the language spec.2250 /// The captured values of this type. These values must be fully resolved per the language spec.
2256 captures: union(enum) {2251 captures: union(enum) {
2257 owned: CaptureValue.Slice,2252 owned: CaptureValue.Slice,
...@@ -2745,7 +2740,6 @@ pub const Key = union(enum) {...@@ -2745,7 +2740,6 @@ pub const Key = union(enum) {
2745 switch (namespace_type) {2740 switch (namespace_type) {
2746 .declared => |declared| {2741 .declared => |declared| {
2747 std.hash.autoHash(&hasher, declared.zir_index);2742 std.hash.autoHash(&hasher, declared.zir_index);
2748 std.hash.autoHash(&hasher, declared.arg_ty);
2749 const captures = switch (declared.captures) {2743 const captures = switch (declared.captures) {
2750 .owned => |cvs| cvs.get(ip),2744 .owned => |cvs| cvs.get(ip),
2751 .external => |cvs| cvs,2745 .external => |cvs| cvs,
...@@ -3155,7 +3149,6 @@ pub const Key = union(enum) {...@@ -3155,7 +3149,6 @@ pub const Key = union(enum) {
3155 .declared => |a_d| {3149 .declared => |a_d| {
3156 const b_d = b_info.declared;3150 const b_d = b_info.declared;
3157 if (a_d.zir_index != b_d.zir_index) return false;3151 if (a_d.zir_index != b_d.zir_index) return false;
3158 if (a_d.arg_ty != b_d.arg_ty) return false;
3159 const a_captures = switch (a_d.captures) {3152 const a_captures = switch (a_d.captures) {
3160 .owned => |s| s.get(ip),3153 .owned => |s| s.get(ip),
3161 .external => |cvs| cvs,3154 .external => |cvs| cvs,
...@@ -3295,7 +3288,6 @@ pub const Key = union(enum) {...@@ -3295,7 +3288,6 @@ pub const Key = union(enum) {
3295 .void => .void_type,3288 .void => .void_type,
3296 .null => .null_type,3289 .null => .null_type,
3297 .false, .true => .bool_type,3290 .false, .true => .bool_type,
3298 .empty_tuple => .empty_tuple_type,
3299 .@"unreachable" => .noreturn_type,3291 .@"unreachable" => .noreturn_type,
3300 },3292 },
33013293
...@@ -3308,6 +3300,7 @@ pub const LoadedStructType = struct {...@@ -3308,6 +3300,7 @@ pub const LoadedStructType = struct {
3308 /// Index of the `struct_decl` or `reify` ZIR instruction.3300 /// Index of the `struct_decl` or `reify` ZIR instruction.
3309 zir_index: TrackedInst.Index,3301 zir_index: TrackedInst.Index,
3310 captures: CaptureValue.Slice,3302 captures: CaptureValue.Slice,
3303 is_reified: bool,
33113304
3312 // TODO: the non-fqn will be needed by the new dwarf structure3305 // TODO: the non-fqn will be needed by the new dwarf structure
3313 /// The name of this struct type.3306 /// The name of this struct type.
...@@ -3319,10 +3312,9 @@ pub const LoadedStructType = struct {...@@ -3319,10 +3312,9 @@ pub const LoadedStructType = struct {
33193312
3320 layout: std.builtin.Type.ContainerLayout,3313 layout: std.builtin.Type.ContainerLayout,
3321 /// May be `undefined` if `layout != .@"packed"`.3314 /// May be `undefined` if `layout != .@"packed"`.
3322 packed_backing_mode: PackedBackingMode,3315 packed_backing_mode: BackingTypeMode,
3323 /// May be `undefined` if `layout != .@"packed",
3324 packed_backing_int_type: Index,
33253316
3317 // The remaining fields are only valid once the struct's layout is resolved.
3326 field_name_map: MapIndex,3318 field_name_map: MapIndex,
3327 field_names: NullTerminatedString.Slice,3319 field_names: NullTerminatedString.Slice,
3328 field_types: Index.Slice,3320 field_types: Index.Slice,
...@@ -3331,11 +3323,11 @@ pub const LoadedStructType = struct {...@@ -3331,11 +3323,11 @@ pub const LoadedStructType = struct {
3331 field_is_comptime_bits: ComptimeBits,3323 field_is_comptime_bits: ComptimeBits,
3332 field_runtime_order: RuntimeOrder.Slice,3324 field_runtime_order: RuntimeOrder.Slice,
3333 field_offsets: Offsets,3325 field_offsets: Offsets,
33343326 packed_backing_int_type: Index,
3335 // These fields are only valid once the layout is resolved, and are never valid for `layout == .@"packed"`.
3336 has_no_possible_value: bool,3327 has_no_possible_value: bool,
3337 has_one_possible_value: bool,3328 has_one_possible_value: bool,
3338 comptime_only: bool,3329 comptime_only: bool,
3330 has_runtime_bits: bool,
3339 size: u32,3331 size: u32,
3340 alignment: Alignment,3332 alignment: Alignment,
33413333
...@@ -3478,6 +3470,7 @@ pub const LoadedUnionType = struct {...@@ -3478,6 +3470,7 @@ pub const LoadedUnionType = struct {
3478 /// Index of the `union_decl` or `reify` ZIR instruction.3470 /// Index of the `union_decl` or `reify` ZIR instruction.
3479 zir_index: TrackedInst.Index,3471 zir_index: TrackedInst.Index,
3480 captures: CaptureValue.Slice,3472 captures: CaptureValue.Slice,
3473 is_reified: bool,
34813474
3482 // TODO: the non-fqn will be needed by the new dwarf structure3475 // TODO: the non-fqn will be needed by the new dwarf structure
3483 /// The name of this union type.3476 /// The name of this union type.
...@@ -3488,23 +3481,26 @@ pub const LoadedUnionType = struct {...@@ -3488,23 +3481,26 @@ pub const LoadedUnionType = struct {
3488 namespace: NamespaceIndex,3481 namespace: NamespaceIndex,
34893482
3490 layout: std.builtin.Type.ContainerLayout,3483 layout: std.builtin.Type.ContainerLayout,
3491 runtime_tag: RuntimeTag,3484 enum_tag_mode: BackingTypeMode,
3492 /// Even if `runtime_tag == .none`, this is populated with the union's "hypothetical" tag type.
3493 enum_tag_type: Index,
3494 /// May be `undefined` if `layout != .@"packed"`.3485 /// May be `undefined` if `layout != .@"packed"`.
3495 packed_backing_mode: PackedBackingMode,3486 packed_backing_mode: BackingTypeMode,
3496 /// May be `undefined` if `layout != .@"packed",3487
3497 packed_backing_int_type: Index,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 the3493 // The remaining fields are only valid once the union's layout is resolved.
3500 // fields of the enum tag type. If you need field names, load them from `enum_tag_type`.
3501 field_types: Index.Slice,3494 field_types: Index.Slice,
3502 field_aligns: Alignment.Slice,3495 field_aligns: Alignment.Slice,
35033496 runtime_tag: RuntimeTag,
3504 // These fields are only valid once the layout is resolved, and are never valid for `layout == .@"packed"`.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,
3505 has_no_possible_value: bool,3500 has_no_possible_value: bool,
3506 has_one_possible_value: bool,3501 has_one_possible_value: bool,
3507 comptime_only: bool,3502 comptime_only: bool,
3503 has_runtime_bits: bool,
3508 size: u32,3504 size: u32,
3509 padding: u32,3505 padding: u32,
3510 alignment: Alignment,3506 alignment: Alignment,
...@@ -3523,6 +3519,7 @@ pub const LoadedEnumType = struct {...@@ -3523,6 +3519,7 @@ pub const LoadedEnumType = struct {
3523 captures: CaptureValue.Slice,3519 captures: CaptureValue.Slice,
3524 /// If `zir_index` is `.none`, this is the union type for which this enum is the tag type.3520 /// If `zir_index` is `.none`, this is the union type for which this enum is the tag type.
3525 owner_union: Index,3521 owner_union: Index,
3522 is_reified: bool,
35263523
3527 // TODO: the non-fqn will be needed by the new dwarf structure3524 // TODO: the non-fqn will be needed by the new dwarf structure
3528 /// The name of this enum type.3525 /// The name of this enum type.
...@@ -3532,19 +3529,14 @@ pub const LoadedEnumType = struct {...@@ -3532,19 +3529,14 @@ pub const LoadedEnumType = struct {
3532 name_nav: Nav.Index.Optional,3529 name_nav: Nav.Index.Optional,
3533 namespace: NamespaceIndex,3530 namespace: NamespaceIndex,
35343531
3535 /// An integer type which is used for the numerical value of the enum. Populated immediately, regardless3532 int_tag_mode: BackingTypeMode,
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,
3539 nonexhaustive: bool,3533 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,
3542 field_name_map: MapIndex,3537 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,
3546 field_names: NullTerminatedString.Slice,3538 field_names: NullTerminatedString.Slice,
3547 /// Empty if `field_value_map` is `.none`.3539 field_value_map: OptionalMapIndex,
3548 field_values: Index.Slice,3540 field_values: Index.Slice,
35493541
3550 /// Look up field index based on field name.3542 /// Look up field index based on field name.
...@@ -3596,7 +3588,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {...@@ -3596,7 +3588,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
3596 const extra_items = extra_list.view().items(.@"0");3588 const extra_items = extra_list.view().items(.@"0");
3597 const item = unwrapped_index.getItem(ip);3589 const item = unwrapped_index.getItem(ip);
3598 // Exiting this `switch` means this is a `packed struct`.3590 // 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) {
3600 .type_struct_packed_auto => .{ .auto, false },3592 .type_struct_packed_auto => .{ .auto, false },
3601 .type_struct_packed_explicit => .{ .explicit, false },3593 .type_struct_packed_explicit => .{ .explicit, false },
3602 .type_struct_packed_auto_defaults => .{ .auto, true },3594 .type_struct_packed_auto_defaults => .{ .auto, true },
...@@ -3667,6 +3659,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {...@@ -3667,6 +3659,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
3667 return .{3659 return .{
3668 .zir_index = extra.data.zir_index,3660 .zir_index = extra.data.zir_index,
3669 .captures = captures,3661 .captures = captures,
3662 .is_reified = extra.data.flags.any_captures == .reified,
3670 .name = extra.data.name,3663 .name = extra.data.name,
3671 .name_nav = extra.data.name_nav,3664 .name_nav = extra.data.name_nav,
3672 .namespace = extra.data.namespace,3665 .namespace = extra.data.namespace,
...@@ -3675,7 +3668,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {...@@ -3675,7 +3668,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
3675 .@"extern" => .@"extern",3668 .@"extern" => .@"extern",
3676 },3669 },
3677 .packed_backing_mode = undefined,3670 .packed_backing_mode = undefined,
3678 .packed_backing_int_type = undefined,3671
3679 .field_name_map = extra.data.field_name_map,3672 .field_name_map = extra.data.field_name_map,
3680 .field_names = field_names,3673 .field_names = field_names,
3681 .field_types = field_types,3674 .field_types = field_types,
...@@ -3684,9 +3677,11 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {...@@ -3684,9 +3677,11 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
3684 .field_is_comptime_bits = field_is_comptime_bits,3677 .field_is_comptime_bits = field_is_comptime_bits,
3685 .field_runtime_order = field_runtime_order,3678 .field_runtime_order = field_runtime_order,
3686 .field_offsets = field_offsets,3679 .field_offsets = field_offsets,
3680 .packed_backing_int_type = .none,
3687 .has_no_possible_value = extra.data.flags.has_no_possible_value,3681 .has_no_possible_value = extra.data.flags.has_no_possible_value,
3688 .has_one_possible_value = extra.data.flags.has_one_possible_value,3682 .has_one_possible_value = extra.data.flags.has_one_possible_value,
3689 .comptime_only = extra.data.flags.comptime_only,3683 .comptime_only = extra.data.flags.comptime_only,
3684 .has_runtime_bits = extra.data.flags.has_runtime_bits,
3690 .size = extra.data.size,3685 .size = extra.data.size,
3691 .alignment = extra.data.flags.alignment,3686 .alignment = extra.data.flags.alignment,
3692 };3687 };
...@@ -3728,12 +3723,13 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {...@@ -3728,12 +3723,13 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
3728 return .{3723 return .{
3729 .zir_index = extra.data.zir_index,3724 .zir_index = extra.data.zir_index,
3730 .captures = captures,3725 .captures = captures,
3726 .is_reified = extra.data.captures_len == .reified,
3731 .name = extra.data.name,3727 .name = extra.data.name,
3732 .name_nav = extra.data.name_nav,3728 .name_nav = extra.data.name_nav,
3733 .namespace = extra.data.namespace,3729 .namespace = extra.data.namespace,
3734 .layout = .@"packed",3730 .layout = .@"packed",
3735 .packed_backing_mode = backing_mode,3731 .packed_backing_mode = backing_mode,
3736 .packed_backing_int_type = extra.data.backing_int_type,3732
3737 .field_name_map = extra.data.field_name_map,3733 .field_name_map = extra.data.field_name_map,
3738 .field_names = field_names,3734 .field_names = field_names,
3739 .field_types = field_types,3735 .field_types = field_types,
...@@ -3742,9 +3738,11 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {...@@ -3742,9 +3738,11 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
3742 .field_is_comptime_bits = .empty,3738 .field_is_comptime_bits = .empty,
3743 .field_runtime_order = .empty,3739 .field_runtime_order = .empty,
3744 .field_offsets = .empty,3740 .field_offsets = .empty,
3741 .packed_backing_int_type = extra.data.backing_int_type,
3745 .has_no_possible_value = undefined,3742 .has_no_possible_value = undefined,
3746 .has_one_possible_value = undefined,3743 .has_one_possible_value = undefined,
3747 .comptime_only = undefined,3744 .comptime_only = undefined,
3745 .has_runtime_bits = undefined,
3748 .size = undefined,3746 .size = undefined,
3749 .alignment = undefined,3747 .alignment = undefined,
3750 };3748 };
...@@ -3756,7 +3754,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {...@@ -3756,7 +3754,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
3756 const extra_items = extra_list.view().items(.@"0");3754 const extra_items = extra_list.view().items(.@"0");
3757 const item = unwrapped_index.getItem(ip);3755 const item = unwrapped_index.getItem(ip);
3758 // Exiting this `switch` means this is a `packed union`.3756 // 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) {
3760 .type_union_packed_auto => .auto,3758 .type_union_packed_auto => .auto,
3761 .type_union_packed_explicit => .explicit,3759 .type_union_packed_explicit => .explicit,
3762 .type_union => {3760 .type_union => {
...@@ -3779,6 +3777,12 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {...@@ -3779,6 +3777,12 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
3779 },3777 },
3780 };3778 };
3781 extra_index += captures.len;3779 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;
3782 const field_types: Index.Slice = .{3786 const field_types: Index.Slice = .{
3783 .tid = unwrapped_index.tid,3787 .tid = unwrapped_index.tid,
3784 .start = extra_index,3788 .start = extra_index,
...@@ -3795,6 +3799,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {...@@ -3795,6 +3799,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
3795 return .{3799 return .{
3796 .zir_index = extra.data.zir_index,3800 .zir_index = extra.data.zir_index,
3797 .captures = captures,3801 .captures = captures,
3802 .is_reified = extra.data.flags.any_captures == .reified,
3798 .name = extra.data.name,3803 .name = extra.data.name,
3799 .name_nav = extra.data.name_nav,3804 .name_nav = extra.data.name_nav,
3800 .namespace = extra.data.namespace,3805 .namespace = extra.data.namespace,
...@@ -3803,14 +3808,17 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {...@@ -3803,14 +3808,17 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
3803 .@"extern" => .@"extern",3808 .@"extern" => .@"extern",
3804 },3809 },
3805 .runtime_tag = extra.data.flags.runtime_tag,3810 .runtime_tag = extra.data.flags.runtime_tag,
3811 .enum_tag_mode = extra.data.flags.enum_tag_mode,
3806 .enum_tag_type = extra.data.enum_tag_type,3812 .enum_tag_type = extra.data.enum_tag_type,
3807 .packed_backing_mode = undefined,3813 .packed_backing_mode = undefined,
3808 .packed_backing_int_type = undefined,3814 .packed_backing_int_type = undefined,
3815 .reified_field_names = reified_field_names,
3809 .field_types = field_types,3816 .field_types = field_types,
3810 .field_aligns = field_aligns,3817 .field_aligns = field_aligns,
3811 .has_no_possible_value = extra.data.flags.has_no_possible_value,3818 .has_no_possible_value = extra.data.flags.has_no_possible_value,
3812 .has_one_possible_value = extra.data.flags.has_one_possible_value,3819 .has_one_possible_value = extra.data.flags.has_one_possible_value,
3813 .comptime_only = extra.data.flags.comptime_only,3820 .comptime_only = extra.data.flags.comptime_only,
3821 .has_runtime_bits = extra.data.flags.has_runtime_bits,
3814 .size = extra.data.size,3822 .size = extra.data.size,
3815 .padding = extra.data.padding,3823 .padding = extra.data.padding,
3816 .alignment = extra.data.flags.alignment,3824 .alignment = extra.data.flags.alignment,
...@@ -3832,6 +3840,12 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {...@@ -3832,6 +3840,12 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
3832 },3840 },
3833 };3841 };
3834 extra_index += captures.len;3842 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;
3835 const field_types: Index.Slice = .{3849 const field_types: Index.Slice = .{
3836 .tid = unwrapped_index.tid,3850 .tid = unwrapped_index.tid,
3837 .start = extra_index,3851 .start = extra_index,
...@@ -3841,19 +3855,23 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {...@@ -3841,19 +3855,23 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
3841 return .{3855 return .{
3842 .zir_index = extra.data.zir_index,3856 .zir_index = extra.data.zir_index,
3843 .captures = captures,3857 .captures = captures,
3858 .is_reified = extra.data.captures_len == .reified,
3844 .name = extra.data.name,3859 .name = extra.data.name,
3845 .name_nav = extra.data.name_nav,3860 .name_nav = extra.data.name_nav,
3846 .namespace = extra.data.namespace,3861 .namespace = extra.data.namespace,
3847 .layout = .@"packed",3862 .layout = .@"packed",
3848 .runtime_tag = .none,3863 .runtime_tag = .none,
3864 .enum_tag_mode = .auto,
3849 .enum_tag_type = extra.data.enum_tag_type,3865 .enum_tag_type = extra.data.enum_tag_type,
3850 .packed_backing_mode = backing_mode,3866 .packed_backing_mode = backing_mode,
3851 .packed_backing_int_type = extra.data.backing_int_type,3867 .packed_backing_int_type = extra.data.backing_int_type,
3868 .reified_field_names = reified_field_names,
3852 .field_types = field_types,3869 .field_types = field_types,
3853 .field_aligns = .empty,3870 .field_aligns = .empty,
3854 .has_no_possible_value = undefined,3871 .has_no_possible_value = undefined,
3855 .has_one_possible_value = undefined,3872 .has_one_possible_value = undefined,
3856 .comptime_only = undefined,3873 .comptime_only = undefined,
3874 .has_runtime_bits = undefined,
3857 .size = undefined,3875 .size = undefined,
3858 .padding = undefined,3876 .padding = undefined,
3859 .alignment = undefined,3877 .alignment = undefined,
...@@ -3917,12 +3935,13 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType {...@@ -3917,12 +3935,13 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType {
3917 return .{3935 return .{
3918 .zir_index = zir_index,3936 .zir_index = zir_index,
3919 .captures = captures,3937 .captures = captures,
3938 .is_reified = extra.data.captures_len == .reified,
3920 .owner_union = owner_union,3939 .owner_union = owner_union,
3921 .name = extra.data.name,3940 .name = extra.data.name,
3922 .name_nav = extra.data.name_nav,3941 .name_nav = extra.data.name_nav,
3923 .namespace = extra.data.namespace,3942 .namespace = extra.data.namespace,
3924 .int_tag_type = extra.data.int_tag_type,3943 .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,
3926 .nonexhaustive = nonexhaustive,3945 .nonexhaustive = nonexhaustive,
3927 .field_name_map = extra.data.field_name_map,3946 .field_name_map = extra.data.field_name_map,
3928 .field_value_map = field_value_map,3947 .field_value_map = field_value_map,
...@@ -4160,7 +4179,7 @@ pub const Index = enum(u32) {...@@ -4160,7 +4179,7 @@ pub const Index = enum(u32) {
4160 };4179 };
41614180
4162 /// Used for a map of `Index` values to the index within a list of `Index` values.4181 /// 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 {
4164 indexes: []const Index,4183 indexes: []const Index,
41654184
4166 pub fn eql(ctx: @This(), a: Index, b_void: void, b_map_index: usize) bool {4185 pub fn eql(ctx: @This(), a: Index, b_void: void, b_map_index: usize) bool {
...@@ -4365,7 +4384,7 @@ pub const Index = enum(u32) {...@@ -4365,7 +4384,7 @@ pub const Index = enum(u32) {
4365 }) void {4384 }) void {
4366 _ = self;4385 _ = self;
4367 const map_fields = @typeInfo(@typeInfo(@TypeOf(tag_to_encoding_map)).pointer.child).@"struct".fields;4386 const map_fields = @typeInfo(@typeInfo(@TypeOf(tag_to_encoding_map)).pointer.child).@"struct".fields;
4368 @setEvalBranchQuota(2_000);4387 @setEvalBranchQuota(3_000);
4369 inline for (@typeInfo(Tag).@"enum".fields, 0..) |tag, start| {4388 inline for (@typeInfo(Tag).@"enum".fields, 0..) |tag, start| {
4370 inline for (0..map_fields.len) |offset| {4389 inline for (0..map_fields.len) |offset| {
4371 if (comptime std.mem.eql(u8, tag.name, map_fields[(start + offset) % map_fields.len].name)) break;4390 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 = .{...@@ -4797,7 +4816,11 @@ pub const static_keys: [static_len]Key = .{
4797 .{ .simple_value = .null },4816 .{ .simple_value = .null },
4798 .{ .simple_value = .true },4817 .{ .simple_value = .true },
4799 .{ .simple_value = .false },4818 .{ .simple_value = .false },
4800 .{ .simple_value = .empty_tuple },4819
4820 .{ .aggregate = .{
4821 .ty = .empty_tuple_type,
4822 .storage = .{ .elems = &.{} },
4823 } },
4801};4824};
48024825
4803/// How many items in the InternPool are statically known.4826/// How many items in the InternPool are statically known.
...@@ -5601,10 +5624,12 @@ pub const Tag = enum(u8) {...@@ -5601,10 +5624,12 @@ pub const Tag = enum(u8) {
5601 has_no_possible_value: bool,5624 has_no_possible_value: bool,
5602 /// Whether the struct is comptime-only. Always `false` until layout resolved.5625 /// Whether the struct is comptime-only. Always `false` until layout resolved.
5603 comptime_only: bool,5626 comptime_only: bool,
5627 /// Whether the struct has runtime bits. Always `false` until layout resolved.
5628 has_runtime_bits: bool,
5604 /// Alignment of the whole struct. Always `.none` until layout resolved.5629 /// Alignment of the whole struct. Always `.none` until layout resolved.
5605 alignment: Alignment,5630 alignment: Alignment,
56065631
5607 _: u17 = 0,5632 _: u16 = 0,
5608 };5633 };
5609 };5634 };
56105635
...@@ -5625,21 +5650,25 @@ pub const Tag = enum(u8) {...@@ -5625,21 +5650,25 @@ pub const Tag = enum(u8) {
5625 name_nav: Nav.Index.Optional,5650 name_nav: Nav.Index.Optional,
5626 namespace: NamespaceIndex,5651 namespace: NamespaceIndex,
56275652
5628 /// The corresponding `PackedBackingMode` depends on the item's `Tag`.5653 /// The corresponding `BackingTypeMode` depends on the item's `Tag`.
5629 backing_int_type: Index,5654 backing_int_type: Index,
56305655
5631 fields_len: u32,5656 fields_len: u32,
5632 field_name_map: MapIndex,5657 field_name_map: MapIndex,
5633 };5658 };
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).
5636 ///5664 ///
5637 /// Trailing:5665 /// Trailing:
5638 /// 0. type_hash: PackedU64 // if `any_captures == .reified`5666 /// 0. type_hash: PackedU64 // if `any_captures == .reified`
5639 /// 1. captures_len: u32 // if `any_captures == .true`5667 /// 1. captures_len: u32 // if `any_captures == .true`
5640 /// 2. capture: CaptureValue // if `any_captures == .true`; for each `captures_len`5668 /// 2. capture: CaptureValue // if `any_captures == .true`; for each `captures_len`
5641 /// 3. field_type: Index // for each `fields_len`5669 /// 3. reified_field_name: NullTerminatedString // if `any_captures == .reified`; for each `fields_len`
5642 /// 4. field_align: Alignment // for each `fields_len` if `any_field_aligns`5670 /// 4. field_type: Index // for each `fields_len`
5671 /// 5. field_align: Alignment // for each `fields_len` if `any_field_aligns`
5643 pub const TypeUnion = struct {5672 pub const TypeUnion = struct {
5644 zir_index: TrackedInst.Index,5673 zir_index: TrackedInst.Index,
56455674
...@@ -5652,7 +5681,6 @@ pub const Tag = enum(u8) {...@@ -5652,7 +5681,6 @@ pub const Tag = enum(u8) {
5652 /// This could be provided through the tag type, but it is more convenient5681 /// This could be provided through the tag type, but it is more convenient
5653 /// to store it directly. This is also necessary for `dumpStatsFallible` to5682 /// to store it directly. This is also necessary for `dumpStatsFallible` to
5654 /// work on unresolved types.5683 /// work on unresolved types.
5655 /// MLUGG TODO: reconsider, because we resolve the tag type eagerly now.
5656 fields_len: u32,5684 fields_len: u32,
56575685
5658 /// Always 0 until layout resolved.5686 /// Always 0 until layout resolved.
...@@ -5669,7 +5697,7 @@ pub const Tag = enum(u8) {...@@ -5669,7 +5697,7 @@ pub const Tag = enum(u8) {
5669 ///5697 ///
5670 /// For `union(enum(E))` syntax, this is `false`, but the generated enum tag type is5698 /// For `union(enum(E))` syntax, this is `false`, but the generated enum tag type is
5671 /// considered to have an explicitly specified integer tag type.5699 /// considered to have an explicitly specified integer tag type.
5672 explicit_tag_type: bool,5700 enum_tag_mode: BackingTypeMode,
56735701
5674 /// `packed` layout is represented separately by `TypeStructPacked`.5702 /// `packed` layout is represented separately by `TypeStructPacked`.
5675 layout: enum(u1) { auto, @"extern" },5703 layout: enum(u1) { auto, @"extern" },
...@@ -5685,19 +5713,25 @@ pub const Tag = enum(u8) {...@@ -5685,19 +5713,25 @@ pub const Tag = enum(u8) {
5685 has_no_possible_value: bool,5713 has_no_possible_value: bool,
5686 /// Whether the union is comptime-only. Always `false` until layout resolved.5714 /// Whether the union is comptime-only. Always `false` until layout resolved.
5687 comptime_only: bool,5715 comptime_only: bool,
5716 /// Whether the union has runtime bits. Always `false` until layout resolved.
5717 has_runtime_bits: bool,
5688 /// Alignment of the whole union. Always `.none` until layout resolved.5718 /// Alignment of the whole union. Always `.none` until layout resolved.
5689 alignment: Alignment,5719 alignment: Alignment,
56905720
5691 _: u16 = 0,5721 _: u15 = 0,
5692 };5722 };
5693 };5723 };
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).
5696 ///5729 ///
5697 /// Trailing:5730 /// Trailing:
5698 /// 0. type_hash: PackedU64 // if `captures_len == .reified`5731 /// 0. type_hash: PackedU64 // if `captures_len == .reified`
5699 /// 1. capture: CaptureValue // if `captures_len != .reified`; for each `captures_len`5732 /// 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`
5701 pub const TypeUnionPacked = struct {5735 pub const TypeUnionPacked = struct {
5702 zir_index: TrackedInst.Index,5736 zir_index: TrackedInst.Index,
5703 captures_len: enum(u32) {5737 captures_len: enum(u32) {
...@@ -5709,7 +5743,7 @@ pub const Tag = enum(u8) {...@@ -5709,7 +5743,7 @@ pub const Tag = enum(u8) {
5709 name_nav: Nav.Index.Optional,5743 name_nav: Nav.Index.Optional,
5710 namespace: NamespaceIndex,5744 namespace: NamespaceIndex,
57115745
5712 /// The corresponding `PackedBackingMode` depends on the item's `Tag`.5746 /// The corresponding `BackingTypeMode` depends on the item's `Tag`.
5713 backing_int_type: Index,5747 backing_int_type: Index,
5714 /// Although packed unions do not semantically have a tag type, the compiler still assigns5748 /// Although packed unions do not semantically have a tag type, the compiler still assigns
5715 /// them a "hypothetical" tag type.5749 /// them a "hypothetical" tag type.
...@@ -5718,7 +5752,6 @@ pub const Tag = enum(u8) {...@@ -5718,7 +5752,6 @@ pub const Tag = enum(u8) {
5718 /// This could be provided through the tag type, but it is more convenient5752 /// This could be provided through the tag type, but it is more convenient
5719 /// to store it directly. This is also necessary for `dumpStatsFallible` to5753 /// to store it directly. This is also necessary for `dumpStatsFallible` to
5720 /// work on unresolved types.5754 /// work on unresolved types.
5721 /// MLUGG TODO: reconsider, because we resolve the tag type eagerly now.
5722 fields_len: u32,5755 fields_len: u32,
5723 };5756 };
57245757
...@@ -5742,8 +5775,7 @@ pub const Tag = enum(u8) {...@@ -5742,8 +5775,7 @@ pub const Tag = enum(u8) {
5742 namespace: NamespaceIndex,5775 namespace: NamespaceIndex,
57435776
5744 /// An integer type which is used for the numerical value of the enum. Whether this was5777 /// 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 field5778 /// user-provided or inferred by the compiler depends on the tag.
5746 /// is populated immediately (i.e. does not require any type resolution).
5747 int_tag_type: Index,5779 int_tag_type: Index,
57485780
5749 fields_len: u32,5781 fields_len: u32,
...@@ -5762,13 +5794,17 @@ pub const Tag = enum(u8) {...@@ -5762,13 +5794,17 @@ pub const Tag = enum(u8) {
5762 };5794 };
5763};5795};
57645796
5765/// Differentiates between user-provided and compiler-generated backing types for packed aggregates.5797/// Differentiates between user-provided and compiler-generated backing types for packed and tagged types.
5766pub const PackedBackingMode = enum(u1) {5798pub const BackingTypeMode = enum(u1) {
5767 /// The backing type was explicitly provided by the user, i.e. `packed struct(T)` or `packed union(T)`.5799 /// The backing type was explicitly provided by the user. For instance:
5768 /// Type resolution simply *validates* that type.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.
5769 explicit,5805 explicit,
5770 /// No backing type was explicitly provided by the user. Type layout resolution will populate the5806 /// No backing type was explicitly provided by the user. Type layout resolution will populate
5771 /// backing type based on the field types; before then it is invalid (probably `.none`).5807 /// an inferred/generated type.
5772 auto,5808 auto,
5773};5809};
57745810
...@@ -5852,8 +5888,6 @@ pub const SimpleValue = enum(u32) {...@@ -5852,8 +5888,6 @@ pub const SimpleValue = enum(u32) {
5852 void = @intFromEnum(Index.void_value),5888 void = @intFromEnum(Index.void_value),
5853 /// This is untyped `null`.5889 /// This is untyped `null`.
5854 null = @intFromEnum(Index.null_value),5890 null = @intFromEnum(Index.null_value),
5855 /// This is the untyped empty struct/array literal: `.{}`
5856 empty_tuple = @intFromEnum(Index.empty_tuple),
5857 true = @intFromEnum(Index.bool_true),5891 true = @intFromEnum(Index.bool_true),
5858 false = @intFromEnum(Index.bool_false),5892 false = @intFromEnum(Index.bool_false),
5859 @"unreachable" = @intFromEnum(Index.unreachable_value),5893 @"unreachable" = @intFromEnum(Index.unreachable_value),
...@@ -6395,7 +6429,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator, io: Io) void {...@@ -6395,7 +6429,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator, io: Io) void {
6395 ip.nav_ty_deps.deinit(gpa);6429 ip.nav_ty_deps.deinit(gpa);
6396 ip.func_ies_deps.deinit(gpa);6430 ip.func_ies_deps.deinit(gpa);
6397 ip.type_layout_deps.deinit(gpa);6431 ip.type_layout_deps.deinit(gpa);
6398 ip.type_inits_deps.deinit(gpa);6432 ip.struct_defaults_deps.deinit(gpa);
6399 ip.zon_file_deps.deinit(gpa);6433 ip.zon_file_deps.deinit(gpa);
6400 ip.embed_file_deps.deinit(gpa);6434 ip.embed_file_deps.deinit(gpa);
6401 ip.namespace_deps.deinit(gpa);6435 ip.namespace_deps.deinit(gpa);
...@@ -6544,12 +6578,10 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -6544,12 +6578,10 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
6544 } },6578 } },
6545 .false => .{ .declared = .{6579 .false => .{ .declared = .{
6546 .zir_index = extra.data.zir_index,6580 .zir_index = extra.data.zir_index,
6547 .arg_ty = .none,
6548 .captures = .{ .owned = .empty },6581 .captures = .{ .owned = .empty },
6549 } },6582 } },
6550 .true => .{ .declared = .{6583 .true => .{ .declared = .{
6551 .zir_index = extra.data.zir_index,6584 .zir_index = extra.data.zir_index,
6552 .arg_ty = .none,
6553 .captures = .{ .owned = .{6585 .captures = .{ .owned = .{
6554 .tid = unwrapped_index.tid,6586 .tid = unwrapped_index.tid,
6555 .start = extra.end + 1,6587 .start = extra.end + 1,
...@@ -6572,11 +6604,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -6572,11 +6604,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
6572 } },6604 } },
6573 _ => .{ .declared = .{6605 _ => .{ .declared = .{
6574 .zir_index = extra.data.zir_index,6606 .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 },
6580 .captures = .{ .owned = .{6607 .captures = .{ .owned = .{
6581 .tid = unwrapped_index.tid,6608 .tid = unwrapped_index.tid,
6582 .start = extra.end,6609 .start = extra.end,
...@@ -6595,12 +6622,10 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -6595,12 +6622,10 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
6595 } },6622 } },
6596 .false => .{ .declared = .{6623 .false => .{ .declared = .{
6597 .zir_index = extra.data.zir_index,6624 .zir_index = extra.data.zir_index,
6598 .arg_ty = if (extra.data.flags.explicit_tag_type) extra.data.enum_tag_type else .none,
6599 .captures = .{ .owned = .empty },6625 .captures = .{ .owned = .empty },
6600 } },6626 } },
6601 .true => .{ .declared = .{6627 .true => .{ .declared = .{
6602 .zir_index = extra.data.zir_index,6628 .zir_index = extra.data.zir_index,
6603 .arg_ty = if (extra.data.flags.explicit_tag_type) extra.data.enum_tag_type else .none,
6604 .captures = .{ .owned = .{6629 .captures = .{ .owned = .{
6605 .tid = unwrapped_index.tid,6630 .tid = unwrapped_index.tid,
6606 .start = extra.end + 1,6631 .start = extra.end + 1,
...@@ -6619,11 +6644,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -6619,11 +6644,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
6619 } },6644 } },
6620 _ => .{ .declared = .{6645 _ => .{ .declared = .{
6621 .zir_index = extra.data.zir_index,6646 .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 },
6627 .captures = .{ .owned = .{6647 .captures = .{ .owned = .{
6628 .tid = unwrapped_index.tid,6648 .tid = unwrapped_index.tid,
6629 .start = extra.end,6649 .start = extra.end,
...@@ -6645,11 +6665,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -6645,11 +6665,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
6645 } },6665 } },
6646 _ => .{ .declared = .{6666 _ => .{ .declared = .{
6647 .zir_index = @enumFromInt(extra_list.view().items(.@"0")[extra.end]),6667 .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 },
6653 .captures = .{ .owned = .{6668 .captures = .{ .owned = .{
6654 .tid = unwrapped_index.tid,6669 .tid = unwrapped_index.tid,
6655 .start = extra.end + 1,6670 .start = extra.end + 1,
...@@ -6662,7 +6677,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -6662,7 +6677,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
6662 const extra = extraDataTrail(unwrapped_index.getExtra(ip), Tag.TypeOpaque, data);6677 const extra = extraDataTrail(unwrapped_index.getExtra(ip), Tag.TypeOpaque, data);
6663 break :ns .{ .declared = .{6678 break :ns .{ .declared = .{
6664 .zir_index = extra.data.zir_index,6679 .zir_index = extra.data.zir_index,
6665 .arg_ty = .none,
6666 .captures = .{ .owned = .{6680 .captures = .{ .owned = .{
6667 .tid = unwrapped_index.tid,6681 .tid = unwrapped_index.tid,
6668 .start = extra.end,6682 .start = extra.end,
...@@ -6883,7 +6897,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -6883,7 +6897,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
6883 },6897 },
6884 .type_array_small,6898 .type_array_small,
6885 .type_vector,6899 .type_vector,
6886 // MLUGG TODO: is this still possible? also, i hate .only_possible_value, it should die in a fire.
6887 .type_struct_packed_auto,6900 .type_struct_packed_auto,
6888 .type_struct_packed_explicit,6901 .type_struct_packed_explicit,
6889 => .{ .aggregate = .{6902 => .{ .aggregate = .{
...@@ -6894,7 +6907,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -6894,7 +6907,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
6894 // There is only one possible value precisely due to the6907 // There is only one possible value precisely due to the
6895 // fact that this values slice is fully populated!6908 // fact that this values slice is fully populated!
6896 .type_struct,6909 .type_struct,
6897 // MLUGG TODO: is this still possible? also, i hate .only_possible_value, it should die in a fire.
6898 .type_struct_packed_auto_defaults,6910 .type_struct_packed_auto_defaults,
6899 .type_struct_packed_explicit_defaults,6911 .type_struct_packed_explicit_defaults,
6900 => {6912 => {
...@@ -7445,12 +7457,12 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:...@@ -7445,12 +7457,12 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
7445 });7457 });
7446 },7458 },
74477459
7448 .struct_type => unreachable, // use getStructType() instead7460 .struct_type => unreachable, // instead use: getDeclaredStructType, getReifiedStructType
7449 .tuple_type => unreachable, // use getTupleType() instead7461 .union_type => unreachable, // instead use: getDeclaredUnionType, getReifiedUnionType
7450 .union_type => unreachable, // use getUnionType() instead7462 .enum_type => unreachable, // instead use: getDeclaredEnumType, getReifiedEnumType, getGeneratedEnumTagType
7451 .opaque_type => unreachable, // use getOpaqueType() instead7463 .opaque_type => unreachable, // instead use: getDeclaredOpaqueType
74527464
7453 .enum_type => unreachable, // use getEnumType() instead7465 .tuple_type => unreachable, // use getTupleType() instead
7454 .func_type => unreachable, // use getFuncType() instead7466 .func_type => unreachable, // use getFuncType() instead
7455 .@"extern" => unreachable, // use getExtern() instead7467 .@"extern" => unreachable, // use getExtern() instead
7456 .func => unreachable, // use getFuncInstance() or getFuncDecl() instead7468 .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:...@@ -8072,43 +8084,180 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
8072 return gop.put();8084 return gop.put();
8073}8085}
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,
8076 fields_len: u32,8249 fields_len: u32,
8077 layout: std.builtin.Type.ContainerLayout,8250 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,
8083 any_comptime_fields: bool,8251 any_comptime_fields: bool,
8084 any_field_defaults: bool,8252 any_field_defaults: bool,
8085 any_field_aligns: bool,8253 any_field_aligns: bool,
8086 key: union(enum) {8254 /// Explicitly specified backing int type. `.none` if not packed or if backing type is inferred.
8087 declared: struct {8255 packed_backing_int_type: Index,
8088 zir_index: TrackedInst.Index,
8089 captures: []const CaptureValue,
8090 },
8091 reified: struct {
8092 zir_index: TrackedInst.Index,
8093 type_hash: u64,
8094 },
8095 },
8096}) Allocator.Error!WipContainerType.Result {8256}) Allocator.Error!WipContainerType.Result {
8097 const key: Key = .{ .struct_type = switch (ini.key) {8257 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .struct_type = .{ .reified = .{
8098 .declared => |d| .{ .declared = .{8258 .zir_index = ini.zir_index,
8099 .zir_index = d.zir_index,8259 .type_hash = ini.type_hash,
8100 .arg_ty = switch (ini.layout) {8260 } } });
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);
8112 defer gop.deinit();8261 defer gop.deinit();
8113 if (gop == .existing) return .{ .existing = gop.existing };8262 if (gop == .existing) return .{ .existing = gop.existing };
81148263
...@@ -8120,46 +8269,37 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread...@@ -8120,46 +8269,37 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread
8120 const field_name_map = try ip.addMap(gpa, io, tid, ini.fields_len);8269 const field_name_map = try ip.addMap(gpa, io, tid, ini.fields_len);
8121 errdefer local.mutate.maps.len -= 1;8270 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
8128 const is_extern = switch (ini.layout) {8272 const is_extern = switch (ini.layout) {
8129 .auto => false,8273 .auto => false,
8130 .@"extern" => true,8274 .@"extern" => true,
8131 .@"packed" => {8275 .@"packed" => {
8132 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStructPacked).@"struct".fields.len +8276 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStructPacked).@"struct".fields.len +
8133 type_hash_captures_extra_len +8277 2 + // type_hash
8134 ini.fields_len + // field_name8278 ini.fields_len + // field_name
8135 ini.fields_len + // field_type8279 ini.fields_len + // field_type
8136 (if (ini.any_field_defaults) ini.fields_len else 0)); // field_default8280 (if (ini.any_field_defaults) ini.fields_len else 0)); // field_default
81378281
8138 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStructPacked{8282 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStructPacked{
8139 .zir_index = zir_index,8283 .zir_index = ini.zir_index,
8140 .captures_len = switch (ini.key) {8284 .captures_len = .reified,
8141 .declared => |d| @enumFromInt(d.captures.len),
8142 .reified => .reified,
8143 },
8144 .name = undefined, // set by `finish`8285 .name = undefined, // set by `finish`
8145 .name_nav = undefined, // set by `finish`8286 .name_nav = undefined, // set by `finish`
8146 .namespace = undefined, // set by `finish`8287 .namespace = undefined, // set by `finish`
8147 .backing_int_type = ini.explicit_packed_backing_type,8288 .backing_int_type = ini.packed_backing_int_type,
8148 .fields_len = ini.fields_len,8289 .fields_len = ini.fields_len,
8149 .field_name_map = field_name_map,8290 .field_name_map = field_name_map,
8150 });8291 });
8151 switch (ini.key) {8292 _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); // type_hash
8152 .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}),
8153 .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)),
8154 }
8155 const field_names_start = extra.mutate.len;8293 const field_names_start = extra.mutate.len;
8156 extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name8294 extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name
8295 const field_types_start = extra.mutate.len;
8157 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type8296 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type
8297 const field_defaults_start = extra.mutate.len;
8158 if (ini.any_field_defaults) {8298 if (ini.any_field_defaults) {
8159 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_default8299 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_default
8160 }8300 }
8161 items.appendAssumeCapacity(.{8301 items.appendAssumeCapacity(.{
8162 .tag = switch (ini.explicit_packed_backing_type) {8302 .tag = switch (ini.packed_backing_int_type) {
8163 .none => if (ini.any_field_defaults) .type_struct_packed_auto_defaults else .type_struct_packed_auto,8303 .none => if (ini.any_field_defaults) .type_struct_packed_auto_defaults else .type_struct_packed_auto,
8164 else => if (ini.any_field_defaults) .type_struct_packed_explicit_defaults else .type_struct_packed_explicit,8304 else => if (ini.any_field_defaults) .type_struct_packed_explicit_defaults else .type_struct_packed_explicit,
8165 },8305 },
...@@ -8171,17 +8311,20 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread...@@ -8171,17 +8311,20 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread
8171 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?,8311 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?,
8172 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name_nav").?,8312 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name_nav").?,
8173 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?,8313 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?,
8174 .tag_type_index = null,8314 .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len },
8175 .fields_len = ini.fields_len,8315 .field_types = .{ .tid = tid, .start = field_types_start, .len = ini.fields_len },
8176 .field_name_map = field_name_map,8316 .field_values = if (ini.any_field_defaults)
8177 .field_names_start = field_names_start,8317 .{ .tid = tid, .start = field_defaults_start, .len = ini.fields_len }
8178 .field_comptime_bits_start = null,8318 else
8319 undefined,
8320 .field_aligns = undefined,
8321 .field_is_comptime_bits = undefined,
8179 } };8322 } };
8180 },8323 },
8181 };8324 };
81828325
8183 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStruct).@"struct".fields.len +8326 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStruct).@"struct".fields.len +
8184 type_hash_captures_extra_len +8327 2 + // type_hash
8185 ini.fields_len + // field_name8328 ini.fields_len + // field_name
8186 ini.fields_len + // field_type8329 ini.fields_len + // field_type
8187 (if (ini.any_field_defaults) ini.fields_len else 0) + // field_default8330 (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...@@ -8191,7 +8334,7 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread
8191 ini.fields_len); // field_offset8334 ini.fields_len); // field_offset
81928335
8193 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStruct{8336 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStruct{
8194 .zir_index = zir_index,8337 .zir_index = ini.zir_index,
8195 .name = undefined, // set by `finish`8338 .name = undefined, // set by `finish`
8196 .name_nav = undefined, // set by `finish`8339 .name_nav = undefined, // set by `finish`
8197 .namespace = undefined, // set by `finish`8340 .namespace = undefined, // set by `finish`
...@@ -8199,10 +8342,7 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread...@@ -8199,10 +8342,7 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread
8199 .field_name_map = field_name_map,8342 .field_name_map = field_name_map,
8200 .size = 0,8343 .size = 0,
8201 .flags = .{8344 .flags = .{
8202 .any_captures = switch (ini.key) {8345 .any_captures = .reified,
8203 .declared => |d| if (d.captures.len != 0) .true else .false,
8204 .reified => .reified,
8205 },
8206 .layout = if (is_extern) .@"extern" else .auto,8346 .layout = if (is_extern) .@"extern" else .auto,
8207 .any_comptime_fields = ini.any_comptime_fields,8347 .any_comptime_fields = ini.any_comptime_fields,
8208 .any_field_defaults = ini.any_field_defaults,8348 .any_field_defaults = ini.any_field_defaults,
...@@ -8210,30 +8350,27 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread...@@ -8210,30 +8350,27 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread
8210 .has_one_possible_value = false,8350 .has_one_possible_value = false,
8211 .has_no_possible_value = false,8351 .has_no_possible_value = false,
8212 .comptime_only = false,8352 .comptime_only = false,
8353 .has_runtime_bits = false,
8213 .alignment = .none,8354 .alignment = .none,
8214 },8355 },
8215 });8356 });
8216 switch (ini.key) {8357 _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); // type_hash
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 }
8223 const field_names_start = extra.mutate.len;8358 const field_names_start = extra.mutate.len;
8224 extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name8359 extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name
8360 const field_types_start = extra.mutate.len;
8225 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type8361 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type
8362 const field_defaults_start = extra.mutate.len;
8226 if (ini.any_field_defaults) {8363 if (ini.any_field_defaults) {
8227 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_default8364 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_default
8228 }8365 }
8366 const field_aligns_start = extra.mutate.len;
8229 if (ini.any_field_aligns) {8367 if (ini.any_field_aligns) {
8230 extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 3) / 4); // field_align8368 extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 3) / 4); // field_align
8231 }8369 }
8232 const field_comptime_bits_start: ?u32 = if (ini.any_comptime_fields) start: {8370 const field_is_comptime_bits_start = extra.mutate.len;
8233 const start = extra.mutate.len;8371 if (ini.any_comptime_fields) {
8234 extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 31) / 32); // field_is_comptime_bits8372 extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 31) / 32); // field_is_comptime_bits
8235 break :start start;8373 }
8236 } else null;
8237 if (!is_extern) {8374 if (!is_extern) {
8238 extra.appendNTimesAssumeCapacity(.{@intFromEnum(LoadedStructType.RuntimeOrder.unresolved)}, ini.fields_len); // field_runtime_order8375 extra.appendNTimesAssumeCapacity(.{@intFromEnum(LoadedStructType.RuntimeOrder.unresolved)}, ini.fields_len); // field_runtime_order
8239 }8376 }
...@@ -8248,58 +8385,174 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread...@@ -8248,58 +8385,174 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread
8248 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name").?,8385 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name").?,
8249 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name_nav").?,8386 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name_nav").?,
8250 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?,8387 .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,
8252 .fields_len = ini.fields_len,8498 .fields_len = ini.fields_len,
8253 .field_name_map = field_name_map,8499 .size = 0,
8254 .field_names_start = field_names_start,8500 .padding = 0,
8255 .field_comptime_bits_start = field_comptime_bits_start,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,
8256 } };8537 } };
8257}8538}
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,
8260 fields_len: u32,8543 fields_len: u32,
8261 layout: std.builtin.Type.ContainerLayout,8544 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,
8269 any_field_aligns: bool,8545 any_field_aligns: bool,
8270 key: union(enum) {8546 runtime_tag: LoadedUnionType.RuntimeTag,
8271 declared: struct {8547 /// Explicitly specified enum tag type. `.none` if `runtime_tag != .tagged`.
8272 zir_index: TrackedInst.Index,8548 enum_tag_type: Index,
8273 captures: []const CaptureValue,8549 /// Explicitly specified backing int type. `.none` if not packed or if backing type is inferred.
8274 /// This is the `T` in one of the following:8550 packed_backing_int_type: Index,
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 },
8286}) Allocator.Error!WipContainerType.Result {8551}) Allocator.Error!WipContainerType.Result {
8287 if (ini.explicit_packed_backing_type != .none) {8552 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .union_type = .{ .reified = .{
8288 assert(ip.zigTypeTag(ini.explicit_packed_backing_type) == .int);8553 .zir_index = ini.zir_index,
8289 if (ini.key == .declared) assert(ini.key.declared.arg_ty == ini.explicit_packed_backing_type);8554 .type_hash = ini.type_hash,
8290 }8555 } } });
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);
8303 defer gop.deinit();8556 defer gop.deinit();
8304 if (gop == .existing) return .{ .existing = gop.existing };8557 if (gop == .existing) return .{ .existing = gop.existing };
83058558
...@@ -8308,98 +8561,86 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread....@@ -8308,98 +8561,86 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.
8308 const extra = local.getMutableExtra(gpa, io);8561 const extra = local.getMutableExtra(gpa, io);
8309 try items.ensureUnusedCapacity(1);8562 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
8316 const is_extern = switch (ini.layout) {8564 const is_extern = switch (ini.layout) {
8317 .auto => false,8565 .auto => false,
8318 .@"extern" => true,8566 .@"extern" => true,
8319 .@"packed" => {8567 .@"packed" => {
8320 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeUnionPacked).@"struct".fields.len +8568 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
8322 ini.fields_len); // field_type8571 ini.fields_len); // field_type
83238572
8324 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnionPacked{8573 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnionPacked{
8325 .zir_index = zir_index,8574 .zir_index = ini.zir_index,
8326 .captures_len = switch (ini.key) {8575 .captures_len = .reified,
8327 .declared => |d| @enumFromInt(d.captures.len),
8328 .reified => .reified,
8329 },
8330 .name = undefined, // set by `finish`8576 .name = undefined, // set by `finish`
8331 .name_nav = undefined, // set by `finish`8577 .name_nav = undefined, // set by `finish`
8332 .namespace = undefined, // set by `finish`8578 .namespace = undefined, // set by `finish`
8333 .backing_int_type = ini.explicit_packed_backing_type,8579 .backing_int_type = ini.packed_backing_int_type,
8334 .enum_tag_type = .none, // set by `setTagType`8580 .enum_tag_type = .none,
8335 .fields_len = ini.fields_len,8581 .fields_len = ini.fields_len,
8336 });8582 });
8337 switch (ini.key) {8583 _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); // type_hash
8338 .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}),8584 const field_names_start = extra.mutate.len;
8339 .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)),8585 extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // reified_field_name
8340 }8586 const field_types_start = extra.mutate.len;
8341 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type8587 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type
8342 items.appendAssumeCapacity(.{8588 items.appendAssumeCapacity(.{
8343 .tag = switch (ini.explicit_packed_backing_type) {8589 .tag = switch (ini.packed_backing_int_type) {
8344 .none => .type_union_packed_auto,8590 .none => .type_union_packed_auto,
8345 else => .type_union_packed_explicit,8591 else => .type_union_packed_explicit,
8346 },8592 },
8347 .data = extra_index,8593 .data = extra_index,
8348 });8594 });
8349 return .{8595 return .{ .wip = .{
8350 .wip = .{8596 .index = gop.put(),
8351 .index = gop.put(),8597 .tid = tid,
8352 .tid = tid,8598 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name").?,
8353 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name").?,8599 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name_nav").?,
8354 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name_nav").?,8600 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "namespace").?,
8355 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "namespace").?,8601 .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len },
8356 .tag_type_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "enum_tag_type").?,8602 .field_types = .{ .tid = tid, .start = field_types_start, .len = ini.fields_len },
8357 .fields_len = 0, // the fields come from the enum, so nothing to set8603 .field_values = undefined,
8358 .field_name_map = undefined,8604 .field_aligns = undefined,
8359 .field_names_start = undefined,8605 .field_is_comptime_bits = undefined,
8360 .field_comptime_bits_start = undefined,8606 } };
8361 },
8362 };
8363 },8607 },
8364 };8608 };
83658609
8366 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeUnion).@"struct".fields.len +8610 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
8368 ini.fields_len + // field_type8613 ini.fields_len + // field_type
8369 (if (ini.any_field_aligns) (ini.fields_len + 3) / 4 else 0)); // field_align8614 (if (ini.any_field_aligns) (ini.fields_len + 3) / 4 else 0)); // field_align
83708615
8371 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{8616 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{
8372 .zir_index = zir_index,8617 .zir_index = ini.zir_index,
8373 .name = undefined, // set by `finish`8618 .name = undefined, // set by `finish`
8374 .name_nav = undefined, // set by `finish`8619 .name_nav = undefined, // set by `finish`
8375 .namespace = undefined, // set by `finish`8620 .namespace = undefined, // set by `finish`
8376 .enum_tag_type = .none, // set by `setTagType`8621 .enum_tag_type = ini.enum_tag_type,
8377 .fields_len = ini.fields_len,8622 .fields_len = ini.fields_len,
8378 .size = 0,8623 .size = 0,
8379 .padding = 0,8624 .padding = 0,
8380 .flags = .{8625 .flags = .{
8381 .any_captures = switch (ini.key) {8626 .any_captures = .reified,
8382 .declared => |d| if (d.captures.len != 0) .true else .false,8627 .enum_tag_mode = if (ini.enum_tag_type == .none) .auto else .explicit,
8383 .reified => .reified,
8384 },
8385 .explicit_tag_type = ini.have_explicit_enum_tag,
8386 .layout = if (is_extern) .@"extern" else .auto,8628 .layout = if (is_extern) .@"extern" else .auto,
8387 .any_field_aligns = ini.any_field_aligns,8629 .any_field_aligns = ini.any_field_aligns,
8388 .runtime_tag = ini.runtime_tag,8630 .runtime_tag = ini.runtime_tag,
8389 .has_one_possible_value = false,8631 .has_one_possible_value = false,
8390 .has_no_possible_value = false,8632 .has_no_possible_value = false,
8391 .comptime_only = false,8633 .comptime_only = false,
8634 .has_runtime_bits = false,
8392 .alignment = .none,8635 .alignment = .none,
8393 },8636 },
8394 });8637 });
8395 switch (ini.key) {8638 _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash));
8396 .declared => |d| if (d.captures.len != 0) {8639 const field_names_start = extra.mutate.len;
8397 extra.appendAssumeCapacity(.{@intCast(d.captures.len)});8640 extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // reified_field_name
8398 extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)});8641 const field_types_start = extra.mutate.len;
8399 },
8400 .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)),
8401 }
8402 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type8642 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type
8643 const field_aligns_start = extra.mutate.len;
8403 if (ini.any_field_aligns) {8644 if (ini.any_field_aligns) {
8404 extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 3) / 4); // field_align8645 extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 3) / 4); // field_align
8405 }8646 }
...@@ -8407,53 +8648,124 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread....@@ -8407,53 +8648,124 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.
8407 .tag = .type_union,8648 .tag = .type_union,
8408 .data = extra_index,8649 .data = extra_index,
8409 });8650 });
8410 return .{8651 return .{ .wip = .{
8411 .wip = .{8652 .index = gop.put(),
8412 .index = gop.put(),8653 .tid = tid,
8413 .tid = tid,8654 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?,
8414 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?,8655 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name_nav").?,
8415 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name_nav").?,8656 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?,
8416 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?,8657 .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len },
8417 .tag_type_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "enum_tag_type").?,8658 .field_types = .{ .tid = tid, .start = field_types_start, .len = ini.fields_len },
8418 .fields_len = 0, // the fields come from the enum, so nothing to set8659 .field_values = undefined,
8419 .field_name_map = undefined,8660 .field_aligns = if (ini.any_field_aligns)
8420 .field_names_start = undefined,8661 .{ .tid = tid, .start = field_aligns_start, .len = ini.fields_len }
8421 .field_comptime_bits_start = undefined,8662 else
8422 },8663 undefined,
8423 };8664 .field_is_comptime_bits = undefined,
8665 } };
8424}8666}
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,
8427 fields_len: u32,8760 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,
8431 nonexhaustive: bool,8761 nonexhaustive: bool,
8432 key: union(enum) {8762 /// Explicitly specified int tag type, or `.none` if the int tag type is inferred.
8433 declared: struct {8763 int_tag_type: Index,
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 },
8443}) Allocator.Error!WipContainerType.Result {8764}) Allocator.Error!WipContainerType.Result {
8444 const key: Key = .{ .enum_type = switch (ini.key) {8765 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .enum_type = .{ .reified = .{
8445 .declared => |d| .{ .declared = .{8766 .zir_index = ini.zir_index,
8446 .zir_index = d.zir_index,8767 .type_hash = ini.type_hash,
8447 .arg_ty = ini.explicit_int_tag_type,8768 } } });
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);
8457 defer gop.deinit();8769 defer gop.deinit();
8458 if (gop == .existing) return .{ .existing = gop.existing };8770 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...@@ -8464,7 +8776,7 @@ pub fn getEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.I
84648776
8465 const tag: Tag, const have_values: bool = if (ini.nonexhaustive)8777 const tag: Tag, const have_values: bool = if (ini.nonexhaustive)
8466 .{ .type_enum_nonexhaustive, true }8778 .{ .type_enum_nonexhaustive, true }
8467 else if (ini.explicit_int_tag_type != .none)8779 else if (ini.int_tag_type != .none)
8468 .{ .type_enum_explicit, true }8780 .{ .type_enum_explicit, true }
8469 else8781 else
8470 .{ .type_enum_auto, false };8782 .{ .type_enum_auto, false };
...@@ -8476,44 +8788,27 @@ pub fn getEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.I...@@ -8476,44 +8788,27 @@ pub fn getEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.I
8476 errdefer local.mutate.maps.len -= @intFromBool(have_values);8788 errdefer local.mutate.maps.len -= @intFromBool(have_values);
84778789
8478 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeEnum).@"struct".fields.len +8790 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeEnum).@"struct".fields.len +
8479 switch (ini.key) {8791 1 + // zir_index
8480 .declared => |d| 1 + d.captures.len, // `zir_index` and `capture`8792 2 + // type_hash
8481 .reified => 3, // `zir_index` and `type_hash`
8482 .generated_union_tag => 1, // owner_union
8483 } +
8484 @intFromBool(have_values) + // field_value_map8793 @intFromBool(have_values) + // field_value_map
8485 ini.fields_len + // field_name8794 ini.fields_len + // field_name
8486 (if (have_values) ini.fields_len else 0)); // field_value8795 (if (have_values) ini.fields_len else 0)); // field_value
84878796
8488 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeEnum{8797 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeEnum{
8489 .captures_len = switch (ini.key) {8798 .captures_len = .reified,
8490 .declared => |d| @enumFromInt(d.captures.len),
8491 .reified => .reified,
8492 .generated_union_tag => .generated_union_tag,
8493 },
8494 .name = undefined, // set by `finish`8799 .name = undefined, // set by `finish`
8495 .name_nav = undefined, // set by `finish`8800 .name_nav = undefined, // set by `finish`
8496 .namespace = undefined, // set by `finish`8801 .namespace = undefined, // set by `finish`
8497 .int_tag_type = ini.explicit_int_tag_type,8802 .int_tag_type = ini.int_tag_type,
8498 .fields_len = ini.fields_len,8803 .fields_len = ini.fields_len,
8499 .field_name_map = field_name_map,8804 .field_name_map = field_name_map,
8500 });8805 });
8501 switch (ini.key) {8806 extra.appendAssumeCapacity(.{@intFromEnum(ini.zir_index)}); // zir_index
8502 .declared => |d| {8807 _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); // type_hash
8503 extra.appendAssumeCapacity(.{@intFromEnum(d.zir_index)}); // zir_index8808 if (have_values) extra.appendAssumeCapacity(.{@intFromEnum(field_value_map)}); // field_value_map
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)});
8515 const field_names_start = extra.mutate.len;8809 const field_names_start = extra.mutate.len;
8516 extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name8810 extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name
8811 const field_values_start = extra.mutate.len;
8517 if (have_values) extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_value8812 if (have_values) extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_value
8518 items.appendAssumeCapacity(.{8813 items.appendAssumeCapacity(.{
8519 .tag = tag,8814 .tag = tag,
...@@ -8525,22 +8820,91 @@ pub fn getEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.I...@@ -8525,22 +8820,91 @@ pub fn getEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.I
8525 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name").?,8820 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name").?,
8526 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name_nav").?,8821 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name_nav").?,
8527 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "namespace").?,8822 .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,
8529 .fields_len = ini.fields_len,8873 .fields_len = ini.fields_len,
8530 .field_name_map = field_name_map,8874 .field_name_map = field_name_map,
8531 .field_names_start = field_names_start,8875 });
8532 .field_comptime_bits_start = null,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,
8533 } };8898 } };
8534}8899}
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 {
8537 zir_index: TrackedInst.Index,8902 zir_index: TrackedInst.Index,
8538 captures: []const CaptureValue,8903 captures: []const CaptureValue,
8539}) Allocator.Error!WipContainerType.Result {8904}) Allocator.Error!WipContainerType.Result {
8540 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .opaque_type = .{ .declared = .{8905 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .opaque_type = .{ .declared = .{
8541 .zir_index = ini.zir_index,8906 .zir_index = ini.zir_index,
8542 .captures = .{ .external = ini.captures },8907 .captures = .{ .external = ini.captures },
8543 .arg_ty = .none,
8544 } } });8908 } } });
8545 defer gop.deinit();8909 defer gop.deinit();
8546 if (gop == .existing) return .{ .existing = gop.existing };8910 if (gop == .existing) return .{ .existing = gop.existing };
...@@ -8569,11 +8933,11 @@ pub fn getOpaqueType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread...@@ -8569,11 +8933,11 @@ pub fn getOpaqueType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread
8569 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name").?,8933 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name").?,
8570 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name_nav").?,8934 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name_nav").?,
8571 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "namespace").?,8935 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "namespace").?,
8572 .tag_type_index = null,8936 .field_names = undefined,
8573 .fields_len = 0,8937 .field_types = undefined,
8574 .field_name_map = undefined,8938 .field_values = undefined,
8575 .field_names_start = undefined,8939 .field_aligns = undefined,
8576 .field_comptime_bits_start = undefined,8940 .field_is_comptime_bits = undefined,
8577 } };8941 } };
8578}8942}
85798943
...@@ -8584,12 +8948,15 @@ pub const WipContainerType = struct {...@@ -8584,12 +8948,15 @@ pub const WipContainerType = struct {
8584 name_nav_index: u32,8948 name_nav_index: u32,
8585 namespace_index: u32,8949 namespace_index: u32,
85868950
8587 tag_type_index: ?u32,8951 // These fields are only populated when creating reified types, because reified types populate
85888952 // field information immediately, with type resolution only handling validation. This is in
8589 fields_len: u32,8953 // contrast to declared types, where field information is populated by the type resolution
8590 field_name_map: MapIndex,8954 // process evaluating ZIR expressions.
8591 field_names_start: u32,8955 field_names: NullTerminatedString.Slice,
8592 field_comptime_bits_start: ?u32,8956 field_types: Index.Slice,
8957 field_values: Index.Slice,
8958 field_aligns: Alignment.Slice,
8959 field_is_comptime_bits: LoadedStructType.ComptimeBits,
85938960
8594 pub fn setName(8961 pub fn setName(
8595 wip: WipContainerType,8962 wip: WipContainerType,
...@@ -8605,48 +8972,6 @@ pub const WipContainerType = struct {...@@ -8605,48 +8972,6 @@ pub const WipContainerType = struct {
8605 extra_items[wip.name_nav_index] = @intFromEnum(name_nav);8972 extra_items[wip.name_nav_index] = @intFromEnum(name_nav);
8606 }8973 }
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
8650 pub fn finish(8975 pub fn finish(
8651 wip: WipContainerType,8976 wip: WipContainerType,
8652 ip: *InternPool,8977 ip: *InternPool,
...@@ -8657,14 +8982,6 @@ pub const WipContainerType = struct {...@@ -8657,14 +8982,6 @@ pub const WipContainerType = struct {
86578982
8658 extra_items[wip.namespace_index] = @intFromEnum(namespace);8983 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
8668 return wip.index;8985 return wip.index;
8669 }8986 }
86708987
...@@ -9504,19 +9821,6 @@ fn addStringsToMap(...@@ -9504,19 +9821,6 @@ fn addStringsToMap(
9504 }9821 }
9505}9822}
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
9520fn addMap(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, cap: usize) Allocator.Error!MapIndex {9824fn addMap(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, cap: usize) Allocator.Error!MapIndex {
9521 const maps = ip.getLocal(tid).getMutableMaps(gpa, io);9825 const maps = ip.getLocal(tid).getMutableMaps(gpa, io);
9522 const unwrapped: MapIndex.Unwrapped = .{ .tid = tid, .index = maps.mutate.len };9826 const unwrapped: MapIndex.Unwrapped = .{ .tid = tid, .index = maps.mutate.len };
...@@ -10260,10 +10564,78 @@ pub fn dump(ip: *const InternPool) void {...@@ -10260,10 +10564,78 @@ pub fn dump(ip: *const InternPool) void {
10260 const stderr = std.debug.lockStderr(&buffer);10564 const stderr = std.debug.lockStderr(&buffer);
10261 defer std.debug.unlockStderr();10565 defer std.debug.unlockStderr();
10262 const w = &stderr.file_writer.interface;10566 const w = &stderr.file_writer.interface;
10567 dumpDependencyStatsFallible(ip, w) catch return;
10263 dumpStatsFallible(ip, w, std.heap.page_allocator) catch return;10568 dumpStatsFallible(ip, w, std.heap.page_allocator) catch return;
10264 dumpAllFallible(ip, w) catch return;10569 dumpAllFallible(ip, w) catch return;
10265}10570}
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
10267fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !void {10639fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !void {
10268 var items_len: usize = 0;10640 var items_len: usize = 0;
10269 var extra_len: usize = 0;10641 var extra_len: usize = 0;
...@@ -10278,10 +10650,10 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo...@@ -10278,10 +10650,10 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo
10278 const limbs_size = 8 * limbs_len;10650 const limbs_size = 8 * limbs_len;
1027910651
10280 // TODO: map overhead size is not taken into account10652 // 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(10655 try w.print(
10284 \\InternPool size: {d} bytes10656 \\InternPool values: {d} bytes
10285 \\ {d} items: {d} bytes10657 \\ {d} items: {d} bytes
10286 \\ {d} extra: {d} bytes10658 \\ {d} extra: {d} bytes
10287 \\ {d} limbs: {d} bytes10659 \\ {d} limbs: {d} bytes
...@@ -10302,6 +10674,8 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo...@@ -10302,6 +10674,8 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo
10302 };10674 };
10303 var counts = std.AutoArrayHashMap(Tag, TagStats).init(arena);10675 var counts = std.AutoArrayHashMap(Tag, TagStats).init(arena);
10304 for (ip.locals) |*local| {10676 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;
10305 const items = local.shared.items.view().slice();10679 const items = local.shared.items.view().slice();
10306 const extra_list = local.shared.extra;10680 const extra_list = local.shared.extra;
10307 const extra_items = extra_list.view().items(.@"0");10681 const extra_items = extra_list.view().items(.@"0");
...@@ -10562,6 +10936,8 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo...@@ -10562,6 +10936,8 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo
1056210936
10563fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {10937fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {
10564 for (ip.locals, 0..) |*local, tid| {10938 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;
10565 const items = local.shared.items.view();10941 const items = local.shared.items.view();
10566 for (10942 for (
10567 items.items(.tag)[0..local.mutate.items.len],10943 items.items(.tag)[0..local.mutate.items.len],
...@@ -11981,22 +12357,42 @@ pub fn unwrapCoercedFunc(ip: *const InternPool, index: Index) Index {...@@ -11981,22 +12357,42 @@ pub fn unwrapCoercedFunc(ip: *const InternPool, index: Index) Index {
11981 };12357 };
11982}12358}
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.
11985pub fn addFieldName(12363pub fn addFieldName(
11986 ip: *InternPool,12364 ip: *InternPool,
11987 extra: Local.Extra,12365 names: NullTerminatedString.Slice,
11988 names_map: MapIndex,12366 map: MapIndex,
11989 names_start: u32,
11990 name: NullTerminatedString,12367 name: NullTerminatedString,
11991) ?u32 {12368) ?u32 {
11992 const extra_items = extra.view().items(.@"0");12369 const m = map.get(ip);
11993 const map = names_map.get(ip);12370 const field_idx = m.count();
11994 const field_index = map.count();12371 const names_slice = names.get(ip);
11995 const strings = extra_items[names_start..][0..field_index];12372 names_slice[field_idx] = name;
11996 const adapter: NullTerminatedString.Adapter = .{ .strings = @ptrCast(strings) };12373 const adapter: NullTerminatedString.Adapter = .{ .strings = names_slice[0..field_idx] };
11997 const gop = map.getOrPutAssumeCapacityAdapted(name, adapter);12374 const gop = m.getOrPutAssumeCapacityAdapted(name, adapter);
11998 if (gop.found_existing) return @intCast(gop.index);12375 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);
12000 return null;12396 return null;
12001}12397}
1200212398
...@@ -12295,6 +12691,7 @@ pub fn resolveStructLayout(...@@ -12295,6 +12691,7 @@ pub fn resolveStructLayout(
12295 has_no_possible_value: bool,12691 has_no_possible_value: bool,
12296 has_one_possible_value: bool,12692 has_one_possible_value: bool,
12297 comptime_only: bool,12693 comptime_only: bool,
12694 has_runtime_bits: bool,
12298) void {12695) void {
12299 const unwrapped_index = struct_type.unwrap(ip);12696 const unwrapped_index = struct_type.unwrap(ip);
1230012697
...@@ -12311,6 +12708,7 @@ pub fn resolveStructLayout(...@@ -12311,6 +12708,7 @@ pub fn resolveStructLayout(
12311 flags.has_no_possible_value = has_no_possible_value;12708 flags.has_no_possible_value = has_no_possible_value;
12312 flags.has_one_possible_value = has_one_possible_value;12709 flags.has_one_possible_value = has_one_possible_value;
12313 flags.comptime_only = comptime_only;12710 flags.comptime_only = comptime_only;
12711 flags.has_runtime_bits = has_runtime_bits;
12314 flags.alignment = alignment;12712 flags.alignment = alignment;
12315}12713}
1231612714
...@@ -12322,12 +12720,14 @@ pub fn resolveUnionLayout(...@@ -12322,12 +12720,14 @@ pub fn resolveUnionLayout(
12322 ip: *InternPool,12720 ip: *InternPool,
12323 io: Io,12721 io: Io,
12324 union_type: Index,12722 union_type: Index,
12723 enum_tag_type: Index,
12325 size: u32,12724 size: u32,
12326 padding: u32,12725 padding: u32,
12327 alignment: Alignment,12726 alignment: Alignment,
12328 has_no_possible_value: bool,12727 has_no_possible_value: bool,
12329 has_one_possible_value: bool,12728 has_one_possible_value: bool,
12330 comptime_only: bool,12729 comptime_only: bool,
12730 has_runtime_bits: bool,
12331) void {12731) void {
12332 const unwrapped_index = union_type.unwrap(ip);12732 const unwrapped_index = union_type.unwrap(ip);
1233312733
...@@ -12339,17 +12739,24 @@ pub fn resolveUnionLayout(...@@ -12339,17 +12739,24 @@ pub fn resolveUnionLayout(
12339 const item = unwrapped_index.getItem(ip);12739 const item = unwrapped_index.getItem(ip);
12340 assert(item.tag == .type_union);12740 assert(item.tag == .type_union);
1234112741
12742 extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "enum_tag_type").?] = @intFromEnum(enum_tag_type);
12342 extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "size").?] = size;12743 extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "size").?] = size;
12343 extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "padding").?] = padding;12744 extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "padding").?] = padding;
12344 const flags: *Tag.TypeUnion.Flags = @ptrCast(&extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "flags").?]);12745 const flags: *Tag.TypeUnion.Flags = @ptrCast(&extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "flags").?]);
12345 flags.has_no_possible_value = has_no_possible_value;12746 flags.has_no_possible_value = has_no_possible_value;
12346 flags.has_one_possible_value = has_one_possible_value;12747 flags.has_one_possible_value = has_one_possible_value;
12347 flags.comptime_only = comptime_only;12748 flags.comptime_only = comptime_only;
12749 flags.has_runtime_bits = has_runtime_bits;
12348 flags.alignment = alignment;12750 flags.alignment = alignment;
12349}12751}
1235012752
12351/// Asserts that `struct_type` is a packed struct type.12753/// 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 {
12353 const unwrapped_index = struct_type.unwrap(ip);12760 const unwrapped_index = struct_type.unwrap(ip);
1235412761
12355 const local = ip.getLocal(unwrapped_index.tid);12762 const local = ip.getLocal(unwrapped_index.tid);
...@@ -12371,7 +12778,13 @@ pub fn resolvePackedStructBackingInt(ip: *InternPool, io: Io, struct_type: Index...@@ -12371,7 +12778,13 @@ pub fn resolvePackedStructBackingInt(ip: *InternPool, io: Io, struct_type: Index
12371}12778}
1237212779
12373/// Asserts that `union_type` is a packed union type.12780/// 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 {
12375 const unwrapped_index = union_type.unwrap(ip);12788 const unwrapped_index = union_type.unwrap(ip);
1237612789
12377 const local = ip.getLocal(unwrapped_index.tid);12790 const local = ip.getLocal(unwrapped_index.tid);
...@@ -12387,5 +12800,32 @@ pub fn resolvePackedUnionBackingInt(ip: *InternPool, io: Io, union_type: Index,...@@ -12387,5 +12800,32 @@ pub fn resolvePackedUnionBackingInt(ip: *InternPool, io: Io, union_type: Index,
12387 else => unreachable,12800 else => unreachable,
12388 }12801 }
1238912802
12803 extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnionPacked, "enum_tag_type").?] = @intFromEnum(enum_tag_type);
12390 extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnionPacked, "backing_int_type").?] = @intFromEnum(backing_int_type);12804 extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnionPacked, "backing_int_type").?] = @intFromEnum(backing_int_type);
12391}12805}
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 {...@@ -397,7 +397,7 @@ pub const Block = struct {
397 /// The name of the current "context" for naming namespace types.397 /// The name of the current "context" for naming namespace types.
398 /// The interpretation of this depends on the name strategy in ZIR, but the name398 /// The interpretation of this depends on the name strategy in ZIR, but the name
399 /// is always incorporated into the type name somehow.399 /// is always incorporated into the type name somehow.
400 /// See `Sema.createTypeName`.400 /// See `Sema.setTypeName`.
401 type_name_ctx: InternPool.NullTerminatedString,401 type_name_ctx: InternPool.NullTerminatedString,
402402
403 /// Create a `LazySrcLoc` based on an `Offset` from the code being analyzed in this block.403 /// Create a `LazySrcLoc` based on an `Offset` from the code being analyzed in this block.
...@@ -1158,7 +1158,7 @@ fn analyzeBodyInner(...@@ -1158,7 +1158,7 @@ fn analyzeBodyInner(
1158 }, inst });1158 }, inst });
1159 }1159 }
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)]) {
1162 // zig fmt: off1162 // zig fmt: off
1163 .alloc => try sema.zirAlloc(block, inst),1163 .alloc => try sema.zirAlloc(block, inst),
1164 .alloc_inferred => try sema.zirAllocInferred(block, true),1164 .alloc_inferred => try sema.zirAllocInferred(block, true),
...@@ -1991,31 +1991,33 @@ fn analyzeBodyInner(...@@ -1991,31 +1991,33 @@ fn analyzeBodyInner(
1991 break :blk .void_value;1991 break :blk .void_value;
1992 },1992 },
1993 };1993 };
1994 if (sema.isNoReturn(air_inst)) {1994 if (sema.isNoReturn(air_ref)) {
1995 // We're going to assume that the body itself is noreturn, so let's ensure that now1995 // We're going to assume that the body itself is noreturn, so let's ensure that now
1996 assert(block.instructions.items.len > 0);1996 assert(block.instructions.items.len > 0);
1997 assert(sema.isNoReturn(block.instructions.items[block.instructions.items.len - 1].toRef()));1997 assert(sema.isNoReturn(block.instructions.items[block.instructions.items.len - 1].toRef()));
1998 break;1998 break;
1999 }1999 }
2000 // <MLUGG TODO REMOVE THIS BLOCK, SILLY OPV CHECK>2000
2001 if (air_inst.toIndex()) |air_inst_index| {2001 // We must resolve the layout of a type before creating a value of that type. Therefore,
2002 switch (sema.air_instructions.items(.tag)[@intFromEnum(air_inst_index)]) {2002 // the layout of the type of `air_ref` must already be resolved.
2003 .inferred_alloc, .inferred_alloc_comptime => {},2003 check_type: {
2004 else => {2004 if (air_ref.toIndex()) |air_inst| switch (sema.air_instructions.items(.tag)[@intFromEnum(air_inst)]) {
2005 assert(sema.typeOf(air_inst).onePossibleValue(pt) catch @panic("") == null);2005 .inferred_alloc, .inferred_alloc_comptime => break :check_type,
2006 sema.typeOf(air_inst).assertHasLayout(zcu);2006 else => {},
2007 },2007 };
2008 }2008 sema.typeOf(air_ref).assertHasLayout(zcu);
2009 } else {2009 // If the type has an OPV, `air_ref` must be that OPV: there is no other interned value
2010 switch (tags[@intFromEnum(inst)]) {2010 // it could be, and it would be a bug for the value to not be comptime-known when it has
2011 // MLUGG TODO: do we actually *want* this exception? we could arguably simplify things without it2011 // an OPV. Behind a `std.debug.runtime_safety` check because `onePossibleValue` mutates
2012 // e.g. analyzeNavVal could stop doing ensureLayoutResolved in most cases (`extern` is an exception) and instead do `assertHasLayout`2012 // the InternPool so cannot be optimized out.
2013 .func, .func_inferred, .func_fancy => {}, // exception: we're in a func decl, layout will get resolved in a bit by `analyzeNavVal`2013 if (std.debug.runtime_safety) {
2014 else => sema.typeOf(air_inst).assertHasLayout(zcu),2014 if (try sema.typeOf(air_ref).onePossibleValue(pt)) |opv| {
2015 assert(air_ref == Air.Inst.Ref.fromValue(opv));
2016 }
2015 }2017 }
2016 }2018 }
2017 // </MLUGG TODO REMOVE THIS BLOCK, SILLY OPV CHECK>2019
2018 map.putAssumeCapacity(inst, air_inst);2020 map.putAssumeCapacity(inst, air_ref);
2019 i += 1;2021 i += 1;
2020 }2022 }
2021}2023}
...@@ -2097,7 +2099,7 @@ pub fn resolveConstStringIntern(...@@ -2097,7 +2099,7 @@ pub fn resolveConstStringIntern(
20972099
2098fn resolveTypeOrPoison(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) !?Type {2100fn resolveTypeOrPoison(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) !?Type {
2099 const air_inst = try sema.resolveInst(zir_ref);2101 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);
2101 if (ty.isGenericPoison()) return null;2103 if (ty.isGenericPoison()) return null;
2102 return ty;2104 return ty;
2103}2105}
...@@ -2216,11 +2218,12 @@ pub fn analyzeAsType(...@@ -2216,11 +2218,12 @@ pub fn analyzeAsType(
2216 sema: *Sema,2218 sema: *Sema,
2217 block: *Block,2219 block: *Block,
2218 src: LazySrcLoc,2220 src: LazySrcLoc,
2221 reason: std.zig.SimpleComptimeReason,
2219 air_inst: Air.Inst.Ref,2222 air_inst: Air.Inst.Ref,
2220) !Type {2223) !Type {
2221 const wanted_type: Type = .type;2224 const wanted_type: Type = .type;
2222 const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);2225 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 });
2224 return val.toType();2227 return val.toType();
2225}2228}
22262229
...@@ -4112,9 +4115,11 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -4112,9 +4115,11 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
4112/// or error union pointed to, initializing these pointers along the way.4115/// or error union pointed to, initializing these pointers along the way.
4113/// Given a `*E!?T`, returns a (valid) `*T`.4116/// Given a `*E!?T`, returns a (valid) `*T`.
4114/// May invalidate already-stored payload data.4117/// May invalidate already-stored payload data.
4118/// Asserts that the layout of the pointer child type is already resolved.
4115fn optEuBasePtrInit(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, src: LazySrcLoc) CompileError!Air.Inst.Ref {4119fn optEuBasePtrInit(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, src: LazySrcLoc) CompileError!Air.Inst.Ref {
4116 const pt = sema.pt;4120 const pt = sema.pt;
4117 const zcu = pt.zcu;4121 const zcu = pt.zcu;
4122 sema.typeOf(ptr).childType(zcu).assertHasLayout(zcu);
4118 var base_ptr = ptr;4123 var base_ptr = ptr;
4119 while (true) switch (sema.typeOf(base_ptr).childType(zcu).zigTypeTag(zcu)) {4124 while (true) switch (sema.typeOf(base_ptr).childType(zcu).zigTypeTag(zcu)) {
4120 .error_union => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true),4125 .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...@@ -4128,6 +4133,7 @@ fn optEuBasePtrInit(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, src: LazySrcL
4128fn zirOptEuBasePtrInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {4133fn zirOptEuBasePtrInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
4129 const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;4134 const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
4130 const ptr = try sema.resolveInst(un_node.operand);4135 const ptr = try sema.resolveInst(un_node.operand);
4136 try sema.ensureLayoutResolved(sema.typeOf(ptr).childType(sema.pt.zcu));
4131 return sema.optEuBasePtrInit(block, ptr, block.nodeOffset(un_node.src_node));4137 return sema.optEuBasePtrInit(block, ptr, block.nodeOffset(un_node.src_node));
4132}4138}
41334139
...@@ -4513,7 +4519,7 @@ fn validateStructInit(...@@ -4513,7 +4519,7 @@ fn validateStructInit(
4513 if (struct_ty.structFieldIsComptime(i, zcu)) continue;4519 if (struct_ty.structFieldIsComptime(i, zcu)) continue;
45144520
4515 if (!struct_ty.isTuple(zcu)) {4521 if (!struct_ty.isTuple(zcu)) {
4516 try sema.ensureFieldInitsResolved(struct_ty);4522 try sema.ensureStructDefaultsResolved(struct_ty);
4517 }4523 }
45184524
4519 const default_val = struct_ty.structFieldDefaultValue(i, zcu) orelse {4525 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...@@ -5737,7 +5743,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
5737 }5743 }
5738 if (zcu.llvm_object != null and options.linkage == .internal) return;5744 if (zcu.llvm_object != null and options.linkage == .internal) return;
5739 const export_ty = Value.fromInterned(uav.val).typeOf(zcu);5745 const export_ty = Value.fromInterned(uav.val).typeOf(zcu);
5740 if (!try sema.validateExternType(export_ty, .other)) {5746 if (!export_ty.validateExtern(.other, zcu)) {
5741 return sema.failWithOwnedErrorMsg(block, msg: {5747 return sema.failWithOwnedErrorMsg(block, msg: {
5742 const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)});5748 const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)});
5743 errdefer msg.destroy(sema.gpa);5749 errdefer msg.destroy(sema.gpa);
...@@ -5789,7 +5795,7 @@ pub fn analyzeExport(...@@ -5789,7 +5795,7 @@ pub fn analyzeExport(
5789 const exported_nav = ip.getNav(exported_nav_index);5795 const exported_nav = ip.getNav(exported_nav_index);
5790 const export_ty: Type = .fromInterned(exported_nav.typeOf(ip));5796 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)) {
5793 return sema.failWithOwnedErrorMsg(block, msg: {5799 return sema.failWithOwnedErrorMsg(block, msg: {
5794 const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)});5800 const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)});
5795 errdefer msg.destroy(gpa);5801 errdefer msg.destroy(gpa);
...@@ -5827,7 +5833,7 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void {...@@ -5827,7 +5833,7 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void {
5827 .nav_val,5833 .nav_val,
5828 .nav_ty,5834 .nav_ty,
5829 .type_layout,5835 .type_layout,
5830 .type_inits,5836 .struct_defaults,
5831 .memoized_state,5837 .memoized_state,
5832 => return, // does nothing outside a function5838 => return, // does nothing outside a function
5833 };5839 };
...@@ -5846,7 +5852,7 @@ fn zirDisableIntrinsics(sema: *Sema) CompileError!void {...@@ -5846,7 +5852,7 @@ fn zirDisableIntrinsics(sema: *Sema) CompileError!void {
5846 .nav_val,5852 .nav_val,
5847 .nav_ty,5853 .nav_ty,
5848 .type_layout,5854 .type_layout,
5849 .type_inits,5855 .struct_defaults,
5850 .memoized_state,5856 .memoized_state,
5851 => return, // does nothing outside a function5857 => return, // does nothing outside a function
5852 };5858 };
...@@ -6729,8 +6735,28 @@ fn analyzeCall(...@@ -6729,8 +6735,28 @@ fn analyzeCall(
6729 } else func_src;6735 } else func_src;
67306736
6731 const func_ty_info = zcu.typeToFunc(func_ty).?;6737 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*...6738 const any_comptime_params = func_ty_info.comptime_bits != 0 or ct: {
6733 const func_is_generic = !func_ty.fnHasRuntimeBits(zcu);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
6734 if (!callConvIsCallable(func_ty_info.cc)) {6760 if (!callConvIsCallable(func_ty_info.cc)) {
6735 return sema.failWithOwnedErrorMsg(block, msg: {6761 return sema.failWithOwnedErrorMsg(block, msg: {
6736 const msg = try sema.errMsg(6762 const msg = try sema.errMsg(
...@@ -6766,7 +6792,7 @@ fn analyzeCall(...@@ -6766,7 +6792,7 @@ fn analyzeCall(
6766 else => unreachable,6792 else => unreachable,
6767 } else .{ null, false };6793 } 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) {
6770 return sema.failWithNeededComptime(block, func_src, .{ .simple = .generic_call_target });6796 return sema.failWithNeededComptime(block, func_src, .{ .simple = .generic_call_target });
6771 }6797 }
67726798
...@@ -6815,13 +6841,13 @@ fn analyzeCall(...@@ -6815,13 +6841,13 @@ fn analyzeCall(
6815 // This is the `inst_map` used when evaluating generic parameters and return types.6841 // This is the `inst_map` used when evaluating generic parameters and return types.
6816 var generic_inst_map: InstMap = .{};6842 var generic_inst_map: InstMap = .{};
6817 defer generic_inst_map.deinit(gpa);6843 defer generic_inst_map.deinit(gpa);
6818 if (func_is_generic) {6844 if (any_generic_types) {
6819 try generic_inst_map.ensureSpaceForInstructions(gpa, fn_zir_info.param_body);6845 try generic_inst_map.ensureSpaceForInstructions(gpa, fn_zir_info.param_body);
6820 }6846 }
68216847
6822 // This exists so that `generic_block` below can include a "called from here" note back to this6848 // This exists so that `generic_block` below can include a "called from here" note back to this
6823 // call site when analyzing generic parameter/return types.6849 // 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) .{
6825 .call_block = block,6851 .call_block = block,
6826 .call_src = call_src,6852 .call_src = call_src,
6827 .func = func_val.?.toIntern(),6853 .func = func_val.?.toIntern(),
...@@ -6834,7 +6860,7 @@ fn analyzeCall(...@@ -6834,7 +6860,7 @@ fn analyzeCall(
6834 // This is the block in which we evaluate generic function components: that is, generic parameter6860 // This is the block in which we evaluate generic function components: that is, generic parameter
6835 // types and the generic return type. This must not be used if the function is not generic.6861 // types and the generic return type. This must not be used if the function is not generic.
6836 // `comptime_reason` is set as needed.6862 // `comptime_reason` is set as needed.
6837 var generic_block: Block = if (func_is_generic) .{6863 var generic_block: Block = if (any_generic_types) .{
6838 .parent = null,6864 .parent = null,
6839 .sema = sema,6865 .sema = sema,
6840 .namespace = fn_nav.analysis.?.namespace,6866 .namespace = fn_nav.analysis.?.namespace,
...@@ -6843,9 +6869,9 @@ fn analyzeCall(...@@ -6843,9 +6869,9 @@ fn analyzeCall(
6843 .src_base_inst = fn_nav.analysis.?.zir_index,6869 .src_base_inst = fn_nav.analysis.?.zir_index,
6844 .type_name_ctx = fn_nav.fqn,6870 .type_name_ctx = fn_nav.fqn,
6845 } else undefined;6871 } 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) {
6849 // We certainly depend on the generic owner's signature!6875 // We certainly depend on the generic owner's signature!
6850 try sema.declareDependency(.{ .src_hash = fn_tracked_inst });6876 try sema.declareDependency(.{ .src_hash = fn_tracked_inst });
6851 }6877 }
...@@ -6857,7 +6883,7 @@ fn analyzeCall(...@@ -6857,7 +6883,7 @@ fn analyzeCall(
6857 if (raw != .generic_poison_type) break :ty .fromInterned(raw);6883 if (raw != .generic_poison_type) break :ty .fromInterned(raw);
68586884
6859 // We must discover the generic parameter type.6885 // We must discover the generic parameter type.
6860 assert(func_is_generic);6886 assert(any_generic_types);
6861 const param_inst_idx = fn_zir_info.param_body[arg_idx];6887 const param_inst_idx = fn_zir_info.param_body[arg_idx];
6862 const param_inst = fn_zir.instructions.get(@intFromEnum(param_inst_idx));6888 const param_inst = fn_zir.instructions.get(@intFromEnum(param_inst_idx));
6863 switch (param_inst.tag) {6889 switch (param_inst.tag) {
...@@ -6888,7 +6914,7 @@ fn analyzeCall(...@@ -6888,7 +6914,7 @@ fn analyzeCall(
6888 } };6914 } };
68896915
6890 const ty_ref = try sema.resolveInlineBody(&generic_block, body, param_inst_idx);6916 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
6893 if (!param_ty.isValidParamType(zcu)) {6919 if (!param_ty.isValidParamType(zcu)) {
6894 const opaque_str = if (param_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else "";6920 const opaque_str = if (param_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else "";
...@@ -6906,7 +6932,7 @@ fn analyzeCall(...@@ -6906,7 +6932,7 @@ fn analyzeCall(
6906 return arg.*; // terminate analysis here6932 return arg.*; // terminate analysis here
6907 }6933 }
69086934
6909 if (func_is_generic) {6935 if (any_generic_types) {
6910 // We need to put the argument into `generic_inst_map` so that other parameters can refer to it.6936 // We need to put the argument into `generic_inst_map` so that other parameters can refer to it.
6911 const param_inst_idx = fn_zir_info.param_body[arg_idx];6937 const param_inst_idx = fn_zir_info.param_body[arg_idx];
6912 const declared_comptime = if (std.math.cast(u5, arg_idx)) |i| func_ty_info.paramIsComptime(i) else false;6938 const declared_comptime = if (std.math.cast(u5, arg_idx)) |i| func_ty_info.paramIsComptime(i) else false;
...@@ -6948,7 +6974,7 @@ fn analyzeCall(...@@ -6948,7 +6974,7 @@ fn analyzeCall(
6948 // calls (where it should be the IES of the instantiation). However, it's how we print this6974 // calls (where it should be the IES of the instantiation). However, it's how we print this
6949 // in error messages.6975 // in error messages.
6950 const resolved_ret_ty: Type = ret_ty: {6976 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
6953 const maybe_poison_bare = if (fn_zir_info.inferred_error_set) maybe_poison: {6979 const maybe_poison_bare = if (fn_zir_info.inferred_error_set) maybe_poison: {
6954 break :maybe_poison ip.errorUnionPayload(func_ty_info.return_type);6980 break :maybe_poison ip.errorUnionPayload(func_ty_info.return_type);
...@@ -6958,7 +6984,7 @@ fn analyzeCall(...@@ -6958,7 +6984,7 @@ fn analyzeCall(
69586984
6959 // Evaluate the generic return type. As with generic parameters, we switch out `sema.code` and `sema.inst_map`.6985 // 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
6963 const old_code = sema.code;6989 const old_code = sema.code;
6964 const old_inst_map = sema.inst_map;6990 const old_inst_map = sema.inst_map;
...@@ -6981,7 +7007,7 @@ fn analyzeCall(...@@ -6981,7 +7007,7 @@ fn analyzeCall(
6981 } else bare: {7007 } else bare: {
6982 assert(fn_zir_info.ret_ty_body.len != 0);7008 assert(fn_zir_info.ret_ty_body.len != 0);
6983 const ty_ref = try sema.resolveInlineBody(&generic_block, fn_zir_info.ret_ty_body, fn_zir_inst);7009 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);
6985 };7011 };
6986 assert(bare_ty.toIntern() != .generic_poison_type);7012 assert(bare_ty.toIntern() != .generic_poison_type);
69877013
...@@ -7035,7 +7061,7 @@ fn analyzeCall(...@@ -7035,7 +7061,7 @@ fn analyzeCall(
7035 });7061 });
7036 if (func_ty_info.cc == .auto) {7062 if (func_ty_info.cc == .auto) {
7037 switch (sema.owner.unwrap()) {7063 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 => {},
7039 .func => |owner_func| ip.funcSetHasErrorTrace(io, owner_func, true),7065 .func => |owner_func| ip.funcSetHasErrorTrace(io, owner_func, true),
7040 }7066 }
7041 }7067 }
...@@ -7043,7 +7069,7 @@ fn analyzeCall(...@@ -7043,7 +7069,7 @@ fn analyzeCall(
7043 try sema.validateRuntimeValue(block, args_info.argSrc(block, arg_idx), arg);7069 try sema.validateRuntimeValue(block, args_info.argSrc(block, arg_idx), arg);
7044 }7070 }
7045 const runtime_func: Air.Inst.Ref, const runtime_args: []const Air.Inst.Ref = func: {7071 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
7048 // Instantiate the generic function!7074 // Instantiate the generic function!
70497075
...@@ -7512,9 +7538,7 @@ fn zirArrayInitElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil...@@ -7512,9 +7538,7 @@ fn zirArrayInitElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil
7512 assert(indexable_ty.isIndexable(zcu)); // validated by a previous instruction7538 assert(indexable_ty.isIndexable(zcu)); // validated by a previous instruction
7513 const elem_ty = switch (indexable_ty.zigTypeTag(zcu)) {7539 const elem_ty = switch (indexable_ty.zigTypeTag(zcu)) {
7514 .@"struct" => indexable_ty.fieldType(@intFromEnum(bin.rhs), zcu),7540 .@"struct" => indexable_ty.fieldType(@intFromEnum(bin.rhs), zcu),
7515 .array, .vector => indexable_ty.childType(zcu),7541 else => indexable_ty.indexableElem(zcu),
7516 .pointer => indexable_ty.indexablePtrElem(zcu),
7517 else => unreachable,
7518 };7542 };
7519 return .fromType(elem_ty);7543 return .fromType(elem_ty);
7520}7544}
...@@ -7835,8 +7859,8 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -7835,8 +7859,8 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
7835 };7859 };
7836 return sema.failWithOwnedErrorMsg(block, msg);7860 return sema.failWithOwnedErrorMsg(block, msg);
7837 }7861 }
7838 const lhs_ty = try sema.analyzeAsType(block, lhs_src, lhs);7862 const lhs_ty = try sema.analyzeAsType(block, lhs_src, .type, lhs);
7839 const rhs_ty = try sema.analyzeAsType(block, rhs_src, rhs);7863 const rhs_ty = try sema.analyzeAsType(block, rhs_src, .type, rhs);
7840 if (lhs_ty.zigTypeTag(zcu) != .error_set)7864 if (lhs_ty.zigTypeTag(zcu) != .error_set)
7841 return sema.fail(block, lhs_src, "expected error set type, found '{f}'", .{lhs_ty.fmt(pt)});7865 return sema.fail(block, lhs_src, "expected error set type, found '{f}'", .{lhs_ty.fmt(pt)});
7842 if (rhs_ty.zigTypeTag(zcu) != .error_set)7866 if (rhs_ty.zigTypeTag(zcu) != .error_set)
...@@ -8017,12 +8041,13 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -8017,12 +8041,13 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
8017 if (dest_ty.zigTypeTag(zcu) != .@"enum") {8041 if (dest_ty.zigTypeTag(zcu) != .@"enum") {
8018 return sema.fail(block, src, "expected enum, found '{f}'", .{dest_ty.fmt(pt)});8042 return sema.fail(block, src, "expected enum, found '{f}'", .{dest_ty.fmt(pt)});
8019 }8043 }
8044 try sema.ensureLayoutResolved(dest_ty);
8020 _ = try sema.checkIntType(block, operand_src, operand_ty);8045 _ = try sema.checkIntType(block, operand_src, operand_ty);
80218046
8022 if (try sema.resolveValue(operand)) |int_val| {8047 if (try sema.resolveValue(operand)) |int_val| {
8023 if (dest_ty.isNonexhaustiveEnum(zcu)) {8048 if (dest_ty.isNonexhaustiveEnum(zcu)) {
8024 const int_tag_ty = dest_ty.intTagType(zcu);8049 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)) {
8026 return Air.internedToRef((try pt.getCoerced(int_val, dest_ty)).toIntern());8051 return Air.internedToRef((try pt.getCoerced(int_val, dest_ty)).toIntern());
8027 }8052 }
8028 return sema.fail(block, src, "int value '{f}' out of range of non-exhaustive enum '{f}'", .{8053 return sema.fail(block, src, "int value '{f}' out of range of non-exhaustive enum '{f}'", .{
...@@ -8077,10 +8102,14 @@ fn zirOptionalPayloadPtr(...@@ -8077,10 +8102,14 @@ fn zirOptionalPayloadPtr(
8077 const optional_ptr = try sema.resolveInst(inst_data.operand);8102 const optional_ptr = try sema.resolveInst(inst_data.operand);
8078 const src = block.nodeOffset(inst_data.src_node);8103 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
8080 return sema.analyzeOptionalPayloadPtr(block, src, optional_ptr, safety_check, false);8109 return sema.analyzeOptionalPayloadPtr(block, src, optional_ptr, safety_check, false);
8081}8110}
80828111
8083/// MLUGG TODO: pre-resolved child?8112/// Asserts that the layout of the pointer child type is already resolved.
8084fn analyzeOptionalPayloadPtr(8113fn analyzeOptionalPayloadPtr(
8085 sema: *Sema,8114 sema: *Sema,
8086 block: *Block,8115 block: *Block,
...@@ -8095,12 +8124,12 @@ fn analyzeOptionalPayloadPtr(...@@ -8095,12 +8124,12 @@ fn analyzeOptionalPayloadPtr(
8095 assert(optional_ptr_ty.zigTypeTag(zcu) == .pointer);8124 assert(optional_ptr_ty.zigTypeTag(zcu) == .pointer);
80968125
8097 const opt_type = optional_ptr_ty.childType(zcu);8126 const opt_type = optional_ptr_ty.childType(zcu);
8127 opt_type.assertHasLayout(zcu);
8098 if (opt_type.zigTypeTag(zcu) != .optional) {8128 if (opt_type.zigTypeTag(zcu) != .optional) {
8099 return sema.failWithExpectedOptionalType(block, src, opt_type);8129 return sema.failWithExpectedOptionalType(block, src, opt_type);
8100 }8130 }
81018131
8102 const child_type = opt_type.optionalChild(zcu);8132 const child_type = opt_type.optionalChild(zcu);
8103 try sema.ensureLayoutResolved(child_type);
8104 const child_pointer = try pt.ptrType(.{8133 const child_pointer = try pt.ptrType(.{
8105 .child = child_type.toIntern(),8134 .child = child_type.toIntern(),
8106 .flags = .{8135 .flags = .{
...@@ -8283,10 +8312,14 @@ fn zirErrUnionPayloadPtr(...@@ -8283,10 +8312,14 @@ fn zirErrUnionPayloadPtr(
8283 const operand = try sema.resolveInst(inst_data.operand);8312 const operand = try sema.resolveInst(inst_data.operand);
8284 const src = block.nodeOffset(inst_data.src_node);8313 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
8286 return sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);8319 return sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);
8287}8320}
82888321
8289/// MLUGG TODO LAYOUT: already-resolved child?8322/// Asserts that the layout of the pointer child type is already resolved.
8290fn analyzeErrUnionPayloadPtr(8323fn analyzeErrUnionPayloadPtr(
8291 sema: *Sema,8324 sema: *Sema,
8292 block: *Block,8325 block: *Block,
...@@ -8307,8 +8340,8 @@ fn analyzeErrUnionPayloadPtr(...@@ -8307,8 +8340,8 @@ fn analyzeErrUnionPayloadPtr(
8307 }8340 }
83088341
8309 const err_union_ty = operand_ty.childType(zcu);8342 const err_union_ty = operand_ty.childType(zcu);
8343 err_union_ty.assertHasLayout(zcu);
8310 const payload_ty = err_union_ty.errorUnionPayload(zcu);8344 const payload_ty = err_union_ty.errorUnionPayload(zcu);
8311 try sema.ensureLayoutResolved(payload_ty);
8312 const operand_pointer_ty = try pt.ptrType(.{8345 const operand_pointer_ty = try pt.ptrType(.{
8313 .child = payload_ty.toIntern(),8346 .child = payload_ty.toIntern(),
8314 .flags = .{8347 .flags = .{
...@@ -8744,7 +8777,7 @@ fn checkParamTypeCommon(...@@ -8744,7 +8777,7 @@ fn checkParamTypeCommon(
8744 }8777 }
8745 if (!param_ty.isGenericPoison() and8778 if (!param_ty.isGenericPoison() and
8746 !target_util.fnCallConvAllowsZigTypes(cc) and8779 !target_util.fnCallConvAllowsZigTypes(cc) and
8747 !try sema.validateExternType(param_ty, .param_ty))8780 !param_ty.validateExtern(.param_ty, zcu))
8748 {8781 {
8749 return sema.failWithOwnedErrorMsg(block, msg: {8782 return sema.failWithOwnedErrorMsg(block, msg: {
8750 const msg = try sema.errMsg(param_src, "parameter of type '{f}' not allowed in function with calling convention '{s}'", .{8783 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(...@@ -8818,7 +8851,7 @@ fn checkReturnTypeAndCallConvCommon(
8818 }8851 }
8819 if (!bare_ret_ty.isGenericPoison() and8852 if (!bare_ret_ty.isGenericPoison() and
8820 !target_util.fnCallConvAllowsZigTypes(@"callconv") and8853 !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)))
8822 {8855 {
8823 return sema.failWithOwnedErrorMsg(block, msg: {8856 return sema.failWithOwnedErrorMsg(block, msg: {
8824 const msg = try sema.errMsg(ret_ty_src, "return type '{s}{f}' not allowed in function with calling convention '{s}'", .{8857 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(...@@ -9042,7 +9075,7 @@ fn funcCommon(
90429075
9043 if (inferred_error_set) {9076 if (inferred_error_set) {
9044 assert(has_body);9077 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, .{
9046 .owner_nav = sema.owner.unwrap().nav_val,9079 .owner_nav = sema.owner.unwrap().nav_val,
90479080
9048 .param_types = param_types,9081 .param_types = param_types,
...@@ -9059,6 +9092,8 @@ fn funcCommon(...@@ -9059,6 +9092,8 @@ fn funcCommon(
9059 .lbrace_column = @as(u16, @truncate(src_locs.columns)),9092 .lbrace_column = @as(u16, @truncate(src_locs.columns)),
9060 .rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)),9093 .rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)),
9061 }));9094 }));
9095 try sema.ensureLayoutResolved(func_val.typeOf(zcu));
9096 return .fromValue(func_val);
9062 }9097 }
90639098
9064 const func_ty = try ip.getFuncType(gpa, io, pt.tid, .{9099 const func_ty = try ip.getFuncType(gpa, io, pt.tid, .{
...@@ -9072,6 +9107,7 @@ fn funcCommon(...@@ -9072,6 +9107,7 @@ fn funcCommon(
9072 });9107 });
90739108
9074 if (has_body) {9109 if (has_body) {
9110 try sema.ensureLayoutResolved(.fromInterned(func_ty));
9075 return .fromIntern(try ip.getFuncDecl(gpa, io, pt.tid, .{9111 return .fromIntern(try ip.getFuncDecl(gpa, io, pt.tid, .{
9076 .owner_nav = sema.owner.unwrap().nav_val,9112 .owner_nav = sema.owner.unwrap().nav_val,
9077 .ty = func_ty,9113 .ty = func_ty,
...@@ -9109,7 +9145,7 @@ fn zirParam(...@@ -9109,7 +9145,7 @@ fn zirParam(
9109 }9145 }
91109146
9111 const param_ty_inst = try sema.resolveInlineBody(block, body, inst);9147 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);
9113 };9149 };
91149150
9115 try block.params.append(sema.arena, .{9151 try block.params.append(sema.arena, .{
...@@ -9948,6 +9984,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp...@@ -9948,6 +9984,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
9948 err_union_ty.fmt(pt),9984 err_union_ty.fmt(pt),
9949 });9985 });
9950 }9986 }
9987 try sema.ensureLayoutResolved(err_union_ty);
99519988
9952 const non_err_cond = if (non_err_case.operand_is_ref)9989 const non_err_cond = if (non_err_case.operand_is_ref)
9953 try sema.analyzePtrIsNonErr(block, operand_src, eu_maybe_ptr)9990 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....@@ -12924,7 +12961,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
12924 const res_ty: InternPool.Index = b: {12961 const res_ty: InternPool.Index = b: {
12925 if (extra.res_ty == .none) break :b .none;12962 if (extra.res_ty == .none) break :b .none;
12926 const res_ty_inst = try sema.resolveInst(extra.res_ty);12963 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);
12928 if (res_ty.isGenericPoison()) break :b .none;12965 if (res_ty.isGenericPoison()) break :b .none;
12929 break :b res_ty.toIntern();12966 break :b res_ty.toIntern();
12930 };12967 };
...@@ -15683,8 +15720,8 @@ fn zirCmpEq(...@@ -15683,8 +15720,8 @@ fn zirCmpEq(
15683 return block.addBinOp(air_tag, lhs, rhs);15720 return block.addBinOp(air_tag, lhs, rhs);
15684 }15721 }
15685 if (lhs_ty_tag == .type and rhs_ty_tag == .type) {15722 if (lhs_ty_tag == .type and rhs_ty_tag == .type) {
15686 const lhs_as_type = try sema.analyzeAsType(block, lhs_src, lhs);15723 const lhs_as_type = try sema.analyzeAsType(block, lhs_src, .type, lhs);
15687 const rhs_as_type = try sema.analyzeAsType(block, rhs_src, rhs);15724 const rhs_as_type = try sema.analyzeAsType(block, rhs_src, .type, rhs);
15688 return if (lhs_as_type.eql(rhs_as_type, zcu) == (op == .eq)) .bool_true else .bool_false;15725 return if (lhs_as_type.eql(rhs_as_type, zcu) == (op == .eq)) .bool_true else .bool_false;
15689 }15726 }
15690 return sema.analyzeCmp(block, src, lhs, rhs, op, lhs_src, rhs_src, true);15727 return sema.analyzeCmp(block, src, lhs, rhs, op, lhs_src, rhs_src, true);
...@@ -15979,16 +16016,7 @@ fn zirThis(...@@ -15979,16 +16016,7 @@ fn zirThis(
15979 extended: Zir.Inst.Extended.InstData,16016 extended: Zir.Inst.Extended.InstData,
15980) CompileError!Air.Inst.Ref {16017) CompileError!Air.Inst.Ref {
15981 _ = extended;16018 _ = extended;
15982 const zcu = sema.pt.zcu;16019 return .fromIntern(sema.pt.zcu.namespacePtr(block.namespace).owner_type);
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);
15992}16020}
1599316021
15994fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {16022fn 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...@@ -16224,12 +16252,12 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
16224 const type_info_ty = try sema.getBuiltinType(src, .Type);16252 const type_info_ty = try sema.getBuiltinType(src, .Type);
16225 const type_info_tag_ty = type_info_ty.unionTagType(zcu).?;16253 const type_info_tag_ty = type_info_ty.unionTagType(zcu).?;
1622616254
16255 try sema.ensureLayoutResolved(ty);
16256
16227 if (ty.typeDeclInst(zcu)) |type_decl_inst| {16257 if (ty.typeDeclInst(zcu)) |type_decl_inst| {
16228 try sema.declareDependency(.{ .namespace = type_decl_inst });16258 try sema.declareDependency(.{ .namespace = type_decl_inst });
16229 }16259 }
1623016260
16231 try sema.ensureLayoutResolved(ty);
16232
16233 switch (ty.zigTypeTag(zcu)) {16261 switch (ty.zigTypeTag(zcu)) {
16234 .type,16262 .type,
16235 .void,16263 .void,
...@@ -16240,7 +16268,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -16240,7 +16268,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
16240 .undefined,16268 .undefined,
16241 .null,16269 .null,
16242 .enum_literal,16270 .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
16245 .@"fn" => {16280 .@"fn" => {
16246 const fn_info_ty = try sema.getBuiltinType(src, .@"Type.Fn");16281 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...@@ -16248,9 +16283,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1624816283
16249 const func_ty_info = zcu.typeToFunc(ty).?;16284 const func_ty_info = zcu.typeToFunc(ty).?;
16250 const param_vals = try sema.arena.alloc(InternPool.Index, func_ty_info.param_types.len);16285 const param_vals = try sema.arena.alloc(InternPool.Index, func_ty_info.param_types.len);
16286 var func_is_generic = false;
16251 for (param_vals, 0..) |*param_val, i| {16287 for (param_vals, 0..) |*param_val, i| {
16252 const param_ty = func_ty_info.param_types.get(ip)[i];16288 const param_ty = func_ty_info.param_types.get(ip)[i];
16253 const is_generic = param_ty == .generic_poison_type;16289 const is_generic = param_ty == .generic_poison_type;
16290 if (is_generic or Type.fromInterned(param_ty).comptimeOnly(zcu)) func_is_generic = true;
16254 const param_ty_val = try pt.intern(.{ .opt = .{16291 const param_ty_val = try pt.intern(.{ .opt = .{
16255 .ty = try pt.intern(.{ .opt_type = .type_type }),16292 .ty = try pt.intern(.{ .opt_type = .type_type }),
16256 .val = if (is_generic) .none else param_ty,16293 .val = if (is_generic) .none else param_ty,
...@@ -16300,18 +16337,21 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -16300,18 +16337,21 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
16300 } });16337 } });
16301 };16338 };
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
16303 const ret_ty_opt = try pt.intern(.{ .opt = .{16352 const ret_ty_opt = try pt.intern(.{ .opt = .{
16304 .ty = try pt.intern(.{ .opt_type = .type_type }),16353 .ty = try pt.intern(.{ .opt_type = .type_type }),
16305 .val = opt_val: {16354 .val = if (ret_ty_is_generic) .none else func_ty_info.return_type,
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 },
16315 } });16355 } });
1631616356
16317 const callconv_ty = try sema.getBuiltinType(src, .CallingConvention);16357 const callconv_ty = try sema.getBuiltinType(src, .CallingConvention);
...@@ -16320,9 +16360,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -16320,9 +16360,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
16320 error.OutOfMemory => |e| return e,16360 error.OutOfMemory => |e| return e,
16321 };16361 };
1632216362
16323 // MLUGG TODO
16324 const func_is_generic = false;
16325
16326 const field_values: [5]InternPool.Index = .{16363 const field_values: [5]InternPool.Index = .{
16327 // calling_convention: CallingConvention,16364 // calling_convention: CallingConvention,
16328 callconv_val.toIntern(),16365 callconv_val.toIntern(),
...@@ -16837,7 +16874,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -16837,7 +16874,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
16837 .struct_type => ip.loadStructType(ty.toIntern()),16874 .struct_type => ip.loadStructType(ty.toIntern()),
16838 else => unreachable,16875 else => unreachable,
16839 };16876 };
16840 try sema.ensureFieldInitsResolved(ty); // can't do this sooner, since it's not allowed on tuples16877 try sema.ensureStructDefaultsResolved(ty); // can't do this sooner, since it's not allowed on tuples
16841 struct_field_vals = try gpa.alloc(InternPool.Index, struct_type.field_types.len);16878 struct_field_vals = try gpa.alloc(InternPool.Index, struct_type.field_types.len);
1684216879
16843 for (struct_field_vals, 0..) |*field_val, field_index| {16880 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...@@ -18193,7 +18230,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1819318230
18194 const elem_ty = blk: {18231 const elem_ty = blk: {
18195 const air_inst = try sema.resolveInst(extra.data.elem_type);18232 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| {
18197 if (err == error.AnalysisFail and sema.err != null and sema.typeOf(air_inst).isSinglePointer(zcu)) {18234 if (err == error.AnalysisFail and sema.err != null and sema.typeOf(air_inst).isSinglePointer(zcu)) {
18198 try sema.errNote(elem_ty_src, sema.err.?, "use '.*' to dereference pointer", .{});18235 try sema.errNote(elem_ty_src, sema.err.?, "use '.*' to dereference pointer", .{});
18199 }18236 }
...@@ -18274,7 +18311,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -18274,7 +18311,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
18274 } else if (inst_data.size != .one and elem_ty.zigTypeTag(zcu) == .@"opaque") {18311 } else if (inst_data.size != .one and elem_ty.zigTypeTag(zcu) == .@"opaque") {
18275 return sema.fail(block, elem_ty_src, "indexable pointer to opaque type '{f}' not allowed", .{elem_ty.fmt(pt)});18312 return sema.fail(block, elem_ty_src, "indexable pointer to opaque type '{f}' not allowed", .{elem_ty.fmt(pt)});
18276 } else if (inst_data.size == .c) {18313 } else if (inst_data.size == .c) {
18277 if (!try sema.validateExternType(elem_ty, .other)) {18314 if (!elem_ty.validateExtern(.other, zcu)) {
18278 const msg = msg: {18315 const msg = msg: {
18279 const msg = try sema.errMsg(elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)});18316 const msg = try sema.errMsg(elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)});
18280 errdefer msg.destroy(sema.gpa);18317 errdefer msg.destroy(sema.gpa);
...@@ -18288,11 +18325,11 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -18288,11 +18325,11 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
18288 }18325 }
18289 }18326 }
1829018327
18291 if (host_size != 0 and !elem_ty.packable(zcu)) {18328 if (host_size != 0) {
18292 return sema.failWithOwnedErrorMsg(block, msg: {18329 if (elem_ty.unpackable(zcu)) |reason| return sema.failWithOwnedErrorMsg(block, msg: {
18293 const msg = try sema.errMsg(elem_ty_src, "bit-pointer cannot refer to value of type '{f}'", .{elem_ty.fmt(pt)});18330 const msg = try sema.errMsg(elem_ty_src, "bit-pointer cannot refer to value of type '{f}'", .{elem_ty.fmt(pt)});
18294 errdefer msg.destroy(sema.gpa);18331 errdefer msg.destroy(sema.gpa);
18295 try sema.explainWhyTypeIsNotPackable(msg, elem_ty_src, elem_ty);18332 try sema.explainWhyTypeIsUnpackable(msg, elem_ty_src, reason);
18296 break :msg msg;18333 break :msg msg;
18297 });18334 });
18298 }18335 }
...@@ -18455,63 +18492,32 @@ fn arrayInitEmpty(sema: *Sema, block: *Block, src: LazySrcLoc, obj_ty: Type) Com...@@ -18455,63 +18492,32 @@ fn arrayInitEmpty(sema: *Sema, block: *Block, src: LazySrcLoc, obj_ty: Type) Com
1845518492
18456fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {18493fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
18457 const pt = sema.pt;18494 const pt = sema.pt;
18495 const zcu = pt.zcu;
18496 const ip = &zcu.intern_pool;
18458 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;18497 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
18459 const ty_src = block.builtinCallArgSrc(inst_data.src_node, 0);18498 const ty_src = block.builtinCallArgSrc(inst_data.src_node, 0);
18460 const field_src = block.builtinCallArgSrc(inst_data.src_node, 1);18499 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);
18462 const extra = sema.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data;18501 const extra = sema.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data;
18463 const union_ty = try sema.resolveType(block, ty_src, extra.union_type);18502 const union_ty = try sema.resolveType(block, ty_src, extra.union_type);
18464 if (union_ty.zigTypeTag(pt.zcu) != .@"union") {18503 if (union_ty.zigTypeTag(pt.zcu) != .@"union") {
18465 return sema.fail(block, ty_src, "expected union type, found '{f}'", .{union_ty.fmt(pt)});18504 return sema.fail(block, ty_src, "expected union type, found '{f}'", .{union_ty.fmt(pt)});
18466 }18505 }
18506 union_ty.assertHasLayout(zcu); // from a previous `field_type_ref` instruction
18467 const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, .{ .simple = .union_field_names });18507 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;
18485 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src);18508 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src);
18486 const field_ty: Type = .fromInterned(zcu.typeToUnion(union_ty).?.field_types.get(ip)[field_index]);18509 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(18511 const payload = try sema.coerce(block, field_ty, try sema.resolveInst(extra.init), payload_src);
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;
1850218512
18503 if (try sema.resolveValue(init)) |init_val| {18513 if (try sema.resolveValue(payload)) |payload_val| {
18504 const tag_ty = union_ty.unionTagTypeHypothetical(zcu);18514 const tag_ty = union_ty.unionTagTypeHypothetical(zcu);
18505 const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index);18515 const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index);
18506 return Air.internedToRef((try pt.internUnion(.{18516 return .fromValue(try pt.unionValue(union_ty, tag_val, payload_val));
18507 .ty = union_ty.toIntern(),
18508 .tag = tag_val.toIntern(),
18509 .val = init_val.toIntern(),
18510 })));
18511 }18517 }
1851218518
18513 try sema.requireRuntimeBlock(block, init_src, null);18519 try sema.requireRuntimeBlock(block, payload_src, null);
18514 return block.addUnionInit(union_ty, field_index, init);18520 return block.addUnionInit(union_ty, field_index, payload);
18515}18521}
1851618522
18517fn zirStructInit(18523fn zirStructInit(
...@@ -18588,9 +18594,6 @@ fn zirStructInit(...@@ -18588,9 +18594,6 @@ fn zirStructInit(
18588 const field_ty = resolved_ty.fieldType(field_index, zcu);18594 const field_ty = resolved_ty.fieldType(field_index, zcu);
18589 field_inits[field_index] = try sema.coerce(block, field_ty, uncoerced_init, field_src);18595 field_inits[field_index] = try sema.coerce(block, field_ty, uncoerced_init, field_src);
18590 if (resolved_ty.structFieldIsComptime(field_index, zcu)) {18596 if (resolved_ty.structFieldIsComptime(field_index, zcu)) {
18591 if (!resolved_ty.isTuple(zcu)) {
18592 try sema.ensureFieldInitsResolved(resolved_ty);
18593 }
18594 const default_value = (try resolved_ty.structFieldValueComptime(pt, field_index)).?;18597 const default_value = (try resolved_ty.structFieldValueComptime(pt, field_index)).?;
18595 const init_val = (try sema.resolveValue(field_inits[field_index])) orelse {18598 const init_val = (try sema.resolveValue(field_inits[field_index])) orelse {
18596 return sema.failWithNeededComptime(block, field_src, .{ .simple = .stored_to_comptime_field });18599 return sema.failWithNeededComptime(block, field_src, .{ .simple = .stored_to_comptime_field });
...@@ -18744,7 +18747,12 @@ fn finishStructInit(...@@ -18744,7 +18747,12 @@ fn finishStructInit(
18744 continue;18747 continue;
18745 }18748 }
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
18749 const field_default: InternPool.Index = d: {18757 const field_default: InternPool.Index = d: {
18750 if (struct_type.field_defaults.len == 0) break :d .none;18758 if (struct_type.field_defaults.len == 0) break :d .none;
...@@ -18935,55 +18943,54 @@ fn structInitAnon(...@@ -18935,55 +18943,54 @@ fn structInitAnon(
18935 break :hash hasher.final();18943 break :hash hasher.final();
18936 };18944 };
18937 const tracked_inst = try block.trackZir(inst);18945 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,
18939 .fields_len = extra_data.fields_len,18949 .fields_len = extra_data.fields_len,
18940 .layout = .auto,18950 .layout = .auto,
18941 .explicit_packed_backing_type = .none,
18942 .any_comptime_fields = any_values,18951 .any_comptime_fields = any_values,
18943 .any_field_defaults = any_values,18952 .any_field_defaults = any_values,
18944 .any_field_aligns = false,18953 .any_field_aligns = false,
18945 .key = .{ .reified = .{18954 .packed_backing_int_type = .none,
18946 .zir_index = tracked_inst,
18947 .type_hash = type_hash,
18948 } },
18949 })) {18955 })) {
18956 .existing => |ty| .fromInterned(ty),
18950 .wip => |wip| ty: {18957 .wip => |wip| ty: {
18951 errdefer wip.cancel(ip, pt.tid);18958 errdefer wip.cancel(ip, pt.tid);
18952 // MLUGG TODO obvs this sux18959 try sema.setTypeName(block, &wip, .anon, "struct", inst);
18953 const anon_prefix = (try sema.createTypeName(block, .anon, "struct", inst)).anon_prefix;18960
18954 wip.setName(ip, try ip.getOrPutStringFmt(gpa, io, pt.tid, "{s}_{d}", .{ anon_prefix, @intFromEnum(wip.index) }, .no_embedded_nulls), .none);18961 // Reified structs have field information populated immediately.
1895518962 @memcpy(wip.field_names.get(ip), names);
18956 const struct_type = ip.loadStructType(wip.index);18963 @memcpy(wip.field_types.get(ip), types);
1895718964 if (any_values) {
18958 for (names, values) |name, init_val| {18965 @memcpy(wip.field_values.get(ip), values);
18959 assert(wip.nextField(ip, name, init_val != .none) == null); // AstGen validated no duplicates for us18966 @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 }
18960 }18973 }
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
18969 const new_namespace_index = try pt.createNamespace(.{18975 const new_namespace_index = try pt.createNamespace(.{
18970 .parent = block.namespace.toOptional(),18976 .parent = block.namespace.toOptional(),
18971 .owner_type = wip.index,18977 .owner_type = wip.index,
18972 .file_scope = block.getFileScopeIndex(zcu),18978 .file_scope = block.getFileScopeIndex(zcu),
18973 .generation = zcu.generation,18979 .generation = zcu.generation,
18974 });18980 });
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 }
18981 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);18981 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
18982 break :ty .fromInterned(wip.finish(ip, new_namespace_index));18989 break :ty .fromInterned(wip.finish(ip, new_namespace_index));
18983 },18990 },
18984 .existing => |ty| .fromInterned(ty),
18985 };18991 };
18986 try sema.addTypeReferenceEntry(src, struct_ty);18992 try sema.addTypeReferenceEntry(src, struct_ty);
18993 try sema.ensureLayoutResolved(struct_ty);
1898718994
18988 _ = opt_runtime_index orelse {18995 _ = opt_runtime_index orelse {
18989 const struct_val = try pt.aggregateValue(struct_ty, values);18996 const struct_val = try pt.aggregateValue(struct_ty, values);
...@@ -19338,6 +19345,7 @@ fn fieldType(...@@ -19338,6 +19345,7 @@ fn fieldType(
19338 const pt = sema.pt;19345 const pt = sema.pt;
19339 const zcu = pt.zcu;19346 const zcu = pt.zcu;
19340 const ip = &zcu.intern_pool;19347 const ip = &zcu.intern_pool;
19348 aggregate_ty.assertHasLayout(zcu);
19341 var cur_ty = aggregate_ty;19349 var cur_ty = aggregate_ty;
19342 while (true) {19350 while (true) {
19343 switch (cur_ty.zigTypeTag(zcu)) {19351 switch (cur_ty.zigTypeTag(zcu)) {
...@@ -19397,7 +19405,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {...@@ -19397,7 +19405,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
19397 .func => |func| if (ip.funcAnalysisUnordered(func).has_error_trace and block.ownerModule().error_tracing) {19405 .func => |func| if (ip.funcAnalysisUnordered(func).has_error_trace and block.ownerModule().error_tracing) {
19398 return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty);19406 return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty);
19399 },19407 },
19400 .@"comptime", .nav_ty, .nav_val, .type_layout, .type_inits, .memoized_state => {},19408 .@"comptime", .nav_ty, .nav_val, .type_layout, .struct_defaults, .memoized_state => {},
19401 }19409 }
19402 return Air.internedToRef(try pt.intern(.{ .opt = .{19410 return Air.internedToRef(try pt.intern(.{ .opt = .{
19403 .ty = opt_ptr_stack_trace_ty.toIntern(),19411 .ty = opt_ptr_stack_trace_ty.toIntern(),
...@@ -19823,7 +19831,7 @@ fn zirReifyPointer(...@@ -19823,7 +19831,7 @@ fn zirReifyPointer(
19823 else => {},19831 else => {},
19824 }19832 }
1982519833
19826 if (size == .c and !try sema.validateExternType(elem_ty, .other)) {19834 if (size == .c and !elem_ty.validateExtern(.other, zcu)) {
19827 return sema.failWithOwnedErrorMsg(block, msg: {19835 return sema.failWithOwnedErrorMsg(block, msg: {
19828 const msg = try sema.errMsg(src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)});19836 const msg = try sema.errMsg(src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)});
19829 errdefer msg.destroy(gpa);19837 errdefer msg.destroy(gpa);
...@@ -19988,6 +19996,7 @@ fn zirReifyStruct(...@@ -19988,6 +19996,7 @@ fn zirReifyStruct(
19988 const name_strategy: Zir.Inst.NameStrategy = @enumFromInt(extended.small);19996 const name_strategy: Zir.Inst.NameStrategy = @enumFromInt(extended.small);
19989 const extra = sema.code.extraData(Zir.Inst.ReifyStruct, extended.operand).data;19997 const extra = sema.code.extraData(Zir.Inst.ReifyStruct, extended.operand).data;
19990 const tracked_inst = try block.trackZir(inst);19998 const tracked_inst = try block.trackZir(inst);
19999
19991 const src: LazySrcLoc = .{20000 const src: LazySrcLoc = .{
19992 .base_node_inst = tracked_inst,20001 .base_node_inst = tracked_inst,
19993 .offset = .nodeOffset(.zero),20002 .offset = .nodeOffset(.zero),
...@@ -20039,7 +20048,7 @@ fn zirReifyStruct(...@@ -20039,7 +20048,7 @@ fn zirReifyStruct(
2003920048
20040 const backing_int_ty_uncoerced = try sema.resolveInst(extra.backing_ty);20049 const backing_int_ty_uncoerced = try sema.resolveInst(extra.backing_ty);
20041 const backing_int_ty_coerced = try sema.coerce(block, .optional_type, backing_int_ty_uncoerced, backing_ty_src);20050 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
20044 const field_names_uncoerced = try sema.resolveInst(extra.field_names);20053 const field_names_uncoerced = try sema.resolveInst(extra.field_names);
20045 const field_names_coerced = try sema.coerce(block, .slice_const_slice_const_u8, field_names_uncoerced, field_names_src);20054 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(...@@ -20079,19 +20088,30 @@ fn zirReifyStruct(
20079 return sema.failWithUseOfUndef(block, backing_ty_src, null);20088 return sema.failWithUseOfUndef(block, backing_ty_src, null);
20080 }20089 }
2008120090
20082 // The validation work here is non-trivial, and it's possible the type already exists.20091 // Most validation of this type happens during type resolution. We basically need to do the work
20083 // So in this first pass, let's just construct a hash to optimize for this case. If the20092 // which AstGen would normally do. An exception is checking for duplicate field names, which is
20084 // inputs turn out to be invalid, we can cancel the WIP type later.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
20086 var any_comptime_fields = false;20098 var any_comptime_fields = false;
20087 var any_default_inits = false;20099 var any_field_defaults = false;
20088 var any_aligned_fields = false;20100 var any_field_aligns = false;
2008920101
20090 // For deduplication purposes, we must create a hash including all details of this type.
20091 // TODO: use a longer hash!20102 // TODO: use a longer hash!
20092 var hasher = std.hash.Wyhash.init(0);20103 var hasher = std.hash.Wyhash.init(0);
20093 std.hash.autoHash(&hasher, layout);20104 std.hash.autoHash(&hasher, layout);
20094 std.hash.autoHash(&hasher, backing_int_ty_val);20105 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
20095 // The field *type* array has already been deduplicated for us thanks to the InternPool!20115 // The field *type* array has already been deduplicated for us thanks to the InternPool!
20096 std.hash.autoHash(&hasher, field_types_arr);20116 std.hash.autoHash(&hasher, field_types_arr);
20097 // However, for field names and attributes, we need to actually iterate the individual fields,20117 // However, for field names and attributes, we need to actually iterate the individual fields,
...@@ -20126,201 +20146,126 @@ fn zirReifyStruct(...@@ -20126,201 +20146,126 @@ fn zirReifyStruct(
20126 field_attrs_src,20146 field_attrs_src,
20127 .{ .simple = .struct_field_default_value },20147 .{ .simple = .struct_field_default_value },
20128 );20148 );
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;
20129 break :d deref_val.toIntern();20153 break :d deref_val.toIntern();
20130 };20154 };
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
20132 std.hash.autoHash(&hasher, .{20175 std.hash.autoHash(&hasher, .{
20133 field_name,20176 field_name,
20134 field_attr_comptime,20177 field_attr_comptime,
20135 field_attr_align,20178 field_attr_align,
20136 field_default,20179 field_default,
20137 });20180 });
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});
20157 }20181 }
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(),
20160 .fields_len = @intCast(fields_len),20186 .fields_len = @intCast(fields_len),
20161 .layout = layout,20187 .layout = layout,
20162 .explicit_packed_backing_type = if (backing_int_ty) |t| t.toIntern() else .none,
20163 .any_comptime_fields = any_comptime_fields,20188 .any_comptime_fields = any_comptime_fields,
20164 .any_field_defaults = any_default_inits,20189 .any_field_defaults = any_field_defaults,
20165 .any_field_aligns = any_aligned_fields,20190 .any_field_aligns = any_field_aligns,
20166 .key = .{ .reified = .{20191 .packed_backing_int_type = if (backing_int_ty) |ty| ty.toIntern() else .none,
20167 .zir_index = tracked_inst,
20168 .type_hash = hasher.final(),
20169 } },
20170 })) {20192 })) {
20171 .wip => |wip| wip,
20172 .existing => |ty| {20193 .existing => |ty| {
20173 try sema.addTypeReferenceEntry(src, .fromInterned(ty));20194 try sema.addTypeReferenceEntry(src, .fromInterned(ty));
20174 return .fromIntern(ty);20195 return .fromIntern(ty);
20175 },20196 },
20176 };20197 .wip => |wip| {
20177 errdefer wip_ty.cancel(ip, pt.tid);20198 errdefer wip.cancel(ip, pt.tid);
2017820199 try sema.setTypeName(block, &wip, name_strategy, "struct", inst);
20179 _ = try (try sema.createTypeName(20200 for (0..fields_len) |field_idx| {
20180 block,20201 const field_name_val = try field_names_arr.elemValue(pt, field_idx);
20181 name_strategy,20202 const field_attrs_val = try field_attrs_arr.elemValue(pt, field_idx);
20182 "struct",20203
20183 inst,20204 // No source location or reason; first loop checked this is valid.
20184 )).apply(&wip_ty, pt);20205 const field_name = try sema.sliceToIpString(block, .unneeded, field_name_val, undefined);
2018520206 wip.field_names.get(ip)[field_idx] = field_name;
20186 const wip_struct_type = ip.loadStructType(wip_ty.index);20207
2018720208 const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType();
20188 for (0..fields_len) |field_idx| {20209 wip.field_types.get(ip)[field_idx] = field_ty.toIntern();
20189 const field_name_val = try field_names_arr.elemValue(pt, field_idx);20210
20190 const field_attrs_val = try field_attrs_arr.elemValue(pt, field_idx);20211 const field_attr_comptime = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
2019120212 std.builtin.Type.StructField.Attributes,
20192 // Don't pass a reason; first loop acts as a check that this is valid.20213 "comptime",
20193 const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined);20214 ).?);
20194 const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType();20215 const field_attr_align = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
20195 const field_attr_comptime = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(20216 std.builtin.Type.StructField.Attributes,
20196 std.builtin.Type.StructField.Attributes,20217 "align",
20197 "comptime",20218 ).?);
20198 ).?);20219 const field_attr_default_value_ptr = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
20199 const field_attr_align = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(20220 std.builtin.Type.StructField.Attributes,
20200 std.builtin.Type.StructField.Attributes,20221 "default_value_ptr",
20201 "align",20222 ).?);
20202 ).?);20223
20203 const field_attr_default_value_ptr = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(20224 if (field_attr_comptime.toBool()) {
20204 std.builtin.Type.StructField.Attributes,20225 const bit_bag_index = field_idx / 32;
20205 "default_value_ptr",20226 const mask = @as(u32, 1) << @intCast(field_idx % 32);
20206 ).?);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| {20230 if (field_attr_default_value_ptr.optionalValue(zcu)) |ptr_val| {
20209 _ = prev_index; // TODO: better source location20231 const ptr_ty = try pt.singleConstPtrType(field_ty);
20210 return sema.fail(block, field_names_src, "duplicate struct field name {f}", .{field_name.fmt(ip)});20232 // No source location; first loop checked this is valid.
20211 }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: {20239 if (field_attr_align.optionalValue(zcu)) |field_align_val| {
20214 const ptr_val = field_attr_default_value_ptr.optionalValue(zcu) orelse break :d .none;20240 const bytes = field_align_val.toUnsignedInt(zcu);
20215 assert(any_default_inits);20241 // No source location; first loop checked this is valid.
20216 const ptr_ty = try pt.singleConstPtrType(field_ty);20242 const a = try sema.validateAlign(block, .unneeded, bytes);
20217 // The first loop checked that this is comptime-dereferencable.20243 wip.field_aligns.get(ip)[field_idx] = a;
20218 const deref_val = (try sema.pointerDeref(block, field_attrs_src, ptr_val, ptr_ty)).?;20244 } else if (any_field_aligns) {
20219 // ...but we've not checked this yet!20245 wip.field_aligns.get(ip)[field_idx] = .none;
20220 if (deref_val.canMutateComptimeVarState(zcu)) {20246 }
20221 return sema.failWithContainsReferenceToComptimeVar(block, field_attrs_src, field_name, "field default value", deref_val);
20222 }20247 }
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") {20249 const new_namespace_index = try pt.createNamespace(.{
20285 var field_bits: u64 = 0;20250 .parent = block.namespace.toOptional(),
20286 for (0..fields_len) |field_idx| {20251 .owner_type = wip.index,
20287 const field_ty: Type = .fromInterned(wip_struct_type.field_types.get(ip)[field_idx]);20252 .file_scope = block.getFileScopeIndex(zcu),
20288 try sema.ensureLayoutResolved(field_ty);20253 .generation = zcu.generation,
20289 field_bits += field_ty.bitSize(zcu);20254 });
20290 }20255 try sema.addTypeReferenceEntry(src, .fromInterned(wip.index));
20291 try type_resolution.resolvePackedStructBackingInt(20256 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
20292 sema,20257 // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind
20293 block,20258 try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) });
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 }
2030720259
20308 const new_namespace_index = try pt.createNamespace(.{20260 try zcu.outdated.ensureUnusedCapacity(gpa, 1);
20309 .parent = block.namespace.toOptional(),20261 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1);
20310 .owner_type = wip_ty.index,20262 errdefer comptime unreachable; // because we don't remove the `outdated` entries
20311 .file_scope = block.getFileScopeIndex(zcu),20263 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0);
20312 .generation = zcu.generation,20264 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {});
20313 });
2031420265
20315 codegen_type: {20266 return .fromIntern(wip.finish(ip, new_namespace_index));
20316 if (zcu.comp.config.use_llvm) break :codegen_type;20267 },
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 });
20320 }20268 }
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));
20324}20269}
2032520270
20326fn zirReifyUnion(20271fn zirReifyUnion(
...@@ -20390,7 +20335,10 @@ fn zirReifyUnion(...@@ -20390,7 +20335,10 @@ fn zirReifyUnion(
2039020335
20391 const arg_ty_uncoerced = try sema.resolveInst(extra.arg_ty);20336 const arg_ty_uncoerced = try sema.resolveInst(extra.arg_ty);
20392 const arg_ty_coerced = try sema.coerce(block, .optional_type, arg_ty_uncoerced, arg_ty_src);20337 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
20395 const field_names_uncoerced = try sema.resolveInst(extra.field_names);20343 const field_names_uncoerced = try sema.resolveInst(extra.field_names);
20396 const field_names_coerced = try sema.coerce(block, .slice_const_slice_const_u8, field_names_uncoerced, field_names_src);20344 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(...@@ -20430,17 +20378,29 @@ fn zirReifyUnion(
20430 return sema.failWithUseOfUndef(block, arg_ty_src, null);20378 return sema.failWithUseOfUndef(block, arg_ty_src, null);
20431 }20379 }
2043220380
20433 // The validation work here is non-trivial, and it's possible the type already exists.20381 // Most validation of this type happens during type resolution. We basically need to do the work
20434 // So in this first pass, let's just construct a hash to optimize for this case. If the20382 // which AstGen would normally do. An exception is checking for duplicate field names, which is
20435 // inputs turn out to be invalid, we can cancel the WIP type later.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.
20440 // TODO: use a longer hash!20390 // TODO: use a longer hash!
20441 var hasher = std.hash.Wyhash.init(0);20391 var hasher = std.hash.Wyhash.init(0);
20442 std.hash.autoHash(&hasher, layout);20392 std.hash.autoHash(&hasher, layout);
20443 std.hash.autoHash(&hasher, arg_ty_val);20393 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
20444 // `field_types_arr` and `field_attrs_arr` are already deduplicated by the InternPool!20404 // `field_types_arr` and `field_attrs_arr` are already deduplicated by the InternPool!
20445 std.hash.autoHash(&hasher, field_types_arr);20405 std.hash.autoHash(&hasher, field_types_arr);
20446 std.hash.autoHash(&hasher, field_attrs_arr);20406 std.hash.autoHash(&hasher, field_attrs_arr);
...@@ -20457,249 +20417,84 @@ fn zirReifyUnion(...@@ -20457,249 +20417,84 @@ fn zirReifyUnion(
20457 try field_attrs_arr.elemValue(pt, field_idx),20417 try field_attrs_arr.elemValue(pt, field_idx),
20458 std.builtin.Type.UnionField.Attributes,20418 std.builtin.Type.UnionField.Attributes,
20459 );20419 );
20460 if (field_attrs.@"align" != null) {20420 if (field_attrs.@"align") |bytes| {
20461 any_aligned_fields = true;20421 if (layout == .@"packed") {
20462 }20422 return sema.fail(block, field_attrs_src, "packed union fields cannot be aligned", .{});
20463 }20423 }
2046420424 // Trigger a compile error if the alignment is invalid.
20465 // Some basic validation to avoid a bogus `getUnionType` call...20425 _ = try sema.validateAlign(block, field_attrs_src, bytes);
20466 const explicit_tag_ty: ?Type, const explicit_packed_backing_type: ?Type = ty: {20426 any_field_aligns = true;
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 },
20472 }20427 }
20473 };
20474 if (any_aligned_fields and layout == .@"packed") {
20475 return sema.fail(block, field_attrs_src, "packed union fields cannot be aligned", .{});
20476 }20428 }
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(),
20479 .fields_len = @intCast(fields_len),20433 .fields_len = @intCast(fields_len),
20480 .layout = layout,20434 .layout = layout,
20481 .explicit_packed_backing_type = if (explicit_packed_backing_type) |t| t.toIntern() else .none,20435 .any_field_aligns = any_field_aligns,
20482 .runtime_tag = rt: {20436 .runtime_tag = rt: {
20483 if (explicit_tag_ty != null) break :rt .tagged;20437 if (explicit_tag_ty != null) break :rt .tagged;
20484 if (layout == .auto and block.wantSafeTypes()) break :rt .safety;20438 if (layout == .auto and block.wantSafeTypes()) break :rt .safety;
20485 break :rt .none;20439 break :rt .none;
20486 },20440 },
20487 .have_explicit_enum_tag = explicit_tag_ty != null,20441 .enum_tag_type = if (explicit_tag_ty) |ty| ty.toIntern() else .none,
20488 .any_field_aligns = any_aligned_fields,20442 .packed_backing_int_type = if (explicit_packed_backing_type) |ty| ty.toIntern() else .none,
20489 .key = .{ .reified = .{
20490 .zir_index = tracked_inst,
20491 .type_hash = hasher.final(),
20492 } },
20493 })) {20443 })) {
20494 .wip => |wip| wip,
20495 .existing => |ty| {20444 .existing => |ty| {
20496 try sema.addTypeReferenceEntry(src, .fromInterned(ty));20445 try sema.addTypeReferenceEntry(src, .fromInterned(ty));
20497 return .fromIntern(ty);20446 return .fromIntern(ty);
20498 },20447 },
20499 };20448 .wip => |wip| {
20500 errdefer wip_ty.cancel(ip, pt.tid);20449 errdefer wip.cancel(ip, pt.tid);
2050120450 try sema.setTypeName(block, &wip, name_strategy, "union", inst);
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);
2051720451
20518 for (0..fields_len) |field_idx| {20452 for (0..fields_len) |field_idx| {
20519 const field_name_val = try field_names_arr.elemValue(pt, field_idx);20453 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.20454 // No source location or reason; first loop checked this is valid.
20521 const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined);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) {20458 const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType();
20524 return sema.fail(block, field_names_src, "no field named '{f}' in enum '{f}'", .{20459 wip.field_types.get(ip)[field_idx] = field_ty.toIntern();
20525 field_name.fmt(ip), enum_tag_ty.fmt(pt),
20526 });
20527 }
2052820460
20529 const enum_field_name = enum_tag_ty.enumFieldName(field_idx, zcu);20461 // No source location; first loop checked this is valid.
20530 if (enum_field_name != field_name) {20462 const field_attrs = try sema.interpretBuiltinType(
20531 return sema.fail(block, field_names_src, "union field name '{f}' does not match enum field name '{f}'", .{20463 block,
20532 field_name.fmt(ip), enum_field_name.fmt(ip),20464 .unneeded,
20533 });20465 try field_attrs_arr.elemValue(pt, field_idx),
20534 }20466 std.builtin.Type.UnionField.Attributes,
20535 }20467 );
20536 if (tag_ty_fields_len > fields_len) return sema.failWithOwnedErrorMsg(block, msg: {20468 if (field_attrs.@"align") |bytes| {
20537 const msg = try sema.errMsg(field_names_src, "{d} enum fields missing in union", .{20469 // No source location; first loop checked this is valid.
20538 tag_ty_fields_len - fields_len,20470 const a = try sema.validateAlign(block, .unneeded, bytes);
20539 });20471 wip.field_aligns.get(ip)[field_idx] = a;
20540 errdefer msg.destroy(gpa);20472 } else if (any_field_aligns) {
20541 for (fields_len..tag_ty_fields_len) |enum_field_idx| {20473 wip.field_aligns.get(ip)[field_idx] = .none;
20542 try sema.addFieldErrNote(enum_tag_ty, enum_field_idx, msg, "field '{f}' missing, declared here", .{20474 }
20543 enum_tag_ty.enumFieldName(enum_field_idx, zcu).fmt(ip),
20544 });
20545 }20475 }
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") {20477 const new_namespace_index = try pt.createNamespace(.{
20621 return sema.failWithOwnedErrorMsg(block, msg: {20478 .parent = block.namespace.toOptional(),
20622 const msg = try sema.errMsg(field_types_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{});20479 .owner_type = wip.index,
20623 errdefer msg.destroy(gpa);20480 .file_scope = block.getFileScopeIndex(zcu),
20624 try sema.addDeclaredHereNote(msg, field_ty);20481 .generation = zcu.generation,
20625 break :msg msg;
20626 });20482 });
20627 }20483 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
2062820484 try sema.addTypeReferenceEntry(src, .fromInterned(wip.index));
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 }
2066520485
20666 if (layout == .@"packed") {20486 // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind
20667 try type_resolution.resolvePackedUnionBackingInt(20487 try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) });
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 }
2068420488
20685 const new_namespace_index = try pt.createNamespace(.{20489 try zcu.outdated.ensureUnusedCapacity(gpa, 1);
20686 .parent = block.namespace.toOptional(),20490 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1);
20687 .owner_type = wip_ty.index,20491 errdefer comptime unreachable; // because we don't remove the `outdated` entry
20688 .file_scope = block.getFileScopeIndex(zcu),20492 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0);
20689 .generation = zcu.generation,20493 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {});
20690 });
2069120494
20692 codegen_type: {20495 return .fromIntern(wip.finish(ip, new_namespace_index));
20693 if (zcu.comp.config.use_llvm) break :codegen_type;20496 },
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);
20701 }20497 }
20702 return .fromIntern(wip_ty.finish(ip, new_namespace_index));
20703}20498}
2070420499
20705fn zirReifyEnum(20500fn zirReifyEnum(
...@@ -20754,10 +20549,10 @@ fn zirReifyEnum(...@@ -20754,10 +20549,10 @@ fn zirReifyEnum(
2075420549
20755 const enum_mode_ty = try sema.getBuiltinType(mode_src, .@"Type.Enum.Mode");20550 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);20552 const tag_ty_uncoerced = try sema.resolveInst(extra.tag_ty);
20758 if (tag_ty.zigTypeTag(zcu) != .int) {20553 const tag_ty_coerced = try sema.coerce(block, .type, tag_ty_uncoerced, tag_ty_src);
20759 return sema.fail(block, tag_ty_src, "tag type must be an integer type", .{});20554 const tag_ty_val = try sema.resolveConstDefinedValue(block, tag_ty_src, tag_ty_coerced, .{ .simple = .enum_int_tag_type });
20760 }20555 const tag_ty = tag_ty_val.toType();
2076120556
20762 const mode_uncoerced = try sema.resolveInst(extra.mode);20557 const mode_uncoerced = try sema.resolveInst(extra.mode);
20763 const mode_coerced = try sema.coerce(block, enum_mode_ty, mode_uncoerced, mode_src);20558 const mode_coerced = try sema.coerce(block, enum_mode_ty, mode_uncoerced, mode_src);
...@@ -20790,11 +20585,13 @@ fn zirReifyEnum(...@@ -20790,11 +20585,13 @@ fn zirReifyEnum(
20790 }20585 }
20791 // We don't need to check `field_names_arr`, because `sliceToIpString` will check that for us.20586 // 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.20588 // Most validation of this type happens during type resolution. We basically need to do the work
20794 // So in this first pass, let's just construct a hash to optimize for this case. If the20589 // which AstGen would normally do. An exception is checking for duplicate field names, which is
20795 // inputs turn out to be invalid, we can cancel the WIP type later.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.
20798 // TODO: use a longer hash!20595 // TODO: use a longer hash!
20799 var hasher = std.hash.Wyhash.init(0);20596 var hasher = std.hash.Wyhash.init(0);
20800 std.hash.autoHash(&hasher, tag_ty.toIntern());20597 std.hash.autoHash(&hasher, tag_ty.toIntern());
...@@ -20810,85 +20607,55 @@ fn zirReifyEnum(...@@ -20810,85 +20607,55 @@ fn zirReifyEnum(
20810 std.hash.autoHash(&hasher, field_name);20607 std.hash.autoHash(&hasher, field_name);
20811 }20608 }
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(),
20814 .fields_len = @intCast(fields_len),20613 .fields_len = @intCast(fields_len),
20815 .explicit_int_tag_type = tag_ty.toIntern(),
20816 .nonexhaustive = nonexhaustive,20614 .nonexhaustive = nonexhaustive,
20817 .key = .{ .reified = .{20615 .int_tag_type = tag_ty.toIntern(),
20818 .zir_index = tracked_inst,
20819 .type_hash = hasher.final(),
20820 } },
20821 })) {20616 })) {
20822 .wip => |wip| wip,
20823 .existing => |ty| {20617 .existing => |ty| {
20824 try sema.addTypeReferenceEntry(src, .fromInterned(ty));20618 try sema.addTypeReferenceEntry(src, .fromInterned(ty));
20825 return .fromIntern(ty);20619 return .fromIntern(ty);
20826 },20620 },
20827 };20621 .wip => |wip| {
20828 errdefer wip_ty.cancel(ip, pt.tid);20622 errdefer wip.cancel(ip, pt.tid);
2082920623
20830 _ = try (try sema.createTypeName(20624 try sema.setTypeName(block, &wip, name_strategy, "enum", inst);
20831 block,
20832 name_strategy,
20833 "enum",
20834 inst,
20835 )).apply(&wip_ty, pt);
2083620625
20837 for (0..fields_len) |field_idx| {20626 // Populate field names and values. Duplicate checking will be handled by type resolution.
20838 const field_name_val = try field_names_arr.elemValue(pt, field_idx);20627 for (0..fields_len) |field_index| {
20839 // Don't pass a reason; first loop acts as a check that this is valid.20628 const field_name_val = try field_names_arr.elemValue(pt, field_index);
20840 const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined);20629 // No source location or reason; first loop checked this is valid.
20841 if (wip_ty.nextField(ip, field_name, false)) |prev_field_idx| return sema.failWithOwnedErrorMsg(block, msg: {20630 const field_name = try sema.sliceToIpString(block, .unneeded, field_name_val, undefined);
20842 const msg = try sema.errMsg(field_names_src, "duplicate enum field '{f}' at index '{d}'", .{ field_name.fmt(ip), field_idx });20631 wip.field_names.get(ip)[field_index] = field_name;
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 }
2084820632
20849 const enum_obj = ip.loadEnumType(wip_ty.index);20633 const field_val = try field_values_arr.elemValue(pt, field_index);
20850 const field_value_map = enum_obj.field_value_map.unwrap().?;20634 wip.field_values.get(ip)[field_index] = field_val.toIntern();
20851 for (0..fields_len) |field_idx| {20635 }
20852 const field_val = try field_values_arr.elemValue(pt, field_idx);20636
20853 const field_values = enum_obj.field_values.get(ip);20637 const new_namespace_index = try pt.createNamespace(.{
20854 field_values[field_idx] = field_val.toIntern();20638 .parent = block.namespace.toOptional(),
20855 const adapter: InternPool.Index.Adapter = .{ .indexes = field_values[0..field_idx] };20639 .owner_type = wip.index,
20856 const gop = field_value_map.get(ip).getOrPutAssumeCapacityAdapted(field_val.toIntern(), adapter);20640 .file_scope = block.getFileScopeIndex(zcu),
20857 if (gop.found_existing) return sema.failWithOwnedErrorMsg(block, msg: {20641 .generation = zcu.generation,
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),
20864 });20642 });
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)) {20644 try sema.addTypeReferenceEntry(src, .fromInterned(wip.index));
20872 return sema.fail(block, src, "non-exhaustive enum specified every value", .{});20645 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
20873 }
2087420646
20875 const new_namespace_index = try pt.createNamespace(.{20647 // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind
20876 .parent = block.namespace.toOptional(),20648 try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) });
20877 .owner_type = wip_ty.index,
20878 .file_scope = block.getFileScopeIndex(zcu),
20879 .generation = zcu.generation,
20880 });
2088120649
20882 codegen_type: {20650 try zcu.outdated.ensureUnusedCapacity(gpa, 1);
20883 if (zcu.comp.config.use_llvm) break :codegen_type;20651 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1);
20884 if (block.ownerModule().strip) break :codegen_type;20652 errdefer comptime unreachable; // because we don't remove the `outdated` entry
20885 zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);20653 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0);
20886 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });20654 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {});
20887 }
2088820655
20889 try sema.addTypeReferenceEntry(src, .fromInterned(wip_ty.index));20656 return .fromIntern(wip.finish(ip, new_namespace_index));
20890 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);20657 },
20891 return .fromIntern(wip_ty.finish(ip, new_namespace_index));20658 }
20892}20659}
2089320660
20894fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref {20661fn 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...@@ -20909,7 +20676,7 @@ fn zirCVaArg(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C
20909 const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.lhs);20676 const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.lhs);
20910 const arg_ty = try sema.resolveType(block, ty_src, extra.rhs);20677 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)) {
20913 const msg = msg: {20680 const msg = msg: {
20914 const msg = try sema.errMsg(ty_src, "cannot get '{f}' from variadic argument", .{arg_ty.fmt(sema.pt)});20681 const msg = try sema.errMsg(ty_src, "cannot get '{f}' from variadic argument", .{arg_ty.fmt(sema.pt)});
20915 errdefer msg.destroy(sema.gpa);20682 errdefer msg.destroy(sema.gpa);
...@@ -24205,8 +23972,8 @@ fn zirMemcpy(...@@ -24205,8 +23972,8 @@ fn zirMemcpy(
24205 return sema.failWithOwnedErrorMsg(block, msg);23972 return sema.failWithOwnedErrorMsg(block, msg);
24206 }23973 }
2420723974
24208 const dest_elem_ty = dest_ty.indexablePtrElem(zcu);23975 const dest_elem_ty = dest_ty.indexableElem(zcu);
24209 const src_elem_ty = src_ty.indexablePtrElem(zcu);23976 const src_elem_ty = src_ty.indexableElem(zcu);
2421023977
24211 try sema.ensureLayoutResolved(dest_elem_ty);23978 try sema.ensureLayoutResolved(dest_elem_ty);
24212 try sema.ensureLayoutResolved(src_elem_ty);23979 try sema.ensureLayoutResolved(src_elem_ty);
...@@ -24906,7 +24673,7 @@ fn zirBuiltinExtern(...@@ -24906,7 +24673,7 @@ fn zirBuiltinExtern(
24906 if (!ty.isPtrAtRuntime(zcu)) {24673 if (!ty.isPtrAtRuntime(zcu)) {
24907 return sema.fail(block, ty_src, "expected (optional) pointer", .{});24674 return sema.fail(block, ty_src, "expected (optional) pointer", .{});
24908 }24675 }
24909 if (!try sema.validateExternType(ty, .other)) {24676 if (!ty.validateExtern(.other, zcu)) {
24910 const msg = msg: {24677 const msg = msg: {
24911 const msg = try sema.errMsg(ty_src, "extern symbol cannot have type '{f}'", .{ty.fmt(pt)});24678 const msg = try sema.errMsg(ty_src, "extern symbol cannot have type '{f}'", .{ty.fmt(pt)});
24912 errdefer msg.destroy(sema.gpa);24679 errdefer msg.destroy(sema.gpa);
...@@ -24954,7 +24721,7 @@ fn zirBuiltinExtern(...@@ -24954,7 +24721,7 @@ fn zirBuiltinExtern(
24954 // So, for now, just use our containing `declaration`.24721 // So, for now, just use our containing `declaration`.
24955 .zir_index = switch (sema.owner.unwrap()) {24722 .zir_index = switch (sema.owner.unwrap()) {
24956 .@"comptime" => |cu| ip.getComptimeUnit(cu).zir_index,24723 .@"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).?,
24958 .memoized_state => unreachable,24725 .memoized_state => unreachable,
24959 .nav_ty, .nav_val => |nav| ip.getNav(nav).analysis.?.zir_index,24726 .nav_ty, .nav_val => |nav| ip.getNav(nav).analysis.?.zir_index,
24960 .func => |func| zir_index: {24727 .func => |func| zir_index: {
...@@ -25060,6 +24827,7 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD...@@ -25060,6 +24827,7 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
25060 // Values are handled here.24827 // Values are handled here.
25061 .calling_convention_c => {24828 .calling_convention_c => {
25062 const callconv_ty = try sema.getBuiltinType(src, .CallingConvention);24829 const callconv_ty = try sema.getBuiltinType(src, .CallingConvention);
24830 // Cannot use `Value.uninterpret` because `c` is a *declaration* whose value depends on the target.
25063 return try sema.namespaceLookupVal(24831 return try sema.namespaceLookupVal(
25064 block,24832 block,
25065 src,24833 src,
...@@ -25068,17 +24836,15 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD...@@ -25068,17 +24836,15 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
25068 ) orelse @panic("std.builtin is corrupt");24836 ) orelse @panic("std.builtin is corrupt");
25069 },24837 },
25070 .calling_convention_inline => {24838 .calling_convention_inline => {
25071 comptime assert(@typeInfo(std.builtin.CallingConvention.Tag).@"enum".tag_type == u8);
25072 const callconv_ty = try sema.getBuiltinType(src, .CallingConvention);24839 const callconv_ty = try sema.getBuiltinType(src, .CallingConvention);
25073 const callconv_tag_ty = callconv_ty.unionTagType(zcu) orelse @panic("std.builtin is corrupt");24840 return .fromValue(Value.uninterpret(
25074 const inline_tag_val = try pt.enumValue(24841 @as(std.builtin.CallingConvention, .@"inline"),
25075 callconv_tag_ty,24842 callconv_ty,
25076 (try pt.intValue(24843 pt,
25077 .u8,24844 ) catch |err| switch (err) {
25078 @intFromEnum(std.builtin.CallingConvention.@"inline"),24845 error.TypeMismatch => @panic("std.builtin is corrupt"),
25079 )).toIntern(),24846 error.OutOfMemory => |e| return e,
25080 );24847 });
25081 return sema.coerce(block, callconv_ty, Air.internedToRef(inline_tag_val.toIntern()), src);
25082 },24848 },
25083 };24849 };
25084 return .fromType(try sema.getBuiltinType(src, builtin_type));24850 return .fromType(try sema.getBuiltinType(src, builtin_type));
...@@ -25180,7 +24946,7 @@ pub fn validateVarType(...@@ -25180,7 +24946,7 @@ pub fn validateVarType(
25180 const zcu = pt.zcu;24946 const zcu = pt.zcu;
25181 var_ty.assertHasLayout(zcu);24947 var_ty.assertHasLayout(zcu);
25182 if (is_extern) {24948 if (is_extern) {
25183 if (!try sema.validateExternType(var_ty, .other)) {24949 if (!var_ty.validateExtern(.other, zcu)) {
25184 const msg = msg: {24950 const msg = msg: {
25185 const msg = try sema.errMsg(src, "extern variable cannot have type '{f}'", .{var_ty.fmt(pt)});24951 const msg = try sema.errMsg(src, "extern variable cannot have type '{f}'", .{var_ty.fmt(pt)});
25186 errdefer msg.destroy(sema.gpa);24952 errdefer msg.destroy(sema.gpa);
...@@ -25296,124 +25062,17 @@ fn explainWhyTypeIsComptime(...@@ -25296,124 +25062,17 @@ fn explainWhyTypeIsComptime(
25296 }25062 }
25297}25063}
2529825064
25299const ExternPosition = enum {25065/// Keep in sync with `Type.validateExtern`.
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
25401pub fn explainWhyTypeIsNotExtern(25066pub fn explainWhyTypeIsNotExtern(
25402 sema: *Sema,25067 sema: *Sema,
25403 msg: *Zcu.ErrorMsg,25068 msg: *Zcu.ErrorMsg,
25404 src_loc: LazySrcLoc,25069 src_loc: LazySrcLoc,
25405 ty: Type,25070 ty: Type,
25406 position: ExternPosition,25071 position: Type.ExternPosition,
25407) CompileError!void {25072) CompileError!void {
25408 const pt = sema.pt;25073 const pt = sema.pt;
25409 const zcu = pt.zcu;25074 const zcu = pt.zcu;
25410 switch (ty.zigTypeTag(zcu)) {25075 switch (ty.zigTypeTag(zcu)) {
25411 .@"opaque",
25412 .bool,
25413 .float,
25414 .@"anyframe",
25415 => return,
25416
25417 .type,25076 .type,
25418 .comptime_float,25077 .comptime_float,
25419 .comptime_int,25078 .comptime_int,
...@@ -25425,101 +25084,110 @@ pub fn explainWhyTypeIsNotExtern(...@@ -25425,101 +25084,110 @@ pub fn explainWhyTypeIsNotExtern(
25425 .frame,25084 .frame,
25426 => return,25085 => return,
2542725086
25428 .pointer => {25087 .void => try sema.errNote(src_loc, msg, "'void' is a zero bit type", .{}),
25429 if (ty.isSlice(zcu)) {25088 .noreturn => try sema.errNote(src_loc, msg, "'noreturn' is only allowed as a return type", .{}),
25430 try sema.errNote(src_loc, msg, "slices have no guaranteed in-memory representation", .{});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'", .{});
25431 } else {25102 } else {
25432 const pointee_ty = ty.childType(zcu);25103 try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.childType(zcu), .other);
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);
25437 }25104 }
25438 },25105 },
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", .{}),
25441 .int => if (!std.math.isPowerOfTwo(ty.intInfo(zcu).bits)) {25106 .int => if (!std.math.isPowerOfTwo(ty.intInfo(zcu).bits)) {
25442 try sema.errNote(src_loc, msg, "only integers with 0 or power of two bits are extern compatible", .{});25107 try sema.errNote(src_loc, msg, "only integers with 0 or power of two bits are extern compatible", .{});
25443 } else {25108 } else {
25444 try sema.errNote(src_loc, msg, "only integers with 0, 8, 16, 32, 64 and 128 bits are extern compatible", .{});25109 try sema.errNote(src_loc, msg, "only integers with 0, 8, 16, 32, 64 and 128 bits are extern compatible", .{});
25445 },25110 },
25446 .@"fn" => {25111 .@"fn" => if (position != .other) {
25447 if (position != .other) {25112 try sema.errNote(src_loc, msg, "type has no guaranteed in-memory representation", .{});
25448 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", .{});
25449 try sema.errNote(src_loc, msg, "use '*const ' to make a function pointer type", .{});25114 } else switch (ty.fnCallingConvention(zcu)) {
25450 return;25115 .auto => try sema.errNote(src_loc, msg, "extern function must specify calling convention", .{}),
25451 }25116 else => |cc| try sema.errNote(src_loc, msg, "{t} function cannot be extern", .{cc}),
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 }
25458 },25117 },
25459 .@"enum" => {25118 .@"enum" => {
25460 const tag_ty = ty.intTagType(zcu);25119 const tag_ty = ty.intTagType(zcu);
25461 try sema.errNote(src_loc, msg, "enum tag type '{f}' is not extern compatible", .{tag_ty.fmt(pt)});25120 try sema.errNote(src_loc, msg, "enum tag type '{f}' is not extern compatible", .{tag_ty.fmt(pt)});
25462 try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position);25121 try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position);
25463 },25122 },
25464 // MLUGG TODO: these notes are bad now (because ABI sized packed type also needs explicit backing type)25123 .@"struct" => {
25465 .@"struct" => try sema.errNote(src_loc, msg, "only extern structs and ABI sized packed structs are extern compatible", .{}),25124 const struct_obj = zcu.intern_pool.loadStructType(ty.toIntern());
25466 .@"union" => try sema.errNote(src_loc, msg, "only extern unions and ABI sized packed unions are extern compatible", .{}),25125 switch (struct_obj.layout) {
25467 .array => {25126 .auto => try sema.errNote(src_loc, msg, "struct with automatic layout has no guaranteed in-memory representation", .{}),
25468 if (position == .ret_ty) {25127 .@"extern" => unreachable,
25469 return sema.errNote(src_loc, msg, "arrays are not allowed as a return type", .{});25128 .@"packed" => switch (struct_obj.packed_backing_mode) {
25470 } else if (position == .param_ty) {25129 .auto => try sema.errNote(src_loc, msg, "inferred backing integer of packed struct has unspecified signedness", .{}),
25471 return sema.errNote(src_loc, msg, "arrays are not allowed as a parameter type", .{});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 },
25472 }25151 }
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),
25474 },25157 },
25475 .vector => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.childType(zcu), .element),25158 .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", .{}),
25477 }25160 }
25478}25161}
2547925162
25480pub fn explainWhyTypeIsNotPackable(25163pub fn explainWhyTypeIsUnpackable(
25481 sema: *Sema,25164 sema: *Sema,
25482 msg: *Zcu.ErrorMsg,25165 msg: *Zcu.ErrorMsg,
25483 src_loc: LazySrcLoc,25166 src: LazySrcLoc,
25484 ty: Type,25167 reason: Type.UnpackableReason,
25485) CompileError!void {25168) CompileError!void {
25486 const pt = sema.pt;25169 const pt = sema.pt;
25487 const zcu = pt.zcu;25170 const zcu = pt.zcu;
25488 switch (ty.zigTypeTag(zcu)) {25171 switch (reason) {
25489 .void,25172 .comptime_only => try sema.errNote(src, msg, "comptime-only types have no bit-packed representation", .{}),
25490 .bool,25173 .pointer => {
25491 .float,25174 try sema.errNote(src, msg, "pointers cannot be directly bitpacked", .{});
25492 .int,25175 try sema.errNote(src, msg, "consider using 'usize' and '@intFromPtr'", .{});
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);
25516 },25176 },
25517 .@"fn" => {25177 .enum_inferred_int_tag => |enum_ty| {
25518 try sema.errNote(src_loc, msg, "type has no guaranteed in-memory representation", .{});25178 const enum_src = enum_ty.srcLoc(zcu);
25519 try sema.errNote(src_loc, msg, "use '*const ' to make a function pointer type", .{});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);
25520 },25189 },
25521 .@"struct" => try sema.errNote(src_loc, msg, "struct in packed type must have packed layout", .{}),25190 .other => try sema.errNote(src, msg, "type does not have a bit-packed representation", .{}),
25522 .@"union" => try sema.errNote(src_loc, msg, "union in packed type must have packed layout", .{}),
25523 }25191 }
25524}25192}
2552525193
...@@ -25545,7 +25213,7 @@ fn getPanicIdFunc(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.SimplePanicId) !In...@@ -25545,7 +25213,7 @@ fn getPanicIdFunc(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.SimplePanicId) !In
25545 try sema.ensureMemoizedStateResolved(src, .panic);25213 try sema.ensureMemoizedStateResolved(src, .panic);
25546 const panic_fn_index = zcu.builtin_decl_values.get(panic_id.toBuiltin());25214 const panic_fn_index = zcu.builtin_decl_values.get(panic_id.toBuiltin());
25547 switch (sema.owner.unwrap()) {25215 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 => {},
25549 .func => |owner_func| zcu.intern_pool.funcSetHasErrorTrace(io, owner_func, true),25217 .func => |owner_func| zcu.intern_pool.funcSetHasErrorTrace(io, owner_func, true),
25550 }25218 }
25551 return panic_fn_index;25219 return panic_fn_index;
...@@ -25962,6 +25630,7 @@ fn fieldVal(...@@ -25962,6 +25630,7 @@ fn fieldVal(
25962 if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {25630 if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {
25963 return inst;25631 return inst;
25964 }25632 }
25633 try sema.ensureLayoutResolved(child_type);
25965 if (child_type.unionTagType(zcu)) |enum_ty| {25634 if (child_type.unionTagType(zcu)) |enum_ty| {
25966 if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index_usize| {25635 if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index_usize| {
25967 const field_index: u32 = @intCast(field_index_usize);25636 const field_index: u32 = @intCast(field_index_usize);
...@@ -25974,6 +25643,7 @@ fn fieldVal(...@@ -25974,6 +25643,7 @@ fn fieldVal(
25974 if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {25643 if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {
25975 return inst;25644 return inst;
25976 }25645 }
25646 try sema.ensureLayoutResolved(child_type);
25977 const field_index_usize = child_type.enumFieldIndex(field_name, zcu) orelse25647 const field_index_usize = child_type.enumFieldIndex(field_name, zcu) orelse
25978 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);25648 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
25979 const field_index: u32 = @intCast(field_index_usize);25649 const field_index: u32 = @intCast(field_index_usize);
...@@ -26195,6 +25865,7 @@ fn fieldPtr(...@@ -26195,6 +25865,7 @@ fn fieldPtr(
26195 if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {25865 if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {
26196 return inst;25866 return inst;
26197 }25867 }
25868 try sema.ensureLayoutResolved(child_type);
26198 if (child_type.unionTagType(zcu)) |enum_ty| {25869 if (child_type.unionTagType(zcu)) |enum_ty| {
26199 if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index| {25870 if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index| {
26200 const field_index_u32: u32 = @intCast(field_index);25871 const field_index_u32: u32 = @intCast(field_index);
...@@ -26208,6 +25879,7 @@ fn fieldPtr(...@@ -26208,6 +25879,7 @@ fn fieldPtr(
26208 if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {25879 if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {
26209 return inst;25880 return inst;
26210 }25881 }
25882 try sema.ensureLayoutResolved(child_type);
26211 const field_index = child_type.enumFieldIndex(field_name, zcu) orelse {25883 const field_index = child_type.enumFieldIndex(field_name, zcu) orelse {
26212 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);25884 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
26213 };25885 };
...@@ -26444,9 +26116,6 @@ fn finishFieldCallBind(...@@ -26444,9 +26116,6 @@ fn finishFieldCallBind(
26444 const container_ty = ptr_ty.childType(zcu);26116 const container_ty = ptr_ty.childType(zcu);
26445 if (container_ty.zigTypeTag(zcu) == .@"struct") {26117 if (container_ty.zigTypeTag(zcu) == .@"struct") {
26446 if (container_ty.structFieldIsComptime(field_index, zcu)) {26118 if (container_ty.structFieldIsComptime(field_index, zcu)) {
26447 if (!container_ty.isTuple(zcu)) {
26448 try sema.ensureFieldInitsResolved(container_ty);
26449 }
26450 const default_val = (try container_ty.structFieldValueComptime(pt, field_index)).?;26119 const default_val = (try container_ty.structFieldValueComptime(pt, field_index)).?;
26451 return .{ .direct = Air.internedToRef(default_val.toIntern()) };26120 return .{ .direct = Air.internedToRef(default_val.toIntern()) };
26452 }26121 }
...@@ -26623,7 +26292,7 @@ fn structFieldPtrByIndex(...@@ -26623,7 +26292,7 @@ fn structFieldPtrByIndex(
26623 const ptr_field_ty = try pt.ptrType(ptr_ty_data);26292 const ptr_field_ty = try pt.ptrType(ptr_ty_data);
2662426293
26625 if (field_is_comptime) {26294 if (field_is_comptime) {
26626 try sema.ensureFieldInitsResolved(struct_ty);26295 assert(struct_type.field_defaults.get(ip)[field_index] != .none);
26627 const val = try pt.intern(.{ .ptr = .{26296 const val = try pt.intern(.{ .ptr = .{
26628 .ty = ptr_field_ty.toIntern(),26297 .ty = ptr_field_ty.toIntern(),
26629 .base_addr = .{ .comptime_field = struct_type.field_defaults.get(ip)[field_index] },26298 .base_addr = .{ .comptime_field = struct_type.field_defaults.get(ip)[field_index] },
...@@ -26647,6 +26316,8 @@ fn structFieldVal(...@@ -26647,6 +26316,8 @@ fn structFieldVal(
26647 const zcu = pt.zcu;26316 const zcu = pt.zcu;
26648 const ip = &zcu.intern_pool;26317 const ip = &zcu.intern_pool;
26649 assert(struct_ty.zigTypeTag(zcu) == .@"struct");26318 assert(struct_ty.zigTypeTag(zcu) == .@"struct");
26319 assert(sema.typeOf(struct_byval).toIntern() == struct_ty.toIntern());
26320 struct_ty.assertHasLayout(zcu);
2665026321
26651 switch (ip.indexToKey(struct_ty.toIntern())) {26322 switch (ip.indexToKey(struct_ty.toIntern())) {
26652 .struct_type => {26323 .struct_type => {
...@@ -26655,7 +26326,6 @@ fn structFieldVal(...@@ -26655,7 +26326,6 @@ fn structFieldVal(
26655 const field_index = struct_type.nameIndex(ip, field_name) orelse26326 const field_index = struct_type.nameIndex(ip, field_name) orelse
26656 return sema.failWithBadStructFieldAccess(block, struct_ty, struct_type, field_name_src, field_name);26327 return sema.failWithBadStructFieldAccess(block, struct_ty, struct_type, field_name_src, field_name);
26657 if (struct_type.field_is_comptime_bits.get(ip, field_index)) {26328 if (struct_type.field_is_comptime_bits.get(ip, field_index)) {
26658 try sema.ensureFieldInitsResolved(struct_ty);
26659 return .fromIntern(struct_type.field_defaults.get(ip)[field_index]);26329 return .fromIntern(struct_type.field_defaults.get(ip)[field_index]);
26660 }26330 }
2666126331
...@@ -26886,6 +26556,8 @@ fn unionFieldVal(...@@ -26886,6 +26556,8 @@ fn unionFieldVal(
26886 const zcu = pt.zcu;26556 const zcu = pt.zcu;
26887 const ip = &zcu.intern_pool;26557 const ip = &zcu.intern_pool;
26888 assert(union_ty.zigTypeTag(zcu) == .@"union");26558 assert(union_ty.zigTypeTag(zcu) == .@"union");
26559 assert(sema.typeOf(union_byval).toIntern() == union_ty.toIntern());
26560 union_ty.assertHasLayout(zcu);
2688926561
26890 const union_obj = zcu.typeToUnion(union_ty).?;26562 const union_obj = zcu.typeToUnion(union_ty).?;
26891 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);26563 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
...@@ -27149,11 +26821,11 @@ fn validateRuntimeElemAccess(...@@ -27149,11 +26821,11 @@ fn validateRuntimeElemAccess(
27149 const msg = try sema.errMsg(26821 const msg = try sema.errMsg(
27150 elem_index_src,26822 elem_index_src,
27151 "values of type '{f}' must be comptime-known, but index value is runtime-known",26823 "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)},
27153 );26825 );
27154 errdefer msg.destroy(sema.gpa);26826 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
27158 break :msg msg;26830 break :msg msg;
27159 };26831 };
...@@ -27885,18 +27557,14 @@ fn coerceExtra(...@@ -27885,18 +27557,14 @@ fn coerceExtra(
27885 // empty tuple to zero-length slice27557 // empty tuple to zero-length slice
27886 // note that this allows coercing to a mutable slice.27558 // note that this allows coercing to a mutable slice.
27887 if (inst_child_ty.structFieldCount(zcu) == 0) {27559 if (inst_child_ty.structFieldCount(zcu) == 0) {
27888 // TODO MLUGG: this is *unacceptably* stupid. we're resolving the child for the alignment value27560 const empty_array_ty = try pt.arrayType(.{
27889 try sema.ensureLayoutResolved(dest_ty.childType(zcu));27561 .len = 0,
27890 const align_val = dest_ty.ptrAlignment(zcu);27562 .child = dest_info.child,
27891 return Air.internedToRef(try pt.intern(.{ .slice = .{27563 .sentinel = dest_info.sentinel,
27892 .ty = dest_ty.toIntern(),27564 });
27893 .ptr = try pt.intern(.{ .ptr = .{27565 const empty_array_val = try pt.aggregateValue(empty_array_ty, &.{});
27894 .ty = dest_ty.slicePtrFieldType(zcu).toIntern(),27566 const empty_array_ptr = try sema.uavRef(empty_array_val.toIntern());
27895 .base_addr = .int,27567 return sema.coerceArrayPtrToSlice(block, dest_ty, empty_array_ptr, inst_src);
27896 .byte_offset = align_val.toByteUnits().?,
27897 } }),
27898 .len = .zero_usize,
27899 } }));
27900 }27568 }
2790127569
27902 // pointer to tuple to slice27570 // pointer to tuple to slice
...@@ -27955,7 +27623,7 @@ fn coerceExtra(...@@ -27955,7 +27623,7 @@ fn coerceExtra(
27955 .int, .comptime_int => {27623 .int, .comptime_int => {
27956 if (maybe_inst_val) |val| {27624 if (maybe_inst_val) |val| {
27957 // comptime-known integer to other number27625 // comptime-known integer to other number
27958 if (!(try sema.intFitsInType(val, dest_ty, null))) {27626 if (!val.intFitsInType(dest_ty, null, zcu)) {
27959 if (!opts.report_err) return error.NotCoercible;27627 if (!opts.report_err) return error.NotCoercible;
27960 return sema.fail(block, inst_src, "type '{f}' cannot represent integer value '{f}'", .{ dest_ty.fmt(pt), val.fmtValueSema(pt, sema) });27628 return sema.fail(block, inst_src, "type '{f}' cannot represent integer value '{f}'", .{ dest_ty.fmt(pt), val.fmtValueSema(pt, sema) });
27961 }27629 }
...@@ -28039,28 +27707,26 @@ fn coerceExtra(...@@ -28039,28 +27707,26 @@ fn coerceExtra(
28039 }27707 }
28040 break :int;27708 break :int;
28041 };27709 };
27710 if (val.isUndef(zcu)) {
27711 return .fromValue(try pt.undefValue(dest_ty));
27712 }
28042 const result_val = try pt.floatValue(dest_ty, val.toFloat(f128, zcu));27713 const result_val = try pt.floatValue(dest_ty, val.toFloat(f128, zcu));
28043 const fits: bool = switch (ip.indexToKey(result_val.toIntern())) {27714 const float = ip.indexToKey(result_val.toIntern()).float;
28044 else => unreachable,27715 var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined;
28045 .undef => true,27716 const operand_big_int = val.toBigInt(&buffer, zcu);
28046 .float => |float| fits: {27717 const fits = switch (float.storage) {
28047 var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined;27718 inline else => |x| fits: {
28048 const operand_big_int = val.toBigInt(&buffer, zcu);27719 if (!std.math.isFinite(x)) break :fits false;
28049 switch (float.storage) {27720 var result_big_int: std.math.big.int.Mutable = .{
28050 inline else => |x| {27721 .limbs = try sema.arena.alloc(std.math.big.Limb, std.math.big.int.calcLimbLen(x)),
28051 if (!std.math.isFinite(x)) break :fits false;27722 .len = undefined,
28052 var result_big_int: std.math.big.int.Mutable = .{27723 .positive = undefined,
28053 .limbs = try sema.arena.alloc(std.math.big.Limb, std.math.big.int.calcLimbLen(x)),27724 };
28054 .len = undefined,27725 switch (result_big_int.setFloat(x, .nearest_even)) {
28055 .positive = undefined,27726 .inexact => break :fits false,
28056 };27727 .exact => {},
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 },
28063 }27728 }
27729 break :fits result_big_int.toConst().eql(operand_big_int);
28064 },27730 },
28065 };27731 };
28066 if (!fits) return sema.fail(27732 if (!fits) return sema.fail(
...@@ -28699,7 +28365,7 @@ pub fn coerceInMemoryAllowed(...@@ -28699,7 +28365,7 @@ pub fn coerceInMemoryAllowed(
28699 // Comptime int to regular int.28365 // Comptime int to regular int.
28700 if (dest_tag == .int and src_tag == .comptime_int) {28366 if (dest_tag == .int and src_tag == .comptime_int) {
28701 if (src_val) |val| {28367 if (src_val) |val| {
28702 if (!(try sema.intFitsInType(val, dest_ty, null))) {28368 if (!val.intFitsInType(dest_ty, null, zcu)) {
28703 return .{ .comptime_int_not_coercible = .{ .wanted = dest_ty, .actual = val } };28369 return .{ .comptime_int_not_coercible = .{ .wanted = dest_ty, .actual = val } };
28704 }28370 }
28705 }28371 }
...@@ -29333,7 +28999,7 @@ fn coerceVarArgParam(...@@ -29333,7 +28999,7 @@ fn coerceVarArgParam(
29333 }28999 }
29334 },29000 },
29335 else => if (uncasted_ty.isAbiInt(zcu)) int: {29001 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;
29337 const target = zcu.getTarget();29003 const target = zcu.getTarget();
29338 const uncasted_info = uncasted_ty.intInfo(zcu);29004 const uncasted_info = uncasted_ty.intInfo(zcu);
29339 if (uncasted_info.bits <= target.cTypeBitSize(switch (uncasted_info.signedness) {29005 if (uncasted_info.bits <= target.cTypeBitSize(switch (uncasted_info.signedness) {
...@@ -29362,7 +29028,7 @@ fn coerceVarArgParam(...@@ -29362,7 +29028,7 @@ fn coerceVarArgParam(
29362 };29028 };
2936329029
29364 const coerced_ty = sema.typeOf(coerced);29030 const coerced_ty = sema.typeOf(coerced);
29365 if (!try sema.validateExternType(coerced_ty, .param_ty)) {29031 if (!coerced_ty.validateExtern(.param_ty, zcu)) {
29366 const msg = msg: {29032 const msg = msg: {
29367 const msg = try sema.errMsg(inst_src, "cannot pass '{f}' to variadic function", .{coerced_ty.fmt(pt)});29033 const msg = try sema.errMsg(inst_src, "cannot pass '{f}' to variadic function", .{coerced_ty.fmt(pt)});
29368 errdefer msg.destroy(sema.gpa);29034 errdefer msg.destroy(sema.gpa);
...@@ -33283,12 +32949,12 @@ fn typeIsArrayLike(sema: *Sema, ty: Type) ?ArrayLike {...@@ -33283,12 +32949,12 @@ fn typeIsArrayLike(sema: *Sema, ty: Type) ?ArrayLike {
33283 .elem_ty = ty.childType(zcu),32949 .elem_ty = ty.childType(zcu),
33284 },32950 },
33285 .@"struct" => {32951 .@"struct" => {
32952 if (!ty.isTuple(zcu)) return null;
33286 const field_count = ty.structFieldCount(zcu);32953 const field_count = ty.structFieldCount(zcu);
33287 if (field_count == 0) return .{32954 if (field_count == 0) return .{
33288 .len = 0,32955 .len = 0,
33289 .elem_ty = .noreturn,32956 .elem_ty = .noreturn,
33290 };32957 };
33291 if (!ty.isTuple(zcu)) return null;
33292 const elem_ty = ty.fieldType(0, zcu);32958 const elem_ty = ty.fieldType(0, zcu);
33293 for (1..field_count) |i| {32959 for (1..field_count) |i| {
33294 if (!ty.fieldType(i, zcu).eql(elem_ty, zcu)) {32960 if (!ty.fieldType(i, zcu).eql(elem_ty, zcu)) {
...@@ -33700,6 +33366,7 @@ fn usizeCast(sema: *Sema, block: *Block, src: LazySrcLoc, int: u64) CompileError...@@ -33700,6 +33366,7 @@ fn usizeCast(sema: *Sema, block: *Block, src: LazySrcLoc, int: u64) CompileError
33700 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});33366 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});
33701}33367}
3370233368
33369/// Asserts that the layout of `union_ty` is already resolved.
33703fn unionFieldIndex(33370fn unionFieldIndex(
33704 sema: *Sema,33371 sema: *Sema,
33705 block: *Block,33372 block: *Block,
...@@ -33717,6 +33384,7 @@ fn unionFieldIndex(...@@ -33717,6 +33384,7 @@ fn unionFieldIndex(
33717 return @intCast(field_index);33384 return @intCast(field_index);
33718}33385}
3371933386
33387/// Asserts that the layout of `struct_ty` is already resolved.
33720fn structFieldIndex(33388fn structFieldIndex(
33721 sema: *Sema,33389 sema: *Sema,
33722 block: *Block,33390 block: *Block,
...@@ -33811,64 +33479,6 @@ fn intFromFloatScalar(...@@ -33811,64 +33479,6 @@ fn intFromFloatScalar(
33811 return pt.getCoerced(cti_result, int_ty);33479 return pt.getCoerced(cti_result, int_ty);
33812}33480}
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
33872fn intInRange(sema: *Sema, tag_ty: Type, int_val: Value, end: usize) !bool {33482fn intInRange(sema: *Sema, tag_ty: Type, int_val: Value, end: usize) !bool {
33873 const pt = sema.pt;33483 const pt = sema.pt;
33874 if (!int_val.compareAllWithZero(.gte, pt.zcu)) return false;33484 if (!int_val.compareAllWithZero(.gte, pt.zcu)) return false;
...@@ -33886,7 +33496,7 @@ fn enumHasInt(sema: *Sema, ty: Type, int: Value) CompileError!bool {...@@ -33886,7 +33496,7 @@ fn enumHasInt(sema: *Sema, ty: Type, int: Value) CompileError!bool {
33886 // The `tagValueIndex` function call below relies on the type being the integer tag type.33496 // The `tagValueIndex` function call below relies on the type being the integer tag type.
33887 // `getCoerced` assumes the value will fit the new type.33497 // `getCoerced` assumes the value will fit the new type.
33888 const int_tag_ty: Type = .fromInterned(enum_type.int_tag_type);33498 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;
33890 const int_coerced = try pt.getCoerced(int, int_tag_ty);33500 const int_coerced = try pt.getCoerced(int, int_tag_ty);
33891 return enum_type.tagValueIndex(&zcu.intern_pool, int_coerced.toIntern()) != null;33501 return enum_type.tagValueIndex(&zcu.intern_pool, int_coerced.toIntern()) != null;
33892}33502}
...@@ -33919,7 +33529,6 @@ fn compareAll(...@@ -33919,7 +33529,6 @@ fn compareAll(
33919}33529}
3392033530
33921/// Asserts the values are comparable. Both operands have type `ty`.33531/// Asserts the values are comparable. Both operands have type `ty`.
33922/// MLUGG TODO: move to `Value`?
33923fn compareScalar(33532fn compareScalar(
33924 sema: *Sema,33533 sema: *Sema,
33925 lhs: Value,33534 lhs: Value,
...@@ -34422,7 +34031,7 @@ const ComptimeStoreResult = @import("Sema/comptime_ptr_access.zig").ComptimeStor...@@ -34422,7 +34031,7 @@ const ComptimeStoreResult = @import("Sema/comptime_ptr_access.zig").ComptimeStor
34422// MLUGG TODO: decide how to do the namespacing here34031// MLUGG TODO: decide how to do the namespacing here
34423pub const type_resolution = @import("Sema/type_resolution.zig");34032pub const type_resolution = @import("Sema/type_resolution.zig");
34424pub const ensureLayoutResolved = type_resolution.ensureLayoutResolved;34033pub const ensureLayoutResolved = type_resolution.ensureLayoutResolved;
34425pub const ensureFieldInitsResolved = type_resolution.ensureFieldInitsResolved;34034pub const ensureStructDefaultsResolved = type_resolution.ensureStructDefaultsResolved;
3442634035
34427pub fn getBuiltinType(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl) SemaError!Type {34036pub fn getBuiltinType(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl) SemaError!Type {
34428 assert(decl.kind() == .type);34037 assert(decl.kind() == .type);
...@@ -34644,48 +34253,14 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ...@@ -34644,48 +34253,14 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ
34644 };34253 };
34645}34254}
3464634255
34647/// TODO MLUGG: this is a gnarly hack34256fn setTypeName(
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(
34683 sema: *Sema,34257 sema: *Sema,
34684 block: *Block,34258 block: *Block,
34259 wip: *const InternPool.WipContainerType,
34685 name_strategy: Zir.Inst.NameStrategy,34260 name_strategy: Zir.Inst.NameStrategy,
34686 anon_prefix: []const u8,34261 anon_prefix: []const u8,
34687 inst: Zir.Inst.Index,34262 inst: Zir.Inst.Index,
34688) CompileError!PartialTypeName {34263) CompileError!void {
34689 const pt = sema.pt;34264 const pt = sema.pt;
34690 const zcu = pt.zcu;34265 const zcu = pt.zcu;
34691 const comp = zcu.comp;34266 const comp = zcu.comp;
...@@ -34693,13 +34268,26 @@ pub fn createTypeName(...@@ -34693,13 +34268,26 @@ pub fn createTypeName(
34693 const io = comp.io;34268 const io = comp.io;
34694 const ip = &zcu.intern_pool;34269 const ip = &zcu.intern_pool;
3469534270
34696 switch (name_strategy) {34271 strat: switch (name_strategy) {
34697 .anon => {}, // handled after switch34272 .anon => {
34698 .parent => return .{ .exact = .{34273 // It would be neat to have "struct:line:column" but this name has
34699 .name = block.type_name_ctx,34274 // to survive incremental updates, where it may have been shifted down
34700 .nav = sema.owner.unwrap().nav_val.toOptional(),34275 // or up to a different line, but unchanged, and thus not unnecessarily
34701 } },34276 // semantically analyzed.
34702 .func => func_strat: {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 => {
34703 const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse return error.AnalysisFail);34291 const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse return error.AnalysisFail);
34704 const zir_tags = sema.code.instructions.items(.tag);34292 const zir_tags = sema.code.instructions.items(.tag);
3470534293
...@@ -34717,7 +34305,9 @@ pub fn createTypeName(...@@ -34717,7 +34305,9 @@ pub fn createTypeName(
34717 // If not then this is a struct type being returned from a non-generic34305 // If not then this is a struct type being returned from a non-generic
34718 // function and the name doesn't matter since it will later34306 // function and the name doesn't matter since it will later
34719 // result in a compile error.34307 // result in a compile error.
34720 const arg_val = try sema.resolveValue(arg) orelse break :func_strat; // fall through to anon strat34308 const arg_val = try sema.resolveValue(arg) orelse {
34309 continue :strat .anon;
34310 };
3472134311
34722 if (arg_i != 0) w.writeByte(',') catch return error.OutOfMemory;34312 if (arg_i != 0) w.writeByte(',') catch return error.OutOfMemory;
3472334313
...@@ -34739,431 +34329,28 @@ pub fn createTypeName(...@@ -34739,431 +34329,28 @@ pub fn createTypeName(
34739 };34329 };
3474034330
34741 w.writeByte(')') catch return error.OutOfMemory;34331 w.writeByte(')') catch return error.OutOfMemory;
34742 return .{ .exact = .{34332 const name = try ip.getOrPutString(gpa, io, pt.tid, aw.written(), .no_embedded_nulls);
34743 .name = try ip.getOrPutString(gpa, io, pt.tid, aw.written(), .no_embedded_nulls),34333 wip.setName(ip, name, .none);
34744 .nav = .none,
34745 } };
34746 },34334 },
34747 .dbg_var => {34335 .dbg_var => {
34748 // TODO: this logic is questionable. We ideally should be traversing the `Block` rather than relying on the order of AstGen instructions.34336 // TODO: this logic is questionable. We ideally should be traversing the `Block` rather than relying on the order of AstGen instructions.
34749 const ref = inst.toRef();34337 const ref = inst.toRef();
34750 const zir_tags = sema.code.instructions.items(.tag);34338 const zir_tags = sema.code.instructions.items(.tag);
34751 const zir_data = sema.code.instructions.items(.data);34339 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]) {
34753 .dbg_var_ptr, .dbg_var_val => if (zir_data[i].str_op.operand == ref) {34341 .dbg_var_ptr, .dbg_var_val => if (zir_data[i].str_op.operand == ref) {
34754 return .{ .exact = .{34342 break zir_data[i].str_op.getStr(sema.code);
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 } };
34760 },34343 },
34761 else => {},34344 else => {},
34345 } else {
34346 continue :strat .anon;
34762 };34347 };
34763 // fall through to anon strat34348 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);
34764 },34352 },
34765 }34353 }
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));
35167}34354}
3516834355
35169fn zirStructDecl(34356fn zirStructDecl(
...@@ -35173,6 +34360,10 @@ fn zirStructDecl(...@@ -35173,6 +34360,10 @@ fn zirStructDecl(
35173) CompileError!Air.Inst.Ref {34360) CompileError!Air.Inst.Ref {
35174 const pt = sema.pt;34361 const pt = sema.pt;
35175 const zcu = pt.zcu;34362 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
35177 const tracked_inst = try block.trackZir(inst);34368 const tracked_inst = try block.trackZir(inst);
3517834369
...@@ -35180,32 +34371,50 @@ fn zirStructDecl(...@@ -35180,32 +34371,50 @@ fn zirStructDecl(
35180 .base_node_inst = tracked_inst,34371 .base_node_inst = tracked_inst,
35181 .offset = .nodeOffset(.zero),34372 .offset = .nodeOffset(.zero),
35182 };34373 };
35183 const backing_ty_src: LazySrcLoc = .{
35184 .base_node_inst = tracked_inst,
35185 .offset = .{ .node_offset_container_tag = .zero },
35186 };
3518734374
35188 const struct_decl = sema.code.getStructDecl(inst);34375 const struct_decl = sema.code.getStructDecl(inst);
3518934376
35190 const captures = try sema.getCaptures(block, src, struct_decl.captures, struct_decl.capture_names);34377 const captures = try sema.getCaptures(block, src, struct_decl.captures, struct_decl.capture_names);
3519134378
35192 const backing_int_type: ?Type = ty: {34379 const ty: Type = switch (try ip.getDeclaredStructType(gpa, io, pt.tid, .{
35193 if (struct_decl.backing_int_type == .none) break :ty null;34380 .zir_index = tracked_inst,
35194 break :ty try sema.resolveType(block, backing_ty_src, struct_decl.backing_int_type);34381 .captures = captures,
35195 // MLUGG TODO validate it's an int!34382 .fields_len = @intCast(struct_decl.field_names.len),
35196 };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(34405 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
35199 pt,34406
35200 block.getFileScopeIndex(zcu),34407 try zcu.outdated.ensureUnusedCapacity(gpa, 2);
35201 &sema.code,34408 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 2);
35202 block.namespace.toOptional(),34409 errdefer comptime unreachable; // because we don't remove the `outdated` entries
35203 tracked_inst,34410 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0);
35204 &struct_decl,34411 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .struct_defaults = wip.index }), 0);
35205 backing_int_type,34412 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {});
35206 captures,34413 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .struct_defaults = wip.index }), {});
35207 try sema.createTypeName(block, struct_decl.name_strategy, "struct", inst),34414
35208 );34415 break :ty .fromInterned(wip.finish(ip, new_namespace_index));
34416 },
34417 };
3520934418
35210 try sema.addTypeReferenceEntry(src, ty);34419 try sema.addTypeReferenceEntry(src, ty);
3521134420
...@@ -35234,124 +34443,68 @@ fn zirUnionDecl(...@@ -35234,124 +34443,68 @@ fn zirUnionDecl(
35234 .base_node_inst = tracked_inst,34443 .base_node_inst = tracked_inst,
35235 .offset = .nodeOffset(.zero),34444 .offset = .nodeOffset(.zero),
35236 };34445 };
35237 const arg_ty_src: LazySrcLoc = .{
35238 .base_node_inst = tracked_inst,
35239 .offset = .{ .node_offset_container_tag = .zero },
35240 };
3524134446
35242 const union_decl = sema.code.getUnionDecl(inst);34447 const union_decl = sema.code.getUnionDecl(inst);
3524334448
35244 const captures = try sema.getCaptures(block, src, union_decl.captures, union_decl.capture_names);34449 const captures = try sema.getCaptures(block, src, union_decl.captures, union_decl.capture_names);
3524534450
35246 const arg_type: ?Type = ty: {34451 const ty: Type = switch (try ip.getDeclaredUnionType(gpa, io, pt.tid, .{
35247 if (union_decl.arg_type == .none) break :ty null;34452 .zir_index = tracked_inst,
35248 break :ty try sema.resolveType(block, arg_ty_src, union_decl.arg_type);34453 .captures = captures,
35249 };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(34460 .tagged_explicit,
35252 pt,34461 .tagged_enum,
35253 block.getFileScopeIndex(zcu),34462 .tagged_enum_explicit,
35254 &sema.code,34463 => .tagged,
35255 block.namespace.toOptional(),34464
35256 block.wantSafeTypes(),34465 .@"extern",
35257 tracked_inst,34466 .@"packed",
35258 &union_decl,34467 .packed_explicit,
35259 arg_type,34468 => .none,
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;
35342 },34469 },
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);34484 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
35346 switch (ip.indexToKey(enum_tag_ty.toIntern()).enum_type) {34485 .parent = block.namespace.toOptional(),
35347 .declared, .reified => {},34486 .owner_type = wip.index,
35348 .generated_union_tag => |owner_union_ty| {34487 .file_scope = block.getFileScopeIndex(zcu),
35349 assert(owner_union_ty == ty.toIntern());34488 .generation = zcu.generation,
35350 // generated tag type [MLUGG]34489 });
35351 // Enum inits are resolved eagerly. TODO MLUGG: honestly i don't think they SHOULD be lol34490 errdefer pt.destroyNamespace(new_namespace_index);
35352 try sema.ensureFieldInitsResolved(.fromInterned(ip.loadUnionType(ty.toIntern()).enum_tag_type));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));
35353 },34506 },
35354 }34507 };
3535534508
35356 try sema.addTypeReferenceEntry(src, ty);34509 try sema.addTypeReferenceEntry(src, ty);
3535734510
...@@ -35369,6 +34522,10 @@ fn zirEnumDecl(...@@ -35369,6 +34522,10 @@ fn zirEnumDecl(
35369) CompileError!Air.Inst.Ref {34522) CompileError!Air.Inst.Ref {
35370 const pt = sema.pt;34523 const pt = sema.pt;
35371 const zcu = pt.zcu;34524 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
35373 const tracked_inst = try block.trackZir(inst);34530 const tracked_inst = try block.trackZir(inst);
3537434531
...@@ -35376,45 +34533,48 @@ fn zirEnumDecl(...@@ -35376,45 +34533,48 @@ fn zirEnumDecl(
35376 .base_node_inst = tracked_inst,34533 .base_node_inst = tracked_inst,
35377 .offset = .nodeOffset(.zero),34534 .offset = .nodeOffset(.zero),
35378 };34535 };
35379 const tag_ty_src: LazySrcLoc = .{
35380 .base_node_inst = tracked_inst,
35381 .offset = .{ .node_offset_container_tag = .zero },
35382 };
3538334536
35384 const enum_decl = sema.code.getEnumDecl(inst);34537 const enum_decl = sema.code.getEnumDecl(inst);
3538534538
35386 const captures = try sema.getCaptures(block, src, enum_decl.captures, enum_decl.capture_names);34539 const captures = try sema.getCaptures(block, src, enum_decl.captures, enum_decl.capture_names);
3538734540
35388 const tag_type: ?Type = ty: {34541 const ty: Type = switch (try ip.getDeclaredEnumType(gpa, io, pt.tid, .{
35389 if (enum_decl.tag_type == .none) break :ty null;34542 .zir_index = tracked_inst,
35390 break :ty try sema.resolveType(block, tag_ty_src, enum_decl.tag_type);34543 .captures = captures,
35391 };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(34552 try sema.setTypeName(block, &wip, enum_decl.name_strategy, "enum", inst);
35394 pt,34553
35395 block.getFileScopeIndex(zcu),34554 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
35396 &sema.code,34555 .parent = block.namespace.toOptional(),
35397 block.namespace.toOptional(),34556 .owner_type = wip.index,
35398 tracked_inst,34557 .file_scope = block.getFileScopeIndex(zcu),
35399 &enum_decl,34558 .generation = zcu.generation,
35400 tag_type,34559 });
35401 captures,34560 errdefer pt.destroyNamespace(new_namespace_index);
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 };
3541534561
35416 // Enum inits are resolved eagerly. TODO MLUGG: honestly i don't think they SHOULD be lol34562 try pt.scanNamespace(new_namespace_index, enum_decl.decls);
35417 try sema.ensureFieldInitsResolved(ty);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
35419 try sema.addTypeReferenceEntry(src, ty);34579 try sema.addTypeReferenceEntry(src, ty);
3542034580
...@@ -35432,6 +34592,10 @@ fn zirOpaqueDecl(...@@ -35432,6 +34592,10 @@ fn zirOpaqueDecl(
35432) CompileError!Air.Inst.Ref {34592) CompileError!Air.Inst.Ref {
35433 const pt = sema.pt;34593 const pt = sema.pt;
35434 const zcu = pt.zcu;34594 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
35436 const tracked_inst = try block.trackZir(inst);34600 const tracked_inst = try block.trackZir(inst);
3543734601
...@@ -35444,15 +34608,26 @@ fn zirOpaqueDecl(...@@ -35444,15 +34608,26 @@ fn zirOpaqueDecl(
3544434608
35445 const captures = try sema.getCaptures(block, src, opaque_decl.captures, opaque_decl.capture_names);34609 const captures = try sema.getCaptures(block, src, opaque_decl.captures, opaque_decl.capture_names);
3544634610
35447 const ty = try analyzeOpaqueDecl(34611 const ty: Type = switch (try ip.getDeclaredOpaqueType(gpa, io, pt.tid, .{
35448 pt,34612 .zir_index = tracked_inst,
35449 block.getFileScopeIndex(zcu),34613 .captures = captures,
35450 block.namespace.toOptional(),34614 })) {
35451 tracked_inst,34615 .existing => |ty| .fromInterned(ty),
35452 &opaque_decl,34616 .wip => |wip| ty: {
35453 captures,34617 errdefer wip.cancel(ip, pt.tid);
35454 try sema.createTypeName(block, opaque_decl.name_strategy, "opaque", inst),34618 try sema.setTypeName(block, &wip, opaque_decl.name_strategy, "opaque", inst);
35455 );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
35457 try sema.addTypeReferenceEntry(src, ty);34632 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...@@ -769,7 +769,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool
769 const ip = &pt.zcu.intern_pool;769 const ip = &pt.zcu.intern_pool;
770770
771 try self.sema.ensureLayoutResolved(res_ty);771 try self.sema.ensureLayoutResolved(res_ty);
772 try self.sema.ensureFieldInitsResolved(res_ty);772 try self.sema.ensureStructDefaultsResolved(res_ty);
773 const struct_info = self.sema.pt.zcu.typeToStruct(res_ty).?;773 const struct_info = self.sema.pt.zcu.typeToStruct(res_ty).?;
774774
775 const fields: @FieldType(Zoir.Node, "struct_literal") = switch (node.get(self.file.zoir.?)) {775 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");...@@ -18,10 +18,6 @@ const arith = @import("arith.zig");
18/// `ty` may be any type; its layout is resolved *recursively* if necessary.18/// `ty` may be any type; its layout is resolved *recursively* if necessary.
19/// Adds incremental dependencies tracking any required type resolution.19/// Adds incremental dependencies tracking any required type resolution.
20/// MLUGG TODO: to make the langspec non-stupid, we need to call this from WAY fewer places (the conditions need to be less specific).20/// 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
25/// MLUGG TODO: to be clear, i should audit EVERY use of this before PRing21/// MLUGG TODO: to be clear, i should audit EVERY use of this before PRing
26pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void {22pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void {
27 const pt = sema.pt;23 const pt = sema.pt;
...@@ -33,7 +29,6 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void {...@@ -33,7 +29,6 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void {
33 .anyframe_type,29 .anyframe_type,
34 .simple_type,30 .simple_type,
35 .opaque_type,31 .opaque_type,
36 .enum_type,
37 .error_set_type,32 .error_set_type,
38 .inferred_error_set_type,33 .inferred_error_set_type,
39 => {},34 => {},
...@@ -52,7 +47,7 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void {...@@ -52,7 +47,7 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void {
52 .tuple_type => |tuple| for (tuple.types.get(ip)) |field_ty| {47 .tuple_type => |tuple| for (tuple.types.get(ip)) |field_ty| {
53 try ensureLayoutResolved(sema, .fromInterned(field_ty));48 try ensureLayoutResolved(sema, .fromInterned(field_ty));
54 },49 },
55 .struct_type, .union_type => {50 .struct_type, .union_type, .enum_type => {
56 try sema.declareDependency(.{ .type_layout = ty.toIntern() });51 try sema.declareDependency(.{ .type_layout = ty.toIntern() });
57 if (zcu.analysis_in_progress.contains(.wrap(.{ .type_layout = ty.toIntern() }))) {52 if (zcu.analysis_in_progress.contains(.wrap(.{ .type_layout = ty.toIntern() }))) {
58 // TODO: better error message53 // TODO: better error message
...@@ -89,36 +84,36 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void {...@@ -89,36 +84,36 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void {
89 }84 }
90}85}
9186
92/// Asserts that `ty` is either a `struct` type, or an `enum` type.87/// Asserts that `ty` is a non-tuple `struct` type, and ensures that its fields' default values
93/// If `ty` is a struct, ensures that fields' default values are resolved.88/// are resolved. Adds incremental dependencies tracking the required type resolution.
94/// If `ty` is an enum, ensures that fields' integer tag valus are resolved.89///
95/// Adds incremental dependencies tracking the required type resolution.90/// It is not necessary to call this function to query the values of comptime fields: those values
96pub fn ensureFieldInitsResolved(sema: *Sema, ty: Type) SemaError!void {91/// are available from type *layout* resolution, see `ensureLayoutResolved`.
92pub fn ensureStructDefaultsResolved(sema: *Sema, ty: Type) SemaError!void {
97 const pt = sema.pt;93 const pt = sema.pt;
98 const zcu = pt.zcu;94 const zcu = pt.zcu;
99 const ip = &zcu.intern_pool;95 const ip = &zcu.intern_pool;
100 switch (ip.indexToKey(ty.toIntern())) {96 assert(ip.indexToKey(ty.toIntern()) == .struct_type);
101 .struct_type, .enum_type => {},
102 else => unreachable, // assertion failure
103 }
10497
105 try sema.declareDependency(.{ .type_inits = ty.toIntern() });98 try sema.declareDependency(.{ .struct_defaults = ty.toIntern() });
106 if (zcu.analysis_in_progress.contains(.wrap(.{ .type_inits = ty.toIntern() }))) {99 if (zcu.analysis_in_progress.contains(.wrap(.{ .struct_defaults = ty.toIntern() }))) {
107 // TODO: better error message100 // TODO: better error message
108 return sema.failWithOwnedErrorMsg(null, try sema.errMsg(101 return sema.failWithOwnedErrorMsg(null, try sema.errMsg(
109 ty.srcLoc(zcu),102 ty.srcLoc(zcu),
110 "{s} '{f}' depends on itself",103 "struct '{f}' depends on itself",
111 .{ @tagName(ty.zigTypeTag(zcu)), ty.fmt(pt) },104 .{ty.fmt(pt)},
112 ));105 ));
113 }106 }
114 try pt.ensureTypeInitsUpToDate(ty);107 try pt.ensureStructDefaultsUpToDate(ty);
115}108}
109
116/// Asserts that `struct_ty` is a non-packed non-tuple struct, and that `sema.owner` is that type.110/// Asserts that `struct_ty` is a non-packed non-tuple struct, and that `sema.owner` is that type.
117/// This function *does* register the `src_hash` dependency on the struct.111/// This function *does* register the `src_hash` dependency on the struct.
118pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {112pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
119 const pt = sema.pt;113 const pt = sema.pt;
120 const zcu = pt.zcu;114 const zcu = pt.zcu;
121 const comp = zcu.comp;115 const comp = zcu.comp;
116 const io = comp.io;
122 const gpa = comp.gpa;117 const gpa = comp.gpa;
123 const ip = &zcu.intern_pool;118 const ip = &zcu.intern_pool;
124119
...@@ -127,10 +122,6 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {...@@ -127,10 +122,6 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
127 const struct_obj = ip.loadStructType(struct_ty.toIntern());122 const struct_obj = ip.loadStructType(struct_ty.toIntern());
128 const zir_index = struct_obj.zir_index.resolve(ip).?;123 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
134 var block: Block = .{125 var block: Block = .{
135 .parent = null,126 .parent = null,
136 .sema = sema,127 .sema = sema,
...@@ -143,39 +134,92 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {...@@ -143,39 +134,92 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
143 };134 };
144 defer assert(block.instructions.items.len == 0);135 defer assert(block.instructions.items.len == 0);
145136
146 const zir_struct = sema.code.getStructDecl(zir_index);137 // There may be old field names in here from a previous update.
147 var field_it = zir_struct.iterateFields();138 struct_obj.field_name_map.get(ip).clearRetainingCapacity();
148 while (field_it.next()) |zir_field| {139
149 const field_ty_src: LazySrcLoc = .{140 if (struct_obj.is_reified) {
150 .base_node_inst = struct_obj.zir_index,141 // The field names are populated, but we haven't checked for duplicates (nor populated the map) yet.
151 .offset = .{ .container_field_type = zir_field.idx },142 for (0..struct_obj.field_names.len) |field_index| {
152 };143 const name = struct_obj.field_names.get(ip)[field_index];
153 const field_align_src: LazySrcLoc = .{144 if (ip.addFieldName(struct_obj.field_names, struct_obj.field_name_map, name)) |prev_field_index| {
154 .base_node_inst = struct_obj.zir_index,145 return sema.failWithOwnedErrorMsg(&block, msg: {
155 .offset = .{ .container_field_align = zir_field.idx },146 const src = block.nodeOffset(.zero);
156 };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: {176 if (zir_field.is_comptime) {
159 block.comptime_reason = .{ .reason = .{177 const bit_bag_index = zir_field.idx / 32;
160 .src = field_ty_src,178 const mask = @as(u32, 1) << @intCast(zir_field.idx % 32);
161 .r = .{ .simple = .struct_field_types },179 struct_obj.field_is_comptime_bits.getAll(ip)[bit_bag_index] |= mask;
162 } };180 }
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());
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: {195 if (struct_obj.field_aligns.len == 0) {
171 block.comptime_reason = .{ .reason = .{196 assert(zir_field.align_body == null);
172 .src = field_align_src,197 } else {
173 .r = .{ .simple = .struct_field_attrs },198 const field_align_src = block.src(.{ .container_field_align = zir_field.idx });
174 } };199 const field_align: Alignment = a: {
175 const align_body = zir_field.align_body orelse break :a .none;200 block.comptime_reason = .{ .reason = .{
176 const align_ref = try sema.resolveInlineBody(&block, align_body, zir_index);201 .src = field_align_src,
177 break :a try sema.analyzeAsAlign(&block, field_align_src, align_ref);202 .r = .{ .simple = .struct_field_attrs },
178 };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
180 if (field_ty.zigTypeTag(zcu) == .@"opaque") {224 if (field_ty.zigTypeTag(zcu) == .@"opaque") {
181 return sema.failWithOwnedErrorMsg(&block, msg: {225 return sema.failWithOwnedErrorMsg(&block, msg: {
...@@ -186,7 +230,8 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {...@@ -186,7 +230,8 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
186 break :msg msg;230 break :msg msg;
187 });231 });
188 }232 }
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)) {
190 return sema.failWithOwnedErrorMsg(&block, msg: {235 return sema.failWithOwnedErrorMsg(&block, msg: {
191 const msg = try sema.errMsg(field_ty_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});236 const msg = try sema.errMsg(field_ty_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
192 errdefer msg.destroy(gpa);237 errdefer msg.destroy(gpa);
...@@ -195,35 +240,14 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {...@@ -195,35 +240,14 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
195 break :msg msg;240 break :msg msg;
196 });241 });
197 }242 }
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 }
205 }243 }
206244
207 try finishStructLayout(sema, &block, struct_ty.srcLoc(zcu), struct_ty.toIntern(), &struct_obj);245 // Fields are okay. Now we need to resolve the struct's overall layout (size, field offsets, etc).
208}
209246
210/// Called after populating field types and alignments; populates field offsets, runtime order, and247 var any_comptime_fields = false;
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;
225 var comptime_only = false;248 var comptime_only = false;
226 var one_possible_value = true;249 var one_possible_value = true;
250 var has_runtime_bits = false;
227 var struct_align: Alignment = .@"1";251 var struct_align: Alignment = .@"1";
228 // Unlike `struct_obj.field_aligns`, these are not `.none`.252 // Unlike `struct_obj.field_aligns`, these are not `.none`.
229 const resolved_field_aligns = try sema.arena.alloc(Alignment, struct_obj.field_names.len);253 const resolved_field_aligns = try sema.arena.alloc(Alignment, struct_obj.field_names.len);
...@@ -240,12 +264,15 @@ pub fn finishStructLayout(...@@ -240,12 +264,15 @@ pub fn finishStructLayout(
240 // Non-`comptime` fields contribute to the struct's layout.264 // Non-`comptime` fields contribute to the struct's layout.
241 struct_align = struct_align.maxStrict(field_align);265 struct_align = struct_align.maxStrict(field_align);
242 if (field_ty.comptimeOnly(zcu)) comptime_only = true;266 if (field_ty.comptimeOnly(zcu)) comptime_only = true;
267 if (field_ty.hasRuntimeBits(zcu)) has_runtime_bits = true;
243 if (try field_ty.onePossibleValue(pt) == null) one_possible_value = false;268 if (try field_ty.onePossibleValue(pt) == null) one_possible_value = false;
244 if (struct_obj.layout == .auto) {269 if (struct_obj.layout == .auto) {
245 struct_obj.field_runtime_order.get(ip)[field_idx] = @enumFromInt(field_idx);270 struct_obj.field_runtime_order.get(ip)[field_idx] = @enumFromInt(field_idx);
246 }271 }
247 } else if (struct_obj.layout == .auto) {272 } else {
273 assert(struct_obj.layout == .auto); // comptime fields not allowed in extern or packed structs
248 struct_obj.field_runtime_order.get(ip)[field_idx] = .omitted; // comptime fields are not in the runtime order274 struct_obj.field_runtime_order.get(ip)[field_idx] = .omitted; // comptime fields are not in the runtime order
275 any_comptime_fields = true;
249 }276 }
250 align_out.* = field_align;277 align_out.* = field_align;
251 }278 }
...@@ -297,75 +324,53 @@ pub fn finishStructLayout(...@@ -297,75 +324,53 @@ pub fn finishStructLayout(
297 cur_offset = offset + field_ty.abiSize(zcu);324 cur_offset = offset + field_ty.abiSize(zcu);
298 }325 }
299 const struct_size = std.math.cast(u32, struct_align.forward(cur_offset)) orelse return sema.fail(326 const struct_size = std.math.cast(u32, struct_align.forward(cur_offset)) orelse return sema.fail(
300 block,327 &block,
301 struct_src,328 struct_ty.srcLoc(zcu),
302 "struct layout requires size {d}, this compiler implementation supports up to {d}",329 "struct layout requires size {d}, this compiler implementation supports up to {d}",
303 .{ struct_align.forward(cur_offset), std.math.maxInt(u32) },330 .{ struct_align.forward(cur_offset), std.math.maxInt(u32) },
304 );331 );
305 ip.resolveStructLayout(332 ip.resolveStructLayout(
306 io,333 io,
307 struct_ty,334 struct_ty.toIntern(),
308 struct_size,335 struct_size,
309 struct_align,336 struct_align,
310 false, // MLUGG TODO XXX NPV337 false, // MLUGG TODO XXX NPV
311 one_possible_value,338 one_possible_value,
312 comptime_only,339 comptime_only,
340 has_runtime_bits,
313 );341 );
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 }
314}347}
315348
316/// Asserts that `struct_ty` is a packed struct, and that `sema.owner` is that type.349/// Asserts that `struct_ty` is a packed struct, and that `sema.owner` is that type.
317/// This function *does* register the `src_hash` dependency on the struct.350/// 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 {
319 const pt = sema.pt;357 const pt = sema.pt;
320 const zcu = pt.zcu;358 const zcu = pt.zcu;
321 const comp = zcu.comp;359 const comp = zcu.comp;
360 const io = comp.io;
322 const gpa = comp.gpa;361 const gpa = comp.gpa;
323 const ip = &zcu.intern_pool;362 const ip = &zcu.intern_pool;
324363
325 assert(sema.owner.unwrap().type_layout == struct_ty.toIntern());364 // Resolve the layout of all fields, and check their types are allowed.
326365 // Also count the number of bits while we're at it.
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
346 var field_bits: u64 = 0;366 var field_bits: u64 = 0;
347 const zir_struct = sema.code.getStructDecl(zir_index);367 for (struct_obj.field_types.get(ip), 0..) |field_ty_ip, field_index| {
348 var field_it = zir_struct.iterateFields();368 const field_ty: Type = .fromInterned(field_ty_ip);
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 };
362 assert(!field_ty.isGenericPoison());369 assert(!field_ty.isGenericPoison());
363 struct_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern();370 const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) });
364
365 try sema.ensureLayoutResolved(field_ty);371 try sema.ensureLayoutResolved(field_ty);
366
367 if (field_ty.zigTypeTag(zcu) == .@"opaque") {372 if (field_ty.zigTypeTag(zcu) == .@"opaque") {
368 return sema.failWithOwnedErrorMsg(&block, msg: {373 return sema.failWithOwnedErrorMsg(block, msg: {
369 const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in struct", .{field_ty.fmt(pt)});374 const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in struct", .{field_ty.fmt(pt)});
370 errdefer msg.destroy(gpa);375 errdefer msg.destroy(gpa);
371 try sema.errNote(field_ty_src, msg, "opaque types have unknown size", .{});376 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...@@ -373,62 +378,73 @@ pub fn resolvePackedStructLayout(sema: *Sema, struct_ty: Type) CompileError!void
373 break :msg msg;378 break :msg msg;
374 });379 });
375 }380 }
376 if (!field_ty.packable(zcu)) {381 if (field_ty.unpackable(zcu)) |reason| return sema.failWithOwnedErrorMsg(block, msg: {
377 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)});
378 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);
379 errdefer msg.destroy(gpa);384 try sema.explainWhyTypeIsUnpackable(msg, field_ty_src, reason);
380 try sema.explainWhyTypeIsNotPackable(msg, field_ty_src, field_ty);385 try sema.addDeclaredHereNote(msg, field_ty);
381 try sema.addDeclaredHereNote(msg, field_ty);386 break :msg msg;
382 break :msg msg;387 });
383 });
384 }
385 assert(!field_ty.comptimeOnly(zcu)); // packable types are not comptime-only388 assert(!field_ty.comptimeOnly(zcu)); // packable types are not comptime-only
386 field_bits += field_ty.bitSize(zcu);389 field_bits += field_ty.bitSize(zcu);
387 }390 }
388391
389 try resolvePackedStructBackingInt(sema, &block, field_bits, struct_ty, &struct_obj);392 const explicit_backing_int_ty: ?Type = if (struct_obj.is_reified) ty: {
390}393 break :ty switch (struct_obj.packed_backing_mode) {
391394 .explicit => .fromInterned(struct_obj.packed_backing_int_type),
392pub fn resolvePackedStructBackingInt(395 .auto => null,
393 sema: *Sema,396 };
394 block: *Block,397 } else ty: {
395 field_bits: u64,398 const zir_index = struct_obj.zir_index.resolve(ip).?;
396 struct_ty: Type,399 const zir_struct = sema.code.getStructDecl(zir_index);
397 struct_obj: *const InternPool.LoadedStructType,400 const backing_int_type_body = zir_struct.backing_int_type_body orelse {
398) SemaError!void {401 break :ty null; // inferred backing type
399 const pt = sema.pt;402 };
400 const zcu = pt.zcu;403 // Explicitly specified, so evaluate the backing int type expression.
401 const comp = zcu.comp;404 const backing_int_type_src = block.src(.container_arg);
402 const gpa = comp.gpa;405 block.comptime_reason = .{ .reason = .{
403 const io = comp.io;406 .src = backing_int_type_src,
404 const ip = &zcu.intern_pool;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) {413 // Finally, either validate or infer the backing int type.
407 .explicit => {414 const backing_int_ty: Type = if (explicit_backing_int_ty) |backing_ty| ty: {
408 // We only need to validate the type.415 // We only need to validate the type.
409 const backing_ty: Type = .fromInterned(struct_obj.packed_backing_int_type);416 if (backing_ty.zigTypeTag(zcu) != .int) return sema.failWithOwnedErrorMsg(block, msg: {
410 assert(backing_ty.zigTypeTag(zcu) == .int);417 const src = struct_ty.srcLoc(zcu);
411 if (field_bits != backing_ty.intInfo(zcu).bits) return sema.failWithOwnedErrorMsg(block, msg: {418 const msg = try sema.errMsg(src, "expected backing integer type, found '{f}'", .{backing_ty.fmt(pt)});
412 const src = struct_ty.srcLoc(zcu);419 errdefer msg.destroy(gpa);
413 const msg = try sema.errMsg(src, "backing integer bit width does not match total bit width of fields", .{});420 try sema.errNote(src, msg, "backing integer '{f}' has bit width '{d}'", .{ backing_ty.fmt(pt), backing_ty.bitSize(zcu) });
414 errdefer msg.destroy(gpa);421 try sema.errNote(src, msg, "struct fields have total bit width '{d}'", .{field_bits});
415 try sema.errNote(src, msg, "backing integer '{f}' has bit width '{d}'", .{ backing_ty.fmt(pt), backing_ty.bitSize(zcu) });422 break :msg msg;
416 try sema.errNote(src, msg, "struct fields have total bit width '{d}'", .{field_bits});423 });
417 break :msg msg;424 if (field_bits != backing_ty.intInfo(zcu).bits) return sema.failWithOwnedErrorMsg(block, msg: {
418 });425 const src = struct_ty.srcLoc(zcu);
419 },426 const msg = try sema.errMsg(src, "backing integer bit width does not match total bit width of fields", .{});
420 .auto => {427 errdefer msg.destroy(gpa);
421 // We need to generate the inferred tag.428 try sema.errNote(src, msg, "backing integer '{f}' has bit width '{d}'", .{ backing_ty.fmt(pt), backing_ty.bitSize(zcu) });
422 const want_bits = std.math.cast(u16, field_bits) orelse return sema.fail(429 try sema.errNote(src, msg, "struct fields have total bit width '{d}'", .{field_bits});
423 block,430 break :msg msg;
424 struct_ty.srcLoc(zcu),431 });
425 "packed struct bit width '{d}' exceeds maximum bit width of 65535",432 break :ty backing_ty;
426 .{field_bits},433 } else ty: {
427 );434 // We need to generate the inferred tag.
428 const backing_int = try pt.intType(.unsigned, want_bits);435 const backing_int_bits = std.math.cast(u16, field_bits) orelse return sema.fail(
429 ip.resolvePackedStructBackingInt(io, struct_ty.toIntern(), backing_int.toIntern());436 block,
430 },437 struct_ty.srcLoc(zcu),
431 }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 );
432}448}
433449
434/// Asserts that `struct_ty` is a non-tuple struct, and that `sema.owner` is that type.450/// Asserts that `struct_ty` is a non-tuple struct, and that `sema.owner` is that type.
...@@ -436,25 +452,33 @@ pub fn resolvePackedStructBackingInt(...@@ -436,25 +452,33 @@ pub fn resolvePackedStructBackingInt(
436pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void {452pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void {
437 const pt = sema.pt;453 const pt = sema.pt;
438 const zcu = pt.zcu;454 const zcu = pt.zcu;
439 const comp = zcu.comp;
440 const gpa = comp.gpa;
441 const ip = &zcu.intern_pool;455 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
445 try sema.ensureLayoutResolved(struct_ty);459 try sema.ensureLayoutResolved(struct_ty);
446460
447 const struct_obj = ip.loadStructType(struct_ty.toIntern());461 const struct_obj = ip.loadStructType(struct_ty.toIntern());
448 const zir_index = struct_obj.zir_index.resolve(ip).?;
449462
450 try sema.declareDependency(.{ .src_hash = struct_obj.zir_index });463 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
452 if (struct_obj.field_defaults.len == 0) {470 if (struct_obj.field_defaults.len == 0) {
453 // The struct has no default field values, so the slice has been omitted.471 // The struct has no default field values, so the slice has been omitted.
454 return;472 return;
455 }473 }
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
459 var block: Block = .{483 var block: Block = .{
460 .parent = null,484 .parent = null,
...@@ -468,16 +492,30 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void {...@@ -468,16 +492,30 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void {
468 };492 };
469 defer assert(block.instructions.items.len == 0);493 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
471 // We'll need to map the struct decl instruction to provide result types509 // We'll need to map the struct decl instruction to provide result types
510 const zir_index = struct_obj.zir_index.resolve(ip).?;
472 try sema.inst_map.ensureSpaceForInstructions(gpa, &.{zir_index});511 try sema.inst_map.ensureSpaceForInstructions(gpa, &.{zir_index});
473512
513 const field_types = struct_obj.field_types.get(ip);
514
474 const zir_struct = sema.code.getStructDecl(zir_index);515 const zir_struct = sema.code.getStructDecl(zir_index);
475 var field_it = zir_struct.iterateFields();516 var field_it = zir_struct.iterateFields();
476 while (field_it.next()) |zir_field| {517 while (field_it.next()) |zir_field| {
477 const default_val_src: LazySrcLoc = .{518 const default_val_src = block.src(.{ .container_field_value = zir_field.idx });
478 .base_node_inst = struct_obj.zir_index,
479 .offset = .{ .container_field_value = zir_field.idx },
480 };
481 block.comptime_reason = .{ .reason = .{519 block.comptime_reason = .{ .reason = .{
482 .src = default_val_src,520 .src = default_val_src,
483 .r = .{ .simple = .struct_field_default_value },521 .r = .{ .simple = .struct_field_default_value },
...@@ -491,13 +529,13 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void {...@@ -491,13 +529,13 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void {
491 // Provide the result type529 // Provide the result type
492 sema.inst_map.putAssumeCapacity(zir_index, .fromIntern(field_ty.toIntern()));530 sema.inst_map.putAssumeCapacity(zir_index, .fromIntern(field_ty.toIntern()));
493 defer assert(sema.inst_map.remove(zir_index));531 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);
495 };533 };
496 const coerced = try sema.coerce(&block, field_ty, uncoerced, default_val_src);534 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);535 const default_val = try sema.resolveConstValue(block, default_val_src, coerced, null);
498 if (default_val.canMutateComptimeVarState(zcu)) {536 if (default_val.canMutateComptimeVarState(zcu)) {
499 const field_name = struct_obj.field_names.get(ip)[zir_field.idx];537 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);
501 }539 }
502 struct_obj.field_defaults.get(ip)[zir_field.idx] = default_val.toIntern();540 struct_obj.field_defaults.get(ip)[zir_field.idx] = default_val.toIntern();
503 }541 }
...@@ -508,6 +546,7 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {...@@ -508,6 +546,7 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
508 const pt = sema.pt;546 const pt = sema.pt;
509 const zcu = pt.zcu;547 const zcu = pt.zcu;
510 const comp = zcu.comp;548 const comp = zcu.comp;
549 const io = comp.io;
511 const gpa = comp.gpa;550 const gpa = comp.gpa;
512 const ip = &zcu.intern_pool;551 const ip = &zcu.intern_pool;
513552
...@@ -516,10 +555,6 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {...@@ -516,10 +555,6 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
516 const union_obj = ip.loadUnionType(union_ty.toIntern());555 const union_obj = ip.loadUnionType(union_ty.toIntern());
517 const zir_index = union_obj.zir_index.resolve(ip).?;556 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
523 var block: Block = .{558 var block: Block = .{
524 .parent = null,559 .parent = null,
525 .sema = sema,560 .sema = sema,
...@@ -532,48 +567,169 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {...@@ -532,48 +567,169 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
532 };567 };
533 defer assert(block.instructions.items.len == 0);568 defer assert(block.instructions.items.len == 0);
534569
535 const zir_union = sema.code.getUnionDecl(zir_index);570 // MLUGG TODO: this is fucking ugly bro
536 var field_it = zir_union.iterateFields();571 const explicit_enum_tag_ty: ?Type = if (union_obj.is_reified) ty: {
537 while (field_it.next()) |zir_field| {572 break :ty switch (union_obj.enum_tag_mode) {
538 const field_ty_src: LazySrcLoc = .{573 .explicit => .fromInterned(union_obj.enum_tag_type),
539 .base_node_inst = union_obj.zir_index,574 .auto => null,
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 },
545 };575 };
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: {637 try sema.ensureLayoutResolved(enum_tag_ty);
548 block.comptime_reason = .{ .reason = .{638 const enum_obj = ip.loadEnumType(enum_tag_ty.toIntern());
549 .src = field_ty_src,639
550 .r = .{ .simple = .union_field_types },640 if (union_obj.is_reified) {
551 } };641 // We have field names in `union_obj.reified_field_names`, but we haven't
552 const type_body = zir_field.type_body orelse break :field_ty .void;642 // checked them against the backing type yet.
553 const type_ref = try sema.resolveInlineBody(&block, type_body, zir_index);643 const union_field_names = union_obj.reified_field_names.get(ip);
554 break :field_ty try sema.analyzeAsType(&block, field_ty_src, type_ref);644 match_fields: {
555 };645 // We can efficiently *check* if the fields match...
556 assert(!field_ty.isGenericPoison());646 if (union_field_names.len == enum_obj.field_names.len) {
557 union_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern();647 for (union_field_names, enum_obj.field_names.get(ip)) |union_field_name, enum_field_name| {
558648 if (!std.mem.eql(u8, union_field_name.toSlice(ip), enum_field_name.toSlice(ip))) break;
559 try sema.ensureLayoutResolved(field_ty);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: {666 // We'll first check the field names against the backing enum, and only analyze the types
562 block.comptime_reason = .{ .reason = .{667 // once we know the fields match one-to-one.
563 .src = field_align_src,668 match_fields: {
564 .r = .{ .simple = .union_field_attrs },669 // We can efficiently *check* if the fields match...
565 } };670 if (zir_union.field_names.len == enum_obj.field_names.len) {
566 const align_body = zir_field.align_body orelse break :a .none;671 for (zir_union.field_names, enum_obj.field_names.get(ip)) |union_field_name_zir, enum_field_name| {
567 const align_ref = try sema.resolveInlineBody(&block, align_body, zir_index);672 const union_field_name_slice = sema.code.nullTerminatedString(union_field_name_zir);
568 break :a try sema.analyzeAsAlign(&block, field_align_src, align_ref);673 if (!std.mem.eql(u8, union_field_name_slice, enum_field_name.toSlice(ip))) break;
569 };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) {690 // Field names okay; populate types and aligns.
572 union_obj.field_aligns.get(ip)[zir_field.idx] = explicit_field_align;691 var field_it = zir_union.iterateFields();
573 } else {692 while (field_it.next()) |zir_field| {
574 assert(explicit_field_align == .none);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 }
575 }720 }
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);
577 if (field_ty.zigTypeTag(zcu) == .@"opaque") {733 if (field_ty.zigTypeTag(zcu) == .@"opaque") {
578 return sema.failWithOwnedErrorMsg(&block, msg: {734 return sema.failWithOwnedErrorMsg(&block, msg: {
579 const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in union", .{field_ty.fmt(pt)});735 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 {...@@ -583,7 +739,7 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
583 break :msg msg;739 break :msg msg;
584 });740 });
585 }741 }
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)) {
587 return sema.failWithOwnedErrorMsg(&block, msg: {743 return sema.failWithOwnedErrorMsg(&block, msg: {
588 const msg = try sema.errMsg(field_ty_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});744 const msg = try sema.errMsg(field_ty_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
589 errdefer msg.destroy(gpa);745 errdefer msg.destroy(gpa);
...@@ -594,36 +750,11 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {...@@ -594,36 +750,11 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
594 }750 }
595 }751 }
596752
597 try finishUnionLayout(753 // Fields are okay. Now we need to resolve the union's overall layout (size, alignment, etc).
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
624 var payload_align: Alignment = .@"1";754 var payload_align: Alignment = .@"1";
625 var payload_size: u64 = 0;755 var payload_size: u64 = 0;
626 var comptime_only = false;756 var comptime_only = false;
757 var has_runtime_bits = union_obj.runtime_tag != .none and enum_tag_ty.hasRuntimeBits(zcu);
627 var possible_values: enum { none, one, many } = .none;758 var possible_values: enum { none, one, many } = .none;
628 for (0..union_obj.field_types.len) |field_idx| {759 for (0..union_obj.field_types.len) |field_idx| {
629 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_idx]);760 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_idx]);
...@@ -637,6 +768,7 @@ pub fn finishUnionLayout(...@@ -637,6 +768,7 @@ pub fn finishUnionLayout(
637 payload_align = payload_align.maxStrict(field_align);768 payload_align = payload_align.maxStrict(field_align);
638 payload_size = @max(payload_size, field_ty.abiSize(zcu));769 payload_size = @max(payload_size, field_ty.abiSize(zcu));
639 if (field_ty.comptimeOnly(zcu)) comptime_only = true;770 if (field_ty.comptimeOnly(zcu)) comptime_only = true;
771 if (field_ty.hasRuntimeBits(zcu)) has_runtime_bits = true;
640 if (!field_ty.isNoReturn(zcu)) {772 if (!field_ty.isNoReturn(zcu)) {
641 if (try field_ty.onePossibleValue(pt) != null) {773 if (try field_ty.onePossibleValue(pt) != null) {
642 possible_values = .many; // this field alone has many possible values774 possible_values = .many; // this field alone has many possible values
...@@ -664,78 +796,100 @@ pub fn finishUnionLayout(...@@ -664,78 +796,100 @@ pub fn finishUnionLayout(
664 };796 };
665797
666 const casted_size = std.math.cast(u32, size) orelse return sema.fail(798 const casted_size = std.math.cast(u32, size) orelse return sema.fail(
667 block,799 &block,
668 union_src,800 union_ty.srcLoc(zcu),
669 "union layout requires size {d}, this compiler implementation supports up to {d}",801 "union layout requires size {d}, this compiler implementation supports up to {d}",
670 .{ size, std.math.maxInt(u32) },802 .{ size, std.math.maxInt(u32) },
671 );803 );
672 ip.resolveUnionLayout(804 ip.resolveUnionLayout(
673 io,805 io,
674 union_ty,806 union_ty.toIntern(),
807 enum_tag_ty.toIntern(),
675 casted_size,808 casted_size,
676 @intCast(padding), // okay because padding is no greater than size809 @intCast(padding), // okay because padding is no greater than size
677 alignment,810 alignment,
678 possible_values == .none, // MLUGG TODO: make sure queries use `LoadedUnionType.has_no_possible_value`!811 possible_values == .none, // MLUGG TODO: make sure queries use `LoadedUnionType.has_no_possible_value`!
679 possible_values == .one,812 possible_values == .one,
680 comptime_only,813 comptime_only,
814 has_runtime_bits,
681 );815 );
682}816}
683817fn failUnionFieldMismatch(sema: *Sema, block: *Block, union_field_names: []const InternPool.NullTerminatedString, enum_tag_ty: Type, enum_obj: *const InternPool.LoadedEnumType) CompileError {
684pub fn resolvePackedUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
685 const pt = sema.pt;818 const pt = sema.pt;
686 const zcu = pt.zcu;819 const zcu = pt.zcu;
687 const comp = zcu.comp;820 const comp = zcu.comp;
688 const gpa = comp.gpa;821 const gpa = comp.gpa;
689 const ip = &zcu.intern_pool;822 const ip = &zcu.intern_pool;
690823 const enum_to_union_map = try sema.arena.alloc(?u32, enum_obj.field_names.len);
691 assert(sema.owner.unwrap().type_layout == union_ty.toIntern());824 @memset(enum_to_union_map, null);
692825 for (union_field_names, 0..) |field_name, union_field_index| {
693 const union_obj = ip.loadUnionType(union_ty.toIntern());826 if (enum_obj.nameIndex(ip, field_name)) |enum_field_index| {
694 const zir_index = union_obj.zir_index.resolve(ip).?;827 enum_to_union_map[enum_field_index] = @intCast(union_field_index);
695828 continue;
696 assert(union_obj.layout == .@"packed");829 }
697830 const union_field_src = block.src(.{ .container_field_name = @intCast(union_field_index) });
698 try sema.declareDependency(.{ .src_hash = union_obj.zir_index });831 return sema.failWithOwnedErrorMsg(block, msg: {
699832 const msg = try sema.errMsg(union_field_src, "no field named '{f}' in enum '{f}'", .{ field_name.fmt(ip), enum_tag_ty.fmt(pt) });
700 var block: Block = .{833 errdefer msg.destroy(gpa);
701 .parent = null,834 try sema.addDeclaredHereNote(msg, enum_tag_ty);
702 .sema = sema,835 break :msg msg;
703 .namespace = union_obj.namespace,836 });
704 .instructions = .{},837 }
705 .inlining = null,838 for (enum_to_union_map, 0..) |union_field_index, enum_field_index| {
706 .comptime_reason = undefined, // always set before using `block`839 if (union_field_index != null) continue;
707 .src_base_inst = union_obj.zir_index,840 const field_name_ip = enum_obj.field_names.get(ip)[enum_field_index];
708 .type_name_ctx = union_obj.name,841 const enum_field_src: LazySrcLoc = .{
709 };842 .base_node_inst = enum_tag_ty.typeDeclInstAllowGeneratedTag(zcu).?,
710 defer assert(block.instructions.items.len == 0);843 .offset = .{ .container_field_name = @intCast(enum_field_index) },
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 },
718 };844 };
719 const field_ty: Type = field_ty: {845 return sema.failWithOwnedErrorMsg(block, msg: {
720 block.comptime_reason = .{ .reason = .{846 const msg = try sema.errMsg(block.nodeOffset(.zero), "enum field '{f}' missing from union", .{field_name_ip.fmt(ip)});
721 .src = field_ty_src,847 errdefer msg.destroy(gpa);
722 .r = .{ .simple = .union_field_types },848 try sema.errNote(enum_field_src, msg, "enum field here", .{});
723 } };849 break :msg msg;
724 // MLUGG TODO: i think this should probably be a compile error? (if so, it's an astgen one, right?)850 });
725 const type_body = zir_field.type_body orelse break :field_ty .void;851 }
726 const type_ref = try sema.resolveInlineBody(&block, type_body, zir_index);852 // The only problem is the field ordering.
727 break :field_ty try sema.analyzeAsType(&block, field_ty_src, type_ref);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) },
728 };860 };
729 assert(!field_ty.isGenericPoison());861 return sema.failWithOwnedErrorMsg(block, msg: {
730 union_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern();862 const msg = try sema.errMsg(block.nodeOffset(.zero), "union field order does not match tag enum field order", .{});
731863 errdefer msg.destroy(gpa);
732 assert(zir_field.align_body == null); // packed union fields cannot be aligned864 try sema.errNote(union_field_src, msg, "union field '{f}' is index {d}", .{ field_name.fmt(ip), union_field_index.? });
733 assert(zir_field.value_body == null); // packed union fields cannot have tag values865 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) });
735 try sema.ensureLayoutResolved(field_ty);890 try sema.ensureLayoutResolved(field_ty);
736
737 if (field_ty.zigTypeTag(zcu) == .@"opaque") {891 if (field_ty.zigTypeTag(zcu) == .@"opaque") {
738 return sema.failWithOwnedErrorMsg(&block, msg: {892 return sema.failWithOwnedErrorMsg(block, msg: {
739 const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in union", .{field_ty.fmt(pt)});893 const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in union", .{field_ty.fmt(pt)});
740 errdefer msg.destroy(gpa);894 errdefer msg.destroy(gpa);
741 try sema.errNote(field_ty_src, msg, "opaque types have unknown size", .{});895 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 {...@@ -743,132 +897,109 @@ pub fn resolvePackedUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
743 break :msg msg;897 break :msg msg;
744 });898 });
745 }899 }
746 if (!field_ty.packable(zcu)) {900 if (field_ty.unpackable(zcu)) |reason| return sema.failWithOwnedErrorMsg(block, msg: {
747 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)});
748 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", .{});
749 errdefer msg.destroy(gpa);940 errdefer msg.destroy(gpa);
750 try sema.explainWhyTypeIsNotPackable(msg, field_ty_src, field_ty);941 try sema.errNote(field_ty_src, msg, "field type '{f}' has bit width '{d}'", .{ field_type.fmt(pt), field_bits });
751 try sema.addDeclaredHereNote(msg, field_ty);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", .{});
752 break :msg msg;944 break :msg msg;
753 });945 });
754 }946 }
755 assert(!field_ty.comptimeOnly(zcu)); // packable types are not comptime-only947 break :ty backing_ty;
756 }948 } else if (union_obj.field_types.len == 0) ty: {
757949 // Special case: there is no first field to infer the type from. Treat the union as empty (zero-bit).
758 try resolvePackedUnionBackingInt(sema, &block, union_ty, &union_obj, false);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 );
759}983}
760984
761/// MLUGG TODO doc comment; asserts all fields are resolved or whatever985pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void {
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 {
769 const pt = sema.pt;986 const pt = sema.pt;
770 const zcu = pt.zcu;987 const zcu = pt.zcu;
771 const comp = zcu.comp;988 const comp = zcu.comp;
772 const gpa = comp.gpa;
773 const io = comp.io;989 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;
850 const gpa = comp.gpa;990 const gpa = comp.gpa;
851 const ip = &zcu.intern_pool;991 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
855 const enum_obj = ip.loadEnumType(enum_ty.toIntern());995 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
864 const maybe_parent_union_obj: ?InternPool.LoadedUnionType = un: {997 const maybe_parent_union_obj: ?InternPool.LoadedUnionType = un: {
865 if (enum_obj.owner_union == .none) break :un null;998 if (enum_obj.owner_union == .none) break :un null;
866 break :un ip.loadUnionType(enum_obj.owner_union);999 break :un ip.loadUnionType(enum_obj.owner_union);
867 };1000 };
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
873 var block: Block = .{1004 var block: Block = .{
874 .parent = null,1005 .parent = null,
...@@ -882,7 +1013,139 @@ pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void {...@@ -882,7 +1013,139 @@ pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void {
882 };1013 };
883 defer assert(block.instructions.items.len == 0);1014 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
887 // Map the enum (or union) decl instruction to provide the tag type as the result type1150 // Map the enum (or union) decl instruction to provide the tag type as the result type
888 try sema.inst_map.ensureSpaceForInstructions(gpa, &.{zir_index});1151 try sema.inst_map.ensureSpaceForInstructions(gpa, &.{zir_index});
...@@ -891,36 +1154,38 @@ pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void {...@@ -891,36 +1154,38 @@ pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void {
8911154
892 // First, populate any explicitly provided values. This is the part that actually depends on1155 // First, populate any explicitly provided values. This is the part that actually depends on
893 // the ZIR, and hence depends on whether this is a declared or generated enum. If any explicit1156 // 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.
895 if (maybe_parent_union_obj) |union_obj| {1158 if (maybe_parent_union_obj) |union_obj| {
896 const zir_union = sema.code.getUnionDecl(zir_index);1159 if (union_obj.is_reified) {
897 var field_it = zir_union.iterateFields();1160 // Generated tag type for reified union; values already populated.
898 while (field_it.next()) |zir_field| {1161 } else {
899 const field_val_src: LazySrcLoc = .{1162 // Generated tag type for declared union; evaluate the expressions given in the union declaration.
900 .base_node_inst = union_obj.zir_index,1163 const zir_union = sema.code.getUnionDecl(zir_index);
901 .offset = .{ .container_field_value = zir_field.idx },1164 var field_it = zir_union.iterateFields();
902 };1165 while (field_it.next()) |zir_field| {
903 block.comptime_reason = .{ .reason = .{1166 const field_val_src = block.src(.{ .container_field_value = zir_field.idx });
904 .src = field_val_src,1167 block.comptime_reason = .{ .reason = .{
905 .r = .{ .simple = .enum_field_values },1168 .src = field_val_src,
906 } };1169 .r = .{ .simple = .enum_field_values },
907 const value_body = zir_field.value_body orelse {1170 } };
908 enum_obj.field_values.get(ip)[zir_field.idx] = .none;1171 const value_body = zir_field.value_body orelse {
909 continue;1172 enum_obj.field_values.get(ip)[zir_field.idx] = .none;
910 };1173 continue;
911 const uncoerced = try sema.resolveInlineBody(&block, value_body, zir_index);1174 };
912 const coerced = try sema.coerce(&block, int_tag_ty, uncoerced, field_val_src);1175 const uncoerced = try sema.resolveInlineBody(&block, value_body, zir_index);
913 const val = try sema.resolveConstValue(&block, field_val_src, coerced, null);1176 const coerced = try sema.coerce(&block, int_tag_ty, uncoerced, field_val_src);
914 enum_obj.field_values.get(ip)[zir_field.idx] = val.toIntern();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 }
915 }1180 }
1181 } else if (enum_obj.is_reified) {
1182 // Reified enum; values already populated.
916 } else {1183 } else {
1184 // Declared enum; evaluate the expressions given in the enum declaration.
917 const zir_enum = sema.code.getEnumDecl(zir_index);1185 const zir_enum = sema.code.getEnumDecl(zir_index);
918 var field_it = zir_enum.iterateFields();1186 var field_it = zir_enum.iterateFields();
919 while (field_it.next()) |zir_field| {1187 while (field_it.next()) |zir_field| {
920 const field_val_src: LazySrcLoc = .{1188 const field_val_src = block.src(.{ .container_field_value = zir_field.idx });
921 .base_node_inst = enum_obj.zir_index.unwrap().?,
922 .offset = .{ .container_field_value = zir_field.idx },
923 };
924 block.comptime_reason = .{ .reason = .{1189 block.comptime_reason = .{ .reason = .{
925 .src = field_val_src,1190 .src = field_val_src,
926 .r = .{ .simple = .enum_field_values },1191 .r = .{ .simple = .enum_field_values },
...@@ -940,14 +1205,14 @@ pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void {...@@ -940,14 +1205,14 @@ pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void {
940 // field values. This is also where we'll detect duplicates.1205 // field values. This is also where we'll detect duplicates.
9411206
942 for (0..enum_obj.field_names.len) |field_idx| {1207 for (0..enum_obj.field_names.len) |field_idx| {
943 const field_val_src: LazySrcLoc = .{1208 const field_val_src = block.src(.{ .container_field_value = @intCast(field_idx) });
944 .base_node_inst = tracked_inst,
945 .offset = .{ .container_field_value = @intCast(field_idx) },
946 };
947 // If the field value was not specified, compute the implicit value.1209 // If the field value was not specified, compute the implicit value.
948 const field_val = val: {1210 const field_val = val: {
949 const explicit_val = enum_obj.field_values.get(ip)[field_idx];1211 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 }
951 if (field_idx == 0) {1216 if (field_idx == 0) {
952 // Implicit value is 0, which is valid for every integer type.1217 // Implicit value is 0, which is valid for every integer type.
953 const val = (try pt.intValue(int_tag_ty, 0)).toIntern();1218 const val = (try pt.intValue(int_tag_ty, 0)).toIntern();
...@@ -967,23 +1232,23 @@ pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void {...@@ -967,23 +1232,23 @@ pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void {
967 enum_obj.field_values.get(ip)[field_idx] = val;1232 enum_obj.field_values.get(ip)[field_idx] = val;
968 break :val val;1233 break :val val;
969 };1234 };
970 const adapter: InternPool.Index.Adapter = .{ .indexes = enum_obj.field_values.get(ip)[0..field_idx] };1235 if (ip.addFieldTagValue(enum_obj.field_values, field_value_map, field_val)) |prev_field_index| {
971 const gop = field_value_map.get(ip).getOrPutAssumeCapacityAdapted(field_val, adapter);1236 return sema.failWithOwnedErrorMsg(&block, msg: {
972 if (!gop.found_existing) continue;1237 const prev_field_val_src = block.src(.{ .container_field_value = prev_field_index });
973 const prev_field_val_src: LazySrcLoc = .{1238 const msg = try sema.errMsg(field_val_src, "enum tag value '{f}' for field '{f}' already taken", .{
974 .base_node_inst = tracked_inst,1239 Value.fromInterned(field_val).fmtValueSema(pt, sema),
975 .offset = .{ .container_field_value = @intCast(gop.index) },1240 enum_obj.field_names.get(ip)[field_idx].fmt(ip),
976 };1241 });
977 return sema.failWithOwnedErrorMsg(&block, msg: {1242 errdefer msg.destroy(gpa);
978 const msg = try sema.errMsg(field_val_src, "enum tag value '{f}' already taken", .{1243 try sema.errNote(prev_field_val_src, msg, "previous occurrence in field '{f}'", .{
979 Value.fromInterned(field_val).fmtValueSema(pt, sema),1244 enum_obj.field_names.get(ip)[prev_field_index].fmt(ip),
1245 });
1246 break :msg msg;
980 });1247 });
981 errdefer msg.destroy(gpa);1248 }
982 try sema.errNote(prev_field_val_src, msg, "previous occurrence here", .{});
983 break :msg msg;
984 });
985 }1249 }
9861250
1251 // MLUGG TODO: fate of this line rests on whether comptime_int is a valid int tag type
987 if (enum_obj.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) {1252 if (enum_obj.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) {
988 const fields_len = enum_obj.field_names.len;1253 const fields_len = enum_obj.field_names.len;
989 if (fields_len >= 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(zcu)) {1254 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 {...@@ -437,6 +437,7 @@ pub fn toValue(self: Type) Value {
437/// - an enum with an explicit tag type has the ABI size of the integer tag type,437/// - an enum with an explicit tag type has the ABI size of the integer tag type,
438/// making it one-possible-value only if the integer tag type has 0 bits.438/// making it one-possible-value only if the integer tag type has 0 bits.
439pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool {439pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool {
440 ty.assertHasLayout(zcu);
440 const ip = &zcu.intern_pool;441 const ip = &zcu.intern_pool;
441 return switch (ip.indexToKey(ty.toIntern())) {442 return switch (ip.indexToKey(ty.toIntern())) {
442 .int_type => |int_type| int_type.bits != 0,443 .int_type => |int_type| int_type.bits != 0,
...@@ -499,14 +500,18 @@ pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool {...@@ -499,14 +500,18 @@ pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool {
499 .generic_poison => unreachable,500 .generic_poison => unreachable,
500 },501 },
501 .struct_type => {502 .struct_type => {
502 // TODO MLUGG: memoize this state when resolving struct?
503 const struct_obj = ip.loadStructType(ty.toIntern());503 const struct_obj = ip.loadStructType(ty.toIntern());
504 for (struct_obj.field_types.get(ip), 0..) |field_ty_ip, field_idx| {504 switch (struct_obj.layout) {
505 if (struct_obj.field_is_comptime_bits.get(ip, field_idx)) continue;505 .auto, .@"extern" => return struct_obj.has_runtime_bits,
506 const field_ty: Type = .fromInterned(field_ty_ip);506 .@"packed" => return Type.fromInterned(struct_obj.packed_backing_int_type).hasRuntimeBits(zcu),
507 if (field_ty.hasRuntimeBits(zcu)) return true;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),
508 }514 }
509 return false;
510 },515 },
511 .tuple_type => |tuple| {516 .tuple_type => |tuple| {
512 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {517 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 {...@@ -515,23 +520,8 @@ pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool {
515 }520 }
516 return false;521 return false;
517 },522 },
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?
535 .opaque_type => true,525 .opaque_type => true,
536 .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).hasRuntimeBits(zcu),526 .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 {...@@ -618,17 +608,18 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool {
618 .generic_poison,608 .generic_poison,
619 => false,609 => false,
620 },610 },
621 .struct_type => ip.loadStructType(ty.toIntern()).layout != .auto,611 .struct_type => switch (ip.loadStructType(ty.toIntern()).layout) {
622 .union_type => {612 .auto => false,
623 const union_obj = ip.loadUnionType(ty.toIntern());613 .@"extern", .@"packed" => true,
624 if (union_obj.layout == .auto) return false;614 },
625 return switch (union_obj.runtime_tag) {615 .union_type => switch (ip.loadUnionType(ty.toIntern()).layout) {
626 .none => true,616 .auto => false,
627 .tagged => false,617 .@"extern", .@"packed" => true,
628 .safety => unreachable, // well-defined layout can't have a safety tag618 },
629 };619 .enum_type => switch (ip.loadEnumType(ty.toIntern()).int_tag_mode) {
620 .explicit => true,
621 .auto => false,
630 },622 },
631 .enum_type => ip.loadEnumType(ty.toIntern()).int_tag_is_explicit,
632623
633 // values, not types624 // values, not types
634 .undef,625 .undef,
...@@ -664,28 +655,29 @@ pub fn fnHasRuntimeBits(fn_ty: Type, zcu: *Zcu) bool {...@@ -664,28 +655,29 @@ pub fn fnHasRuntimeBits(fn_ty: Type, zcu: *Zcu) bool {
664 if (param_ty == .generic_poison_type) return false;655 if (param_ty == .generic_poison_type) return false;
665 if (Type.fromInterned(param_ty).comptimeOnly(zcu)) return false;656 if (Type.fromInterned(param_ty).comptimeOnly(zcu)) return false;
666 }657 }
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 }
667 if (fn_info.return_type == .generic_poison_type) return false;667 if (fn_info.return_type == .generic_poison_type) return false;
668 if (Type.fromInterned(fn_info.return_type).comptimeOnly(zcu)) return false;668 if (Type.fromInterned(fn_info.return_type).comptimeOnly(zcu)) return false;
669 if (fn_info.cc == .@"inline") return false;669 if (fn_info.cc == .@"inline") return false;
670 return true;670 return true;
671}671}
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 {
674 switch (ty.zigTypeTag(zcu)) {675 switch (ty.zigTypeTag(zcu)) {
675 .@"fn" => return ty.fnHasRuntimeBits(zcu),676 .@"fn" => return ty.fnHasRuntimeBits(zcu),
676 else => return ty.hasRuntimeBits(zcu),677 else => return ty.hasRuntimeBits(zcu),
677 }678 }
678}679}
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
689pub fn isNoReturn(ty: Type, zcu: *const Zcu) bool {681pub fn isNoReturn(ty: Type, zcu: *const Zcu) bool {
690 return zcu.intern_pool.isNoReturn(ty.toIntern());682 return zcu.intern_pool.isNoReturn(ty.toIntern());
691}683}
...@@ -711,7 +703,6 @@ pub fn ptrAddressSpace(ty: Type, zcu: *const Zcu) std.builtin.AddressSpace {...@@ -711,7 +703,6 @@ pub fn ptrAddressSpace(ty: Type, zcu: *const Zcu) std.builtin.AddressSpace {
711}703}
712704
713/// Never returns `none`. Asserts that all necessary type resolution is already done.705/// Never returns `none`. Asserts that all necessary type resolution is already done.
714/// MLUGG TODO: check that it really does never return `.none`
715pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {706pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {
716 const ip = &zcu.intern_pool;707 const ip = &zcu.intern_pool;
717 const target = zcu.getTarget();708 const target = zcu.getTarget();
...@@ -810,7 +801,7 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {...@@ -810,7 +801,7 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {
810 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {801 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
811 if (val != .none) continue; // comptime field802 if (val != .none) continue; // comptime field
812 const field_align = Type.fromInterned(field_ty).abiAlignment(zcu);803 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);
814 }805 }
815 return big_align;806 return big_align;
816 },807 },
...@@ -818,14 +809,20 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {...@@ -818,14 +809,20 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {
818 const struct_obj = ip.loadStructType(ty.toIntern());809 const struct_obj = ip.loadStructType(ty.toIntern());
819 switch (struct_obj.layout) {810 switch (struct_obj.layout) {
820 .@"packed" => return Type.fromInterned(struct_obj.packed_backing_int_type).abiAlignment(zcu),811 .@"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 },
822 }816 }
823 },817 },
824 .union_type => {818 .union_type => {
825 const union_obj = ip.loadUnionType(ty.toIntern());819 const union_obj = ip.loadUnionType(ty.toIntern());
826 switch (union_obj.layout) {820 switch (union_obj.layout) {
827 .@"packed" => return Type.fromInterned(union_obj.packed_backing_int_type).abiAlignment(zcu),821 .@"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 },
829 }826 }
830 },827 },
831 .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).abiAlignment(zcu),828 .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 {...@@ -1277,38 +1274,17 @@ pub fn nullablePtrElem(ty: Type, zcu: *const Zcu) Type {
1277 }1274 }
1278}1275}
12791276
1280/// Given that `ty` is an indexable pointer, returns its element type. Specifically:1277/// Asserts that `ty` is an indexable type, and returns its element type. Tuples (and pointers to
1281/// * for `*[n]T`, returns `T`1278/// tuples) are not supported because they do not have a single element type.
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.
1288///1279///
1289/// MLUGG TODO: should i even have this one? it's a subset of indexableElem1280/// Returns `T` for each of the following types:
1290pub fn indexablePtrElem(ty: Type, zcu: *const Zcu) Type {1281/// * `[n]T`
1291 const ip = &zcu.intern_pool;1282/// * `@Vector(n, T)`
1292 const ptr_type = ip.indexToKey(ty.toIntern()).ptr_type;1283/// * `*[n]T`
1293 return switch (ptr_type.flags.size) {1284/// * `*@Vector(n, T)`
1294 .many, .slice, .c => return .fromInterned(ptr_type.child),1285/// * `[]T`
1295 .one => switch (ip.indexToKey(ptr_type.child)) {1286/// * `[*]T`
1296 inline .array_type, .vector_type => |arr| return .fromInterned(arr.child),1287/// * `[*c]T`
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.
1312pub fn indexableElem(ty: Type, zcu: *const Zcu) Type {1288pub fn indexableElem(ty: Type, zcu: *const Zcu) Type {
1313 const ip = &zcu.intern_pool;1289 const ip = &zcu.intern_pool;
1314 return switch (ip.indexToKey(ty.toIntern())) {1290 return switch (ip.indexToKey(ty.toIntern())) {
...@@ -1348,6 +1324,7 @@ pub fn optionalChild(ty: Type, zcu: *const Zcu) Type {...@@ -1348,6 +1324,7 @@ pub fn optionalChild(ty: Type, zcu: *const Zcu) Type {
1348/// Returns the tag type of a union, if the type is a union and it has a tag type.1324/// Returns the tag type of a union, if the type is a union and it has a tag type.
1349/// Otherwise, returns `null`.1325/// Otherwise, returns `null`.
1350pub fn unionTagType(ty: Type, zcu: *const Zcu) ?Type {1326pub fn unionTagType(ty: Type, zcu: *const Zcu) ?Type {
1327 assertHasLayout(ty, zcu);
1351 const ip = &zcu.intern_pool;1328 const ip = &zcu.intern_pool;
1352 switch (ip.indexToKey(ty.toIntern())) {1329 switch (ip.indexToKey(ty.toIntern())) {
1353 .union_type => {},1330 .union_type => {},
...@@ -1363,6 +1340,7 @@ pub fn unionTagType(ty: Type, zcu: *const Zcu) ?Type {...@@ -1363,6 +1340,7 @@ pub fn unionTagType(ty: Type, zcu: *const Zcu) ?Type {
1363/// Same as `unionTagType` but includes safety tag.1340/// Same as `unionTagType` but includes safety tag.
1364/// Codegen should use this version.1341/// Codegen should use this version.
1365pub fn unionTagTypeSafety(ty: Type, zcu: *const Zcu) ?Type {1342pub fn unionTagTypeSafety(ty: Type, zcu: *const Zcu) ?Type {
1343 assertHasLayout(ty, zcu);
1366 const ip = &zcu.intern_pool;1344 const ip = &zcu.intern_pool;
1367 return switch (ip.indexToKey(ty.toIntern())) {1345 return switch (ip.indexToKey(ty.toIntern())) {
1368 .union_type => {1346 .union_type => {
...@@ -1377,11 +1355,13 @@ pub fn unionTagTypeSafety(ty: Type, zcu: *const Zcu) ?Type {...@@ -1377,11 +1355,13 @@ pub fn unionTagTypeSafety(ty: Type, zcu: *const Zcu) ?Type {
1377/// Asserts the type is a union; returns the tag type, even if the tag will1355/// Asserts the type is a union; returns the tag type, even if the tag will
1378/// not be stored at runtime.1356/// not be stored at runtime.
1379pub fn unionTagTypeHypothetical(ty: Type, zcu: *const Zcu) Type {1357pub fn unionTagTypeHypothetical(ty: Type, zcu: *const Zcu) Type {
1358 assertHasLayout(ty, zcu);
1380 const union_obj = zcu.typeToUnion(ty).?;1359 const union_obj = zcu.typeToUnion(ty).?;
1381 return Type.fromInterned(union_obj.enum_tag_type);1360 return Type.fromInterned(union_obj.enum_tag_type);
1382}1361}
13831362
1384pub fn unionFieldType(ty: Type, enum_tag: Value, zcu: *const Zcu) ?Type {1363pub fn unionFieldType(ty: Type, enum_tag: Value, zcu: *const Zcu) ?Type {
1364 assertHasLayout(ty, zcu);
1385 const ip = &zcu.intern_pool;1365 const ip = &zcu.intern_pool;
1386 const union_obj = zcu.typeToUnion(ty).?;1366 const union_obj = zcu.typeToUnion(ty).?;
1387 const union_fields = union_obj.field_types.get(ip);1367 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 {...@@ -1390,17 +1370,20 @@ pub fn unionFieldType(ty: Type, enum_tag: Value, zcu: *const Zcu) ?Type {
1390}1370}
13911371
1392pub fn unionFieldTypeByIndex(ty: Type, index: usize, zcu: *const Zcu) Type {1372pub fn unionFieldTypeByIndex(ty: Type, index: usize, zcu: *const Zcu) Type {
1373 assertHasLayout(ty, zcu);
1393 const ip = &zcu.intern_pool;1374 const ip = &zcu.intern_pool;
1394 const union_obj = zcu.typeToUnion(ty).?;1375 const union_obj = zcu.typeToUnion(ty).?;
1395 return Type.fromInterned(union_obj.field_types.get(ip)[index]);1376 return Type.fromInterned(union_obj.field_types.get(ip)[index]);
1396}1377}
13971378
1398pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 {1379pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 {
1380 assertHasLayout(ty, zcu);
1399 const union_obj = zcu.typeToUnion(ty).?;1381 const union_obj = zcu.typeToUnion(ty).?;
1400 return zcu.unionTagFieldIndex(union_obj, enum_tag);1382 return zcu.unionTagFieldIndex(union_obj, enum_tag);
1401}1383}
14021384
1403pub fn unionHasAllZeroBitFieldTypes(ty: Type, zcu: *Zcu) bool {1385pub fn unionHasAllZeroBitFieldTypes(ty: Type, zcu: *Zcu) bool {
1386 assertHasLayout(ty, zcu);
1404 const ip = &zcu.intern_pool;1387 const ip = &zcu.intern_pool;
1405 const union_obj = zcu.typeToUnion(ty).?;1388 const union_obj = zcu.typeToUnion(ty).?;
1406 for (union_obj.field_types.get(ip)) |field_ty| {1389 for (union_obj.field_types.get(ip)) |field_ty| {
...@@ -1413,14 +1396,17 @@ pub fn unionHasAllZeroBitFieldTypes(ty: Type, zcu: *Zcu) bool {...@@ -1413,14 +1396,17 @@ pub fn unionHasAllZeroBitFieldTypes(ty: Type, zcu: *Zcu) bool {
1413/// Asserts the type is either an extern or packed union.1396/// Asserts the type is either an extern or packed union.
1414pub fn unionBackingType(ty: Type, pt: Zcu.PerThread) !Type {1397pub fn unionBackingType(ty: Type, pt: Zcu.PerThread) !Type {
1415 const zcu = pt.zcu;1398 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) {
1417 .@"extern" => try pt.arrayType(.{ .len = ty.abiSize(zcu), .child = .u8_type }),1402 .@"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),
1419 .auto => unreachable,1404 .auto => unreachable,
1420 };1405 };
1421}1406}
14221407
1423pub fn unionGetLayout(ty: Type, zcu: *const Zcu) Zcu.UnionLayout {1408pub fn unionGetLayout(ty: Type, zcu: *const Zcu) Zcu.UnionLayout {
1409 assertHasLayout(ty, zcu);
1424 const union_obj = zcu.intern_pool.loadUnionType(ty.toIntern());1410 const union_obj = zcu.intern_pool.loadUnionType(ty.toIntern());
1425 return Type.getUnionLayout(union_obj, zcu);1411 return Type.getUnionLayout(union_obj, zcu);
1426}1412}
...@@ -1865,11 +1851,8 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value {...@@ -1865,11 +1851,8 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value {
1865 for (field_vals, 0..) |*field_val, i_usize| {1851 for (field_vals, 0..) |*field_val, i_usize| {
1866 const i: u32 = @intCast(i_usize);1852 const i: u32 = @intCast(i_usize);
1867 if (struct_obj.field_is_comptime_bits.get(ip, i)) {1853 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);
1872 field_val.* = struct_obj.field_defaults.get(ip)[i];1854 field_val.* = struct_obj.field_defaults.get(ip)[i];
1855 assert(field_val.* != .none);
1873 continue;1856 continue;
1874 }1857 }
1875 const field_ty = Type.fromInterned(struct_obj.field_types.get(ip)[i]);1858 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....@@ -2257,19 +2240,23 @@ pub fn errorSetNames(ty: Type, zcu: *const Zcu) InternPool.NullTerminatedString.
2257}2240}
22582241
2259pub fn enumFields(ty: Type, zcu: *const Zcu) InternPool.NullTerminatedString.Slice {2242pub fn enumFields(ty: Type, zcu: *const Zcu) InternPool.NullTerminatedString.Slice {
2243 assertHasLayout(ty, zcu);
2260 return zcu.intern_pool.loadEnumType(ty.toIntern()).field_names;2244 return zcu.intern_pool.loadEnumType(ty.toIntern()).field_names;
2261}2245}
22622246
2263pub fn enumFieldCount(ty: Type, zcu: *const Zcu) usize {2247pub fn enumFieldCount(ty: Type, zcu: *const Zcu) usize {
2248 assertHasLayout(ty, zcu);
2264 return zcu.intern_pool.loadEnumType(ty.toIntern()).field_names.len;2249 return zcu.intern_pool.loadEnumType(ty.toIntern()).field_names.len;
2265}2250}
22662251
2267pub fn enumFieldName(ty: Type, field_index: usize, zcu: *const Zcu) InternPool.NullTerminatedString {2252pub fn enumFieldName(ty: Type, field_index: usize, zcu: *const Zcu) InternPool.NullTerminatedString {
2253 assertHasLayout(ty, zcu);
2268 const ip = &zcu.intern_pool;2254 const ip = &zcu.intern_pool;
2269 return ip.loadEnumType(ty.toIntern()).field_names.get(ip)[field_index];2255 return ip.loadEnumType(ty.toIntern()).field_names.get(ip)[field_index];
2270}2256}
22712257
2272pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, zcu: *const Zcu) ?u32 {2258pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, zcu: *const Zcu) ?u32 {
2259 assertHasLayout(ty, zcu);
2273 const ip = &zcu.intern_pool;2260 const ip = &zcu.intern_pool;
2274 const enum_type = ip.loadEnumType(ty.toIntern());2261 const enum_type = ip.loadEnumType(ty.toIntern());
2275 return enum_type.nameIndex(ip, field_name);2262 return enum_type.nameIndex(ip, field_name);
...@@ -2279,6 +2266,7 @@ pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, zcu...@@ -2279,6 +2266,7 @@ pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, zcu
2279/// an integer which represents the enum value. Returns the field index in2266/// an integer which represents the enum value. Returns the field index in
2280/// declaration order, or `null` if `enum_tag` does not match any field.2267/// declaration order, or `null` if `enum_tag` does not match any field.
2281pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 {2268pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 {
2269 assertHasLayout(ty, zcu);
2282 const ip = &zcu.intern_pool;2270 const ip = &zcu.intern_pool;
2283 const enum_type = ip.loadEnumType(ty.toIntern());2271 const enum_type = ip.loadEnumType(ty.toIntern());
2284 const int_tag = switch (ip.indexToKey(enum_tag.toIntern())) {2272 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 {...@@ -2293,28 +2281,40 @@ pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 {
2293/// Returns none in the case of a tuple which uses the integer index as the field name.2281/// Returns none in the case of a tuple which uses the integer index as the field name.
2294pub fn structFieldName(ty: Type, index: usize, zcu: *const Zcu) InternPool.OptionalNullTerminatedString {2282pub fn structFieldName(ty: Type, index: usize, zcu: *const Zcu) InternPool.OptionalNullTerminatedString {
2295 const ip = &zcu.intern_pool;2283 const ip = &zcu.intern_pool;
2296 return switch (ip.indexToKey(ty.toIntern())) {2284 switch (ip.indexToKey(ty.toIntern())) {
2297 .struct_type => ip.loadStructType(ty.toIntern()).field_names.get(ip)[index].toOptional(),2285 .struct_type => {
2298 .tuple_type => .none,2286 assertHasLayout(ty, zcu);
2287 return ip.loadStructType(ty.toIntern()).field_names.get(ip)[index].toOptional();
2288 },
2289 .tuple_type => return .none,
2299 else => unreachable,2290 else => unreachable,
2300 };2291 }
2301}2292}
23022293
2303pub fn structFieldCount(ty: Type, zcu: *const Zcu) u32 {2294pub fn structFieldCount(ty: Type, zcu: *const Zcu) u32 {
2304 const ip = &zcu.intern_pool;2295 const ip = &zcu.intern_pool;
2305 return switch (ip.indexToKey(ty.toIntern())) {2296 switch (ip.indexToKey(ty.toIntern())) {
2306 .struct_type => ip.loadStructType(ty.toIntern()).field_types.len,2297 .struct_type => {
2307 .tuple_type => |tuple| tuple.types.len,2298 assertHasLayout(ty, zcu);
2299 return ip.loadStructType(ty.toIntern()).field_types.len;
2300 },
2301 .tuple_type => |tuple| return tuple.types.len,
2308 else => unreachable,2302 else => unreachable,
2309 };2303 }
2310}2304}
23112305
2312/// Returns the field type. Supports structs and unions.2306/// Returns the field type. Supports structs and unions.
2313pub fn fieldType(ty: Type, index: usize, zcu: *const Zcu) Type {2307pub fn fieldType(ty: Type, index: usize, zcu: *const Zcu) Type {
2314 const ip = &zcu.intern_pool;2308 const ip = &zcu.intern_pool;
2315 const types = switch (ip.indexToKey(ty.toIntern())) {2309 const types = switch (ip.indexToKey(ty.toIntern())) {
2316 .struct_type => ip.loadStructType(ty.toIntern()).field_types,2310 .struct_type => types: {
2317 .union_type => ip.loadUnionType(ty.toIntern()).field_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 },
2318 .tuple_type => |tuple| tuple.types,2318 .tuple_type => |tuple| tuple.types,
2319 else => unreachable,2319 else => unreachable,
2320 };2320 };
...@@ -2335,11 +2335,13 @@ pub fn resolvedFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment...@@ -2335,11 +2335,13 @@ pub fn resolvedFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment
2335 return switch (ip.indexToKey(ty.toIntern())) {2335 return switch (ip.indexToKey(ty.toIntern())) {
2336 .tuple_type => |tuple| Type.fromInterned(tuple.types.get(ip)[index]).abiAlignment(zcu),2336 .tuple_type => |tuple| Type.fromInterned(tuple.types.get(ip)[index]).abiAlignment(zcu),
2337 .struct_type => {2337 .struct_type => {
2338 assertHasLayout(ty, zcu);
2338 const struct_obj = ip.loadStructType(ty.toIntern());2339 const struct_obj = ip.loadStructType(ty.toIntern());
2339 const field_ty: Type = .fromInterned(struct_obj.field_types.get(ip)[index]);2340 const field_ty: Type = .fromInterned(struct_obj.field_types.get(ip)[index]);
2340 return field_ty.defaultStructFieldAlignment(struct_obj.layout, zcu);2341 return field_ty.defaultStructFieldAlignment(struct_obj.layout, zcu);
2341 },2342 },
2342 .union_type => {2343 .union_type => {
2344 assertHasLayout(ty, zcu);
2343 const union_obj = ip.loadUnionType(ty.toIntern());2345 const union_obj = ip.loadUnionType(ty.toIntern());
2344 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[index]);2346 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[index]);
2345 return field_ty.abiAlignment(zcu);2347 return field_ty.abiAlignment(zcu);
...@@ -2353,12 +2355,14 @@ pub fn explicitFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment...@@ -2353,12 +2355,14 @@ pub fn explicitFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment
2353 return switch (ip.indexToKey(ty.toIntern())) {2355 return switch (ip.indexToKey(ty.toIntern())) {
2354 .tuple_type => .none,2356 .tuple_type => .none,
2355 .struct_type => {2357 .struct_type => {
2358 assertHasLayout(ty, zcu);
2356 const struct_obj = ip.loadStructType(ty.toIntern());2359 const struct_obj = ip.loadStructType(ty.toIntern());
2357 assert(struct_obj.layout != .@"packed");2360 assert(struct_obj.layout != .@"packed");
2358 if (struct_obj.field_aligns.len == 0) return .none;2361 if (struct_obj.field_aligns.len == 0) return .none;
2359 return struct_obj.field_aligns.get(ip)[index];2362 return struct_obj.field_aligns.get(ip)[index];
2360 },2363 },
2361 .union_type => {2364 .union_type => {
2365 assertHasLayout(ty, zcu);
2362 const union_obj = ip.loadUnionType(ty.toIntern());2366 const union_obj = ip.loadUnionType(ty.toIntern());
2363 assert(union_obj.layout != .@"packed");2367 assert(union_obj.layout != .@"packed");
2364 if (union_obj.field_aligns.len == 0) return .none;2368 if (union_obj.field_aligns.len == 0) return .none;
...@@ -2413,7 +2417,6 @@ pub fn structFieldValueComptime(ty: Type, pt: Zcu.PerThread, index: usize) !?Val...@@ -2413,7 +2417,6 @@ pub fn structFieldValueComptime(ty: Type, pt: Zcu.PerThread, index: usize) !?Val
2413 .struct_type => {2417 .struct_type => {
2414 const struct_type = ip.loadStructType(ty.toIntern());2418 const struct_type = ip.loadStructType(ty.toIntern());
2415 if (struct_type.field_is_comptime_bits.get(ip, index)) {2419 if (struct_type.field_is_comptime_bits.get(ip, index)) {
2416 assertHasInits(ty, zcu);
2417 return .fromInterned(struct_type.field_defaults.get(ip)[index]);2420 return .fromInterned(struct_type.field_defaults.get(ip)[index]);
2418 } else {2421 } else {
2419 return Type.fromInterned(struct_type.field_types.get(ip)[index]).onePossibleValue(pt);2422 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...@@ -2433,11 +2436,14 @@ pub fn structFieldValueComptime(ty: Type, pt: Zcu.PerThread, index: usize) !?Val
24332436
2434pub fn structFieldIsComptime(ty: Type, index: usize, zcu: *const Zcu) bool {2437pub fn structFieldIsComptime(ty: Type, index: usize, zcu: *const Zcu) bool {
2435 const ip = &zcu.intern_pool;2438 const ip = &zcu.intern_pool;
2436 return switch (ip.indexToKey(ty.toIntern())) {2439 switch (ip.indexToKey(ty.toIntern())) {
2437 .struct_type => ip.loadStructType(ty.toIntern()).field_is_comptime_bits.get(ip, index),2440 .struct_type => {
2438 .tuple_type => |tuple| tuple.values.get(ip)[index] != .none,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,
2439 else => unreachable,2445 else => unreachable,
2440 };2446 }
2441}2447}
24422448
2443pub const FieldOffset = struct {2449pub const FieldOffset = struct {
...@@ -2850,34 +2856,166 @@ pub fn isNullFromType(ty: Type, zcu: *const Zcu) ?bool {...@@ -2850,34 +2856,166 @@ pub fn isNullFromType(ty: Type, zcu: *const Zcu) ?bool {
2850 return null;2856 return null;
2851}2857}
28522858
2853/// Returns true if `ty` is allowed in packed types.2859pub const UnpackableReason = union(enum) {
2854pub fn packable(ty: Type, zcu: *const Zcu) bool {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 {
2855 return switch (ty.zigTypeTag(zcu)) {2870 return switch (ty.zigTypeTag(zcu)) {
2871 .void,
2872 .bool,
2873 .float,
2874 .int,
2875 => null,
2876
2856 .type,2877 .type,
2857 .comptime_float,2878 .comptime_float,
2858 .comptime_int,2879 .comptime_int,
2859 .enum_literal,2880 .enum_literal,
2860 .undefined,2881 .undefined,
2861 .null,2882 .null,
2883 => .comptime_only,
2884
2885 .noreturn,
2886 .@"opaque",
2862 .error_union,2887 .error_union,
2863 .error_set,2888 .error_set,
2864 .frame,2889 .frame,
2865 .noreturn,
2866 .@"opaque",
2867 .@"anyframe",2890 .@"anyframe",
2868 .@"fn",2891 .@"fn",
2869 .array,2892 .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,
2870 => false,2942 => false,
2871 .optional => return ty.isPtrLikeOptional(zcu),2943
2872 .void,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",
2873 .bool,2958 .bool,
2874 .float,2959 .float,
2875 .int,2960 .@"anyframe",
2876 .vector,
2877 => true,2961 => true,
2878 .@"enum" => zcu.intern_pool.loadEnumType(ty.toIntern()).int_tag_is_explicit,2962
2879 .pointer => !ty.isSlice(zcu),2963 .pointer => {
2880 .@"struct", .@"union" => ty.containerLayout(zcu) == .@"packed",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),
2881 };3019 };
2882}3020}
28833021
...@@ -2889,7 +3027,6 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void {...@@ -2889,7 +3027,6 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void {
2889 .anyframe_type,3027 .anyframe_type,
2890 .simple_type,3028 .simple_type,
2891 .opaque_type,3029 .opaque_type,
2892 .enum_type,
2893 .error_set_type,3030 .error_set_type,
2894 .inferred_error_set_type,3031 .inferred_error_set_type,
2895 => {},3032 => {},
...@@ -2906,12 +3043,11 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void {...@@ -2906,12 +3043,11 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void {
2906 .tuple_type => |tuple| for (tuple.types.get(&zcu.intern_pool)) |field_ty| {3043 .tuple_type => |tuple| for (tuple.types.get(&zcu.intern_pool)) |field_ty| {
2907 assertHasLayout(.fromInterned(field_ty), zcu);3044 assertHasLayout(.fromInterned(field_ty), zcu);
2908 },3045 },
2909 .struct_type, .union_type => {3046 .struct_type, .union_type, .enum_type => {
2910 const unit: InternPool.AnalUnit = .wrap(.{ .type_layout = ty.toIntern() });3047 const unit: InternPool.AnalUnit = .wrap(.{ .type_layout = ty.toIntern() });
2911 assert(!zcu.outdated.contains(unit));3048 assert(!zcu.outdated.contains(unit));
2912 assert(!zcu.potentially_outdated.contains(unit));3049 assert(!zcu.potentially_outdated.contains(unit));
2913 },3050 },
2914 else => unreachable, // assertion failure; not a struct or union
29153051
2916 // values, not types3052 // values, not types
2917 .simple_value,3053 .simple_value,
...@@ -2930,23 +3066,13 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void {...@@ -2930,23 +3066,13 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void {
2930 .opt,3066 .opt,
2931 .aggregate,3067 .aggregate,
2932 .un,3068 .un,
3069 .undef,
2933 // memoization, not types3070 // memoization, not types
2934 .memoized_call,3071 .memoized_call,
2935 => unreachable,3072 => unreachable,
2936 }3073 }
2937}3074}
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
2950/// Recursively walks the type and marks for each subtype how many times it has been seen3076/// Recursively walks the type and marks for each subtype how many times it has been seen
2951fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUnmanaged(Type, u16)) error{OutOfMemory}!void {3077fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUnmanaged(Type, u16)) error{OutOfMemory}!void {
2952 const zcu = pt.zcu;3078 const zcu = pt.zcu;
...@@ -3116,6 +3242,7 @@ pub const Comparison = struct {...@@ -3116,6 +3242,7 @@ pub const Comparison = struct {
3116 };3242 };
3117};3243};
31183244
3245pub const @"u0": Type = .{ .ip_index = .u0_type };
3119pub const @"u1": Type = .{ .ip_index = .u1_type };3246pub const @"u1": Type = .{ .ip_index = .u1_type };
3120pub const @"u8": Type = .{ .ip_index = .u8_type };3247pub const @"u8": Type = .{ .ip_index = .u8_type };
3121pub const @"u16": Type = .{ .ip_index = .u16_type };3248pub 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...@@ -2207,7 +2207,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
22072207
2208 const ptr_ty_info = Type.fromInterned(ptr.ty).ptrInfo(zcu);2208 const ptr_ty_info = Type.fromInterned(ptr.ty).ptrInfo(zcu);
2209 const need_child: Type = .fromInterned(ptr_ty_info.child);2209 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") {
2211 // No refinement can happen - this pointer is presumably invalid.2211 // No refinement can happen - this pointer is presumably invalid.
2212 // Just offset it.2212 // Just offset it.
2213 const parent = try arena.create(PointerDeriveStep);2213 const parent = try arena.create(PointerDeriveStep);
...@@ -2595,8 +2595,8 @@ pub fn uninterpret(val: anytype, ty: Type, pt: Zcu.PerThread) error{ OutOfMemory...@@ -2595,8 +2595,8 @@ pub fn uninterpret(val: anytype, ty: Type, pt: Zcu.PerThread) error{ OutOfMemory
2595pub fn doPointersOverlap(ptr_val_a: Value, ptr_val_b: Value, elem_count: u64, zcu: *const Zcu) bool {2595pub fn doPointersOverlap(ptr_val_a: Value, ptr_val_b: Value, elem_count: u64, zcu: *const Zcu) bool {
2596 const ip = &zcu.intern_pool;2596 const ip = &zcu.intern_pool;
25972597
2598 const a_elem_ty = ptr_val_a.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).indexablePtrElem(zcu);2599 const b_elem_ty = ptr_val_b.typeOf(zcu).indexableElem(zcu);
26002600
2601 const a_ptr = ip.indexToKey(ptr_val_a.toIntern()).ptr;2601 const a_ptr = ip.indexToKey(ptr_val_a.toIntern()).ptr;
2602 const b_ptr = ip.indexToKey(ptr_val_b.toIntern()).ptr;2602 const b_ptr = ip.indexToKey(ptr_val_b.toIntern()).ptr;
...@@ -2682,3 +2682,58 @@ pub fn eqlScalarNum(lhs: Value, rhs: Value, zcu: *Zcu) bool {...@@ -2682,3 +2682,58 @@ pub fn eqlScalarNum(lhs: Value, rhs: Value, zcu: *Zcu) bool {
2682 const rhs_bigint = rhs.toBigInt(&rhs_bigint_space, zcu);2682 const rhs_bigint = rhs.toBigInt(&rhs_bigint_space, zcu);
2683 return lhs_bigint.eql(rhs_bigint);2683 return lhs_bigint.eql(rhs_bigint);
2684}2684}
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 {...@@ -1912,40 +1912,6 @@ pub const SrcLoc = struct {
1912 const full = tree.fullPtrType(parent_node).?;1912 const full = tree.fullPtrType(parent_node).?;
1913 return tree.nodeToSpan(full.ast.bit_range_end.unwrap().?);1913 return tree.nodeToSpan(full.ast.bit_range_end.unwrap().?);
1914 },1914 },
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 },
1949 .node_offset_init_ty => |node_off| {1915 .node_offset_init_ty => |node_off| {
1950 const tree = try src_loc.file_scope.getTree(zcu);1916 const tree = try src_loc.file_scope.getTree(zcu);
1951 const parent_node = node_off.toAbsolute(src_loc.base_node);1917 const parent_node = node_off.toAbsolute(src_loc.base_node);
...@@ -2021,6 +1987,14 @@ pub const SrcLoc = struct {...@@ -2021,6 +1987,14 @@ pub const SrcLoc = struct {
2021 }1987 }
2022 return tree.nodeToSpan(node);1988 return tree.nodeToSpan(node);
2023 },1989 },
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 },
2024 .container_field_name,1998 .container_field_name,
2025 .container_field_value,1999 .container_field_value,
2026 .container_field_type,2000 .container_field_type,
...@@ -2262,7 +2236,11 @@ pub const SrcLoc = struct {...@@ -2262,7 +2236,11 @@ pub const SrcLoc = struct {
2262 var param_it = full.iterate(tree);2236 var param_it = full.iterate(tree);
2263 for (0..param_idx) |_| assert(param_it.next() != null);2237 for (0..param_idx) |_| assert(param_it.next() != null);
2264 const param = param_it.next().?;2238 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 }
2266 },2244 },
2267 }2245 }
2268 }2246 }
...@@ -2484,10 +2462,6 @@ pub const LazySrcLoc = struct {...@@ -2484,10 +2462,6 @@ pub const LazySrcLoc = struct {
2484 node_offset_ptr_bitoffset: Ast.Node.Offset,2462 node_offset_ptr_bitoffset: Ast.Node.Offset,
2485 /// The source location points to the host size of a pointer.2463 /// The source location points to the host size of a pointer.
2486 node_offset_ptr_hostsize: Ast.Node.Offset,2464 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,
2491 /// The source location points to the type of an array or struct initializer.2465 /// The source location points to the type of an array or struct initializer.
2492 node_offset_init_ty: Ast.Node.Offset,2466 node_offset_init_ty: Ast.Node.Offset,
2493 /// The source location points to the LHS of an assignment (or assign-op, e.g. `+=`).2467 /// The source location points to the LHS of an assignment (or assign-op, e.g. `+=`).
...@@ -2532,6 +2506,11 @@ pub const LazySrcLoc = struct {...@@ -2532,6 +2506,11 @@ pub const LazySrcLoc = struct {
2532 fn_proto_param_type: FnProtoParam,2506 fn_proto_param_type: FnProtoParam,
2533 array_cat_lhs: ArrayCat,2507 array_cat_lhs: ArrayCat,
2534 array_cat_rhs: ArrayCat,2508 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,
2535 /// The source location points to the name of the field at the given index2514 /// The source location points to the name of the field at the given index
2536 /// of the container type declaration at the base node.2515 /// of the container type declaration at the base node.
2537 container_field_name: u32,2516 container_field_name: u32,
...@@ -3149,7 +3128,7 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {...@@ -3149,7 +3128,7 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
3149 .nav_val => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_val = nav }),3128 .nav_val => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_val = nav }),
3150 .nav_ty => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_ty = nav }),3129 .nav_ty => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_ty = nav }),
3151 .type_layout => |ty| try zcu.markPoDependeeUpToDate(.{ .type_layout = ty }),3130 .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 }),
3153 .func => |func| try zcu.markPoDependeeUpToDate(.{ .func_ies = func }),3132 .func => |func| try zcu.markPoDependeeUpToDate(.{ .func_ies = func }),
3154 .memoized_state => |stage| try zcu.markPoDependeeUpToDate(.{ .memoized_state = stage }),3133 .memoized_state => |stage| try zcu.markPoDependeeUpToDate(.{ .memoized_state = stage }),
3155 }3134 }
...@@ -3165,7 +3144,7 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni...@@ -3165,7 +3144,7 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni
3165 .nav_val => |nav| .{ .nav_val = nav },3144 .nav_val => |nav| .{ .nav_val = nav },
3166 .nav_ty => |nav| .{ .nav_ty = nav },3145 .nav_ty => |nav| .{ .nav_ty = nav },
3167 .type_layout => |ty| .{ .type_layout = ty },3146 .type_layout => |ty| .{ .type_layout = ty },
3168 .type_inits => |ty| .{ .type_inits = ty },3147 .struct_defaults => |ty| .{ .struct_defaults = ty },
3169 .func => |func_index| .{ .func_ies = func_index },3148 .func => |func_index| .{ .func_ies = func_index },
3170 .memoized_state => |stage| .{ .memoized_state = stage },3149 .memoized_state => |stage| .{ .memoized_state = stage },
3171 };3150 };
...@@ -3195,88 +3174,44 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni...@@ -3195,88 +3174,44 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni
3195 }3174 }
3196}3175}
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.
3198pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {3181pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
3199 if (!zcu.comp.config.incremental) return null;3182 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
3219 if (zcu.outdated_ready.count() > 0) {3184 if (zcu.outdated_ready.count() > 0) {
3220 const unit = zcu.outdated_ready.keys()[0];3185 const unit = zcu.outdated_ready.keys()[0];
3221 log.debug("findOutdatedToAnalyze: trivial {f}", .{zcu.fmtAnalUnit(unit)});3186 log.debug("findOutdatedToAnalyze: {f}", .{zcu.fmtAnalUnit(unit)});
3222 return unit;3187 return unit;
3223 }3188 }
32243189
3225 // There is no single AnalUnit which is ready for re-analysis. Instead, we must assume that some3190 // Usually, getting here means that everything is up-to-date, so there is no more work to do. We
3226 // AnalUnit with PO dependencies is outdated -- e.g. in the above example we arbitrarily pick one of3191 // will see that `zcu.outdated` and `zcu.potentially_outdated` are both empty.
3227 // A or B. We should definitely not select a function, since a function can't be responsible for the3192 //
3228 // loop (IES dependencies can't have loops). We should also, of course, not select a `comptime`3193 // However, if a previous update had a dependency loop compile error, there is a cycle in the
3229 // declaration, since you can't depend on those!3194 // dependency graph (which is usually acyclic), which can cause a scenario where no unit appears
32303195 // to be ready, because they're all waiting for the next in the loop to be up-to-date. In that
3231 // The choice of this unit could have a big impact on how much total analysis we perform, since3196 // case, we usually have to just bite the bullet and analyze one of them. An exception is if
3232 // if analysis concludes any dependencies on its result are up-to-date, then other PO AnalUnit3197 // `zcu.outdated` is empty but `zcu.potentially_outdated` is non-empty: in that case, the only
3233 // may be resolved as up-to-date. To hopefully avoid doing too much work, let's find a unit3198 // possible situation is a cycle where everything is actually up-to-date, so we can clear out
3234 // which the most things depend on - the idea is that this will resolve a lot of loops (but this3199 // `zcu.potentially_outdated` and we are done.
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;
32663200
3267 if (chosen_unit == null or n > chosen_unit_dependers) {3201 if (zcu.outdated.count() == 0) {
3268 chosen_unit = unit;3202 // Everything is up-to-date. There could be lingering entries in `zcu.potentially_outdated`
3269 chosen_unit_dependers = n;3203 // from a dependency loop on a previous update.
3270 }3204 zcu.potentially_outdated.clearRetainingCapacity();
3271 }3205 log.debug("findOutdatedToAnalyze: all up-to-date", .{});
3206 return null;
3272 }3207 }
32733208
3274 log.debug("findOutdatedToAnalyze: heuristic returned '{f}' ({d} dependers)", .{3209 const unit = zcu.outdated.keys()[0];
3275 zcu.fmtAnalUnit(chosen_unit.?),3210 log.debug("findOutdatedToAnalyze: dependency loop affecting {d} units, selected {f}", .{
3276 chosen_unit_dependers,3211 zcu.outdated.count(),
3212 zcu.fmtAnalUnit(unit),
3277 });3213 });
32783214 return unit;
3279 return chosen_unit.?;
3280}3215}
32813216
3282/// During an incremental update, before semantic analysis, call this to flush all values from3217/// During an incremental update, before semantic analysis, call this to flush all values from
...@@ -3356,12 +3291,59 @@ pub fn mapOldZirToNew(...@@ -3356,12 +3291,59 @@ pub fn mapOldZirToNew(
3356 }3291 }
33573292
3358 while (match_stack.pop()) |match_item| {3293 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, because3294 // There are some properties of type declarations which cannot change across incremental
3360 // we wouldn't know how to correlate type information with the last update.3295 // updates. If they have, we need to ignore this mapping. These properties are essentially
3361 // Synchronizes with logic in `Zcu.PerThread.recreateStructType` etc.3296 // everything passed into `InternPool.getDeclaredStructType` (likewise for unions, enums,
3362 if (old_zir.typeCapturesLen(match_item.old_inst) != new_zir.typeCapturesLen(match_item.new_inst)) {3297 // and opaques).
3363 // Don't map this type or anything within it.3298 const old_tag = old_zir.instructions.items(.data)[@intFromEnum(match_item.old_inst)].extended.opcode;
3364 continue;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,
3365 }3347 }
33663348
3367 // Match the namespace declaration itself3349 // Match the namespace declaration itself
...@@ -4068,7 +4050,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R...@@ -4068,7 +4050,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R
4068 }4050 }
4069 if (has_inits) {4051 if (has_inits) {
4070 // this should only be referenced by the type4052 // this should only be referenced by the type
4071 const unit: AnalUnit = .wrap(.{ .type_inits = ty });4053 const unit: AnalUnit = .wrap(.{ .struct_defaults = ty });
4072 try units.putNoClobber(gpa, unit, referencer);4054 try units.putNoClobber(gpa, unit, referencer);
4073 }4055 }
40744056
...@@ -4184,7 +4166,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R...@@ -4184,7 +4166,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R
4184 const other: AnalUnit = .wrap(switch (unit.unwrap()) {4166 const other: AnalUnit = .wrap(switch (unit.unwrap()) {
4185 .nav_val => |n| .{ .nav_ty = n },4167 .nav_val => |n| .{ .nav_ty = n },
4186 .nav_ty => |n| .{ .nav_val = n },4168 .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,
4188 });4170 });
4189 const gop = try units.getOrPut(gpa, other);4171 const gop = try units.getOrPut(gpa, other);
4190 if (gop.found_existing) break :queue_paired;4172 if (gop.found_existing) break :queue_paired;
...@@ -4305,6 +4287,16 @@ pub fn navFileScope(zcu: *Zcu, nav: InternPool.Nav.Index) *File {...@@ -4305,6 +4287,16 @@ pub fn navFileScope(zcu: *Zcu, nav: InternPool.Nav.Index) *File {
4305 return zcu.fileByIndex(zcu.navFileScopeIndex(nav));4287 return zcu.fileByIndex(zcu.navFileScopeIndex(nav));
4306}4288}
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
4308pub fn fmtAnalUnit(zcu: *Zcu, unit: AnalUnit) std.fmt.Alt(FormatAnalUnit, formatAnalUnit) {4300pub fn fmtAnalUnit(zcu: *Zcu, unit: AnalUnit) std.fmt.Alt(FormatAnalUnit, formatAnalUnit) {
4309 return .{ .data = .{ .unit = unit, .zcu = zcu } };4301 return .{ .data = .{ .unit = unit, .zcu = zcu } };
4310}4302}
...@@ -4331,7 +4323,7 @@ fn formatAnalUnit(data: FormatAnalUnit, writer: *Io.Writer) Io.Writer.Error!void...@@ -4331,7 +4323,7 @@ fn formatAnalUnit(data: FormatAnalUnit, writer: *Io.Writer) Io.Writer.Error!void
4331 }4323 }
4332 },4324 },
4333 .nav_val, .nav_ty => |nav, tag| return writer.print("{t}('{f}' [{}])", .{ tag, ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }),4325 .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) }),
4335 .func => |func| {4327 .func => |func| {
4336 const nav = zcu.funcInfo(func).owner_nav;4328 const nav = zcu.funcInfo(func).owner_nav;
4337 return writer.print("func('{f}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(func) });4329 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...@@ -4357,7 +4349,7 @@ fn formatDependee(data: FormatDependee, writer: *Io.Writer) Io.Writer.Error!void
4357 const fqn = ip.getNav(nav).fqn;4349 const fqn = ip.getNav(nav).fqn;
4358 return writer.print("{t}('{f}')", .{ tag, fqn.fmt(ip) });4350 return writer.print("{t}('{f}')", .{ tag, fqn.fmt(ip) });
4359 },4351 },
4360 .type_layout, .type_inits => |ip_index, tag| {4352 .type_layout, .struct_defaults => |ip_index, tag| {
4361 const name = Type.fromInterned(ip_index).containerTypeName(ip);4353 const name = Type.fromInterned(ip_index).containerTypeName(ip);
4362 return writer.print("{t}('{f}')", .{ tag, name.fmt(ip) });4354 return writer.print("{t}('{f}')", .{ tag, name.fmt(ip) });
4363 },4355 },
src/Zcu/PerThread.zig+67-88
...@@ -695,20 +695,46 @@ pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) (Alloca...@@ -695,20 +695,46 @@ pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) (Alloca
695 .file = file_index,695 .file = file_index,
696 .inst = .main_struct_inst,696 .inst = .main_struct_inst,
697 });697 });
698 const file_root_type = try Sema.analyzeStructDecl(698 const wip: InternPool.WipContainerType = switch (try ip.getDeclaredStructType(gpa, io, pt.tid, .{
699 pt,699 .zir_index = tracked_inst,
700 file_index,700 .captures = &.{},
701 &file.zir.?,701 .fields_len = @intCast(struct_decl.field_names.len),
702 .none,702 .layout = struct_decl.layout,
703 tracked_inst,703 .any_comptime_fields = struct_decl.field_comptime_bits != null,
704 &struct_decl,704 .any_field_defaults = struct_decl.field_default_body_lens != null,
705 null,705 .any_field_aligns = struct_decl.field_align_body_lens != null,
706 &.{},706 .packed_backing_mode = if (struct_decl.backing_int_type_body != null) .explicit else .auto,
707 .{ .exact = .{707 })) {
708 .name = try file.internFullyQualifiedName(pt),708 .existing => unreachable, // it would have been set as `zcu.fileRootType` already
709 .nav = .none,709 .wip => |wip| wip,
710 } },710 };
711 );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
712 zcu.setFileRootType(file_index, file_root_type.toIntern());738 zcu.setFileRootType(file_index, file_root_type.toIntern());
713 if (zcu.comp.time_report) |*tr| tr.stats.n_imported_files += 1;739 if (zcu.comp.time_report) |*tr| tr.stats.n_imported_files += 1;
714}740}
...@@ -1048,11 +1074,6 @@ pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void...@@ -1048,11 +1074,6 @@ pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void
10481074
1049 assert(!zcu.analysis_in_progress.contains(anal_unit));1075 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
1056 const was_outdated = zcu.outdated.swapRemove(anal_unit) or1077 const was_outdated = zcu.outdated.swapRemove(anal_unit) or
1057 zcu.potentially_outdated.swapRemove(anal_unit);1078 zcu.potentially_outdated.swapRemove(anal_unit);
10581079
...@@ -1113,17 +1134,11 @@ pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void...@@ -1113,17 +1134,11 @@ pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void
1113 };1134 };
1114 defer sema.deinit();1135 defer sema.deinit();
11151136
1116 const result = switch (ty.containerLayout(zcu)) {1137 const result = switch (ty.zigTypeTag(zcu)) {
1117 .auto, .@"extern" => switch (ty.zigTypeTag(zcu)) {1138 .@"enum" => Sema.type_resolution.resolveEnumLayout(&sema, ty),
1118 .@"struct" => Sema.type_resolution.resolveStructLayout(&sema, ty),1139 .@"struct" => Sema.type_resolution.resolveStructLayout(&sema, ty),
1119 .@"union" => Sema.type_resolution.resolveUnionLayout(&sema, ty),1140 .@"union" => Sema.type_resolution.resolveUnionLayout(&sema, ty),
1120 else => unreachable,1141 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 },
1127 };1142 };
1128 result catch |err| switch (err) {1143 result catch |err| switch (err) {
1129 error.AnalysisFail => {1144 error.AnalysisFail => {
...@@ -1145,36 +1160,31 @@ pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void...@@ -1145,36 +1160,31 @@ pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void
1145 sema.flushExports() catch |err| switch (err) {1160 sema.flushExports() catch |err| switch (err) {
1146 error.OutOfMemory => |e| return e,1161 error.OutOfMemory => |e| return e,
1147 };1162 };
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 }
1155}1163}
11561164
1157/// Ensures that the default/tag values of the given `struct` or `enum` type are fully up-to-date,1165/// Ensures that the default values of the given "declared" (not reified) `struct` type are fully
1158/// performing re-analysis if necessary. Asserts that `ty` is a struct (not a tuple!) or an enum.1166/// up-to-date, performing re-analysis if necessary. Asserts that `ty` is a struct (not tuple) type.
1159/// Returns `error.AnalysisFail` if an analysis error is encountered during resolution; the caller1167/// Returns `error.AnalysisFail` if an analysis error is encountered while resolving the default
1160/// is free to ignore this, since the error is already registered.1168/// field values; the caller is free to ignore this, since the error is already registered.
1161pub fn ensureTypeInitsUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void {1169pub fn ensureStructDefaultsUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void {
1162 const tracy = trace(@src());1170 const tracy = trace(@src());
1163 defer tracy.end();1171 defer tracy.end();
11641172
1165 const zcu = pt.zcu;1173 const zcu = pt.zcu;
1166 const gpa = zcu.gpa;1174 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
1172 assert(!zcu.analysis_in_progress.contains(anal_unit));1183 assert(!zcu.analysis_in_progress.contains(anal_unit));
11731184
1174 // Determine whether or not this type is outdated. For this kind of `AnalUnit`, that's1185 // Determine whether or not this type is outdated. For this kind of `AnalUnit`, that's
1175 // the only indicator as to whether or not analysis is required; when a struct/enum is1186 // the only indicator as to whether or not analysis is required; when a struct/enum is
1176 // first created, it's marked as outdated.1187 // first created, it's marked as outdated.
1177 // MLUGG TODO: make that actually true, it's a good strategy here!
11781188
1179 const was_outdated = zcu.outdated.swapRemove(anal_unit) or1189 const was_outdated = zcu.outdated.swapRemove(anal_unit) or
1180 zcu.potentially_outdated.swapRemove(anal_unit);1190 zcu.potentially_outdated.swapRemove(anal_unit);
...@@ -1194,7 +1204,7 @@ pub fn ensureTypeInitsUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void {...@@ -1194,7 +1204,7 @@ pub fn ensureTypeInitsUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void {
1194 }1204 }
1195 // For types, we already know that we have to invalidate all dependees.1205 // For types, we already know that we have to invalidate all dependees.
1196 // TODO: we actually *could* detect whether everything was the same. should we bother?1206 // 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() });
1198 } else {1208 } else {
1199 // We can trust the current information about this unit.1209 // We can trust the current information about this unit.
1200 if (zcu.failed_analysis.contains(anal_unit)) return error.AnalysisFail;1210 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 {...@@ -1236,12 +1246,7 @@ pub fn ensureTypeInitsUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void {
1236 };1246 };
1237 defer sema.deinit();1247 defer sema.deinit();
12381248
1239 const result = switch (ty.zigTypeTag(zcu)) {1249 Sema.type_resolution.resolveStructDefaults(&sema, ty) catch |err| switch (err) {
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) {
1245 error.AnalysisFail => {1250 error.AnalysisFail => {
1246 if (!zcu.failed_analysis.contains(anal_unit)) {1251 if (!zcu.failed_analysis.contains(anal_unit)) {
1247 // If this unit caused the error, it would have an entry in `failed_analysis`.1252 // 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...@@ -1270,20 +1275,6 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu
1270 const tracy = trace(@src());1275 const tracy = trace(@src());
1271 defer tracy.end();1276 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
1287 const zcu = pt.zcu;1278 const zcu = pt.zcu;
1288 const gpa = zcu.gpa;1279 const gpa = zcu.gpa;
1289 const ip = &zcu.intern_pool;1280 const ip = &zcu.intern_pool;
...@@ -3033,7 +3024,7 @@ fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.Sem...@@ -3033,7 +3024,7 @@ fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.Sem
3033 const zir = file.zir.?;3024 const zir = file.zir.?;
30343025
3035 try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, {});3026 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
3038 func.setAnalyzed(ip, io);3029 func.setAnalyzed(ip, io);
3039 if (func.analysisUnordered(ip).inferred_error_set) {3030 if (func.analysisUnordered(ip).inferred_error_set) {
...@@ -3231,9 +3222,6 @@ fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.Sem...@@ -3231,9 +3222,6 @@ fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.Sem
3231 func.setResolvedErrorSet(ip, io, ies.resolved);3222 func.setResolvedErrorSet(ip, io, ies.resolved);
3232 }3223 }
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
3237 try sema.flushExports();3225 try sema.flushExports();
32383226
3239 defer {3227 defer {
...@@ -3835,7 +3823,6 @@ pub fn enumValue(pt: Zcu.PerThread, ty: Type, tag_int: InternPool.Index) Allocat...@@ -3835,7 +3823,6 @@ pub fn enumValue(pt: Zcu.PerThread, ty: Type, tag_int: InternPool.Index) Allocat
3835/// declaration order.3823/// declaration order.
3836pub fn enumValueFieldIndex(pt: Zcu.PerThread, ty: Type, field_index: u32) Allocator.Error!Value {3824pub fn enumValueFieldIndex(pt: Zcu.PerThread, ty: Type, field_index: u32) Allocator.Error!Value {
3837 const ip = &pt.zcu.intern_pool;3825 const ip = &pt.zcu.intern_pool;
3838 ty.assertHasInits(pt.zcu);
3839 const enum_type = ip.loadEnumType(ty.toIntern());3826 const enum_type = ip.loadEnumType(ty.toIntern());
38403827
3841 assert(field_index < enum_type.field_names.len);3828 assert(field_index < enum_type.field_names.len);
...@@ -3859,7 +3846,9 @@ pub fn enumValueFieldIndex(pt: Zcu.PerThread, ty: Type, field_index: u32) Alloca...@@ -3859,7 +3846,9 @@ pub fn enumValueFieldIndex(pt: Zcu.PerThread, ty: Type, field_index: u32) Alloca
38593846
3860pub fn undefValue(pt: Zcu.PerThread, ty: Type) Allocator.Error!Value {3847pub fn undefValue(pt: Zcu.PerThread, ty: Type) Allocator.Error!Value {
3861 if (std.debug.runtime_safety) {3848 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 }
3863 }3852 }
3864 return .fromInterned(try pt.intern(.{ .undef = ty.toIntern() }));3853 return .fromInterned(try pt.intern(.{ .undef = ty.toIntern() }));
3865}3854}
...@@ -3941,7 +3930,10 @@ pub fn aggregateValue(pt: Zcu.PerThread, ty: Type, elems: []const InternPool.Ind...@@ -3941,7 +3930,10 @@ pub fn aggregateValue(pt: Zcu.PerThread, ty: Type, elems: []const InternPool.Ind
3941 for (elems) |elem| {3930 for (elems) |elem| {
3942 if (!Value.fromInterned(elem).isUndef(pt.zcu)) break;3931 if (!Value.fromInterned(elem).isUndef(pt.zcu)) break;
3943 } else if (elems.len > 0) {3932 } else if (elems.len > 0) {
3944 return pt.undefValue(ty); // all-undef3933 // 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() }));
3945 }3937 }
3946 return .fromInterned(try pt.intern(.{ .aggregate = .{3938 return .fromInterned(try pt.intern(.{ .aggregate = .{
3947 .ty = ty.toIntern(),3939 .ty = ty.toIntern(),
...@@ -4096,19 +4088,6 @@ pub fn getExtern(pt: Zcu.PerThread, key: InternPool.Key.Extern) Allocator.Error!...@@ -4096,19 +4088,6 @@ pub fn getExtern(pt: Zcu.PerThread, key: InternPool.Key.Extern) Allocator.Error!
4096 return result.index;4088 return result.index;
4097}4089}
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
4112/// Given a namespace, re-scan its declarations from the type definition if they have not4091/// Given a namespace, re-scan its declarations from the type definition if they have not
4113/// yet been re-scanned on this update.4092/// yet been re-scanned on this update.
4114/// If the type declaration instruction has been lost, returns `error.AnalysisFail`.4093/// 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 {...@@ -4393,7 +4372,7 @@ pub fn resolveTypeForCodegen(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void {
4393 .@"struct" => switch (ip.indexToKey(ty.toIntern())) {4372 .@"struct" => switch (ip.indexToKey(ty.toIntern())) {
4394 .struct_type => {4373 .struct_type => {
4395 try pt.ensureTypeLayoutUpToDate(ty);4374 try pt.ensureTypeLayoutUpToDate(ty);
4396 try pt.ensureTypeInitsUpToDate(ty);4375 try pt.ensureStructDefaultsUpToDate(ty);
4397 },4376 },
4398 .tuple_type => |tuple| for (0..tuple.types.len) |i| {4377 .tuple_type => |tuple| for (0..tuple.types.len) |i| {
4399 const field_is_comptime = tuple.values.get(ip)[i] != .none;4378 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 {...@@ -4405,7 +4384,7 @@ pub fn resolveTypeForCodegen(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void {
4405 },4384 },
44064385
4407 .@"union" => try pt.ensureTypeLayoutUpToDate(ty),4386 .@"union" => try pt.ensureTypeLayoutUpToDate(ty),
4408 .@"enum" => try pt.ensureTypeInitsUpToDate(ty),4387 .@"enum" => try pt.ensureTypeLayoutUpToDate(ty),
4409 }4388 }
4410}4389}
4411pub fn resolveValueTypesForCodegen(pt: Zcu.PerThread, val: Value) Zcu.SemaError!void {4390pub fn resolveValueTypesForCodegen(pt: Zcu.PerThread, val: Value) Zcu.SemaError!void {
src/codegen.zig+5-6
...@@ -347,7 +347,6 @@ pub fn generateSymbol(...@@ -347,7 +347,6 @@ pub fn generateSymbol(
347 .void => unreachable, // non-runtime value347 .void => unreachable, // non-runtime value
348 .null => unreachable, // non-runtime value348 .null => unreachable, // non-runtime value
349 .@"unreachable" => unreachable, // non-runtime value349 .@"unreachable" => unreachable, // non-runtime value
350 .empty_tuple => return,
351 .false, .true => try w.writeByte(switch (simple_value) {350 .false, .true => try w.writeByte(switch (simple_value) {
352 .false => 0,351 .false => 0,
353 .true => 1,352 .true => 1,
...@@ -1065,20 +1064,20 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo...@@ -1065,20 +1064,20 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo
1065 const elem_ty = ty.childType(zcu);1064 const elem_ty = ty.childType(zcu);
1066 const ptr = ip.indexToKey(val.toIntern()).ptr;1065 const ptr = ip.indexToKey(val.toIntern()).ptr;
1067 if (ptr.base_addr == .int) return .{ .immediate = ptr.byte_offset };1066 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) {
1069 .int => unreachable, // handled above1068 .int => unreachable, // handled above
10701069
1071 .nav => |nav| if (elem_ty.isFnOrHasRuntimeBits(zcu)) {1070 .nav => |nav| if (elem_ty.isRuntimeFnOrHasRuntimeBits(zcu)) {
1072 return .{ .lea_nav = nav };1071 return .{ .lea_nav = nav };
1073 } else {1072 } else {
1074 // Create the 0xaa bit pattern...1073 // Create the 0xaa bit pattern...
1075 const undef_ptr_bits: u64 = @intCast((@as(u66, 1) << @intCast(target.ptrBitWidth() + 1)) / 3);1074 const undef_ptr_bits: u64 = @intCast((@as(u66, 1) << @intCast(target.ptrBitWidth() + 1)) / 3);
1076 // ...but align the pointer1075 // ...but align the pointer
1077 const alignment = pt.navAlignment(nav);1076 const alignment = zcu.navAlignment(nav);
1078 return .{ .immediate = alignment.forward(undef_ptr_bits) };1077 return .{ .immediate = alignment.forward(undef_ptr_bits) };
1079 },1078 },
10801079
1081 .uav => |uav| if (elem_ty.isFnOrHasRuntimeBits(zcu)) {1080 .uav => |uav| if (elem_ty.isRuntimeFnOrHasRuntimeBits(zcu)) {
1082 return .{ .lea_uav = uav };1081 return .{ .lea_uav = uav };
1083 } else {1082 } else {
1084 // Create the 0xaa bit pattern...1083 // Create the 0xaa bit pattern...
...@@ -1089,7 +1088,7 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo...@@ -1089,7 +1088,7 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo
1089 },1088 },
10901089
1091 else => {},1090 else => {},
1092 }1091 };
1093 },1092 },
1094 },1093 },
1095 .int => {1094 .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,...@@ -6594,7 +6594,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
6594 if (try isel.hasRepeatedByteRepr(.fromInterned(fill_val))) |fill_byte|6594 if (try isel.hasRepeatedByteRepr(.fromInterned(fill_val))) |fill_byte|
6595 break :fill_byte .{ .constant = fill_byte };6595 break :fill_byte .{ .constant = fill_byte };
6596 }6596 }
6597 switch (dst_ty.indexablePtrElem(zcu).abiSize(zcu)) {6597 switch (dst_ty.indexableElem(zcu).abiSize(zcu)) {
6598 0 => unreachable,6598 0 => unreachable,
6599 1 => break :fill_byte .{ .value = bin_op.rhs },6599 1 => break :fill_byte .{ .value = bin_op.rhs },
6600 2, 4, 8 => |size| {6600 2, 4, 8 => |size| {
...@@ -7217,7 +7217,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -7217,7 +7217,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
7217 const ptr_ra = try ptr_vi.value.defReg(isel) orelse break :unused;7217 const ptr_ra = try ptr_vi.value.defReg(isel) orelse break :unused;
72187218
7219 const ty_nav = air.data(air.inst_index).ty_nav;7219 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) {
7221 false => {7221 false => {
7222 try isel.nav_relocs.append(gpa, .{7222 try isel.nav_relocs.append(gpa, .{
7223 .nav = ty_nav.nav,7223 .nav = ty_nav.nav,
...@@ -7240,7 +7240,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -7240,7 +7240,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
7240 });7240 });
7241 try isel.emit(.adrp(ptr_ra.x(), 0));7241 try isel.emit(.adrp(ptr_ra.x(), 0));
7242 },7242 },
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));
7244 }7244 }
7245 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;7245 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
7246 },7246 },
...@@ -10738,7 +10738,7 @@ pub const Value = struct {...@@ -10738,7 +10738,7 @@ pub const Value = struct {
10738 } }),10738 } }),
10739 }),10739 }),
10740 .simple_value => |simple_value| switch (simple_value) {10740 .simple_value => |simple_value| switch (simple_value) {
10741 .undefined, .void, .null, .empty_tuple, .@"unreachable" => unreachable,10741 .undefined, .void, .null, .@"unreachable" => unreachable,
10742 .true => continue :constant_key .{ .int = .{10742 .true => continue :constant_key .{ .int = .{
10743 .ty = .bool_type,10743 .ty = .bool_type,
10744 .storage = .{ .u64 = 1 },10744 .storage = .{ .u64 = 1 },
...@@ -10931,7 +10931,7 @@ pub const Value = struct {...@@ -10931,7 +10931,7 @@ pub const Value = struct {
10931 .ptr => |ptr| {10931 .ptr => |ptr| {
10932 assert(offset == 0 and size == 8);10932 assert(offset == 0 and size == 8);
10933 break :free switch (ptr.base_addr) {10933 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) {
10935 false => {10935 false => {
10936 try isel.nav_relocs.append(zcu.gpa, .{10936 try isel.nav_relocs.append(zcu.gpa, .{
10937 .nav = nav,10937 .nav = nav,
...@@ -10965,9 +10965,9 @@ pub const Value = struct {...@@ -10965,9 +10965,9 @@ pub const Value = struct {
10965 },10965 },
10966 } else continue :constant_key .{ .int = .{10966 } else continue :constant_key .{ .int = .{
10967 .ty = .usize_type,10967 .ty = .usize_type,
10968 .storage = .{ .u64 = isel.pt.navAlignment(nav).forward(0xaaaaaaaaaaaaaaaa) },10968 .storage = .{ .u64 = zcu.navAlignment(nav).forward(0xaaaaaaaaaaaaaaaa) },
10969 } },10969 } },
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) {
10971 false => {10971 false => {
10972 try isel.uav_relocs.append(zcu.gpa, .{10972 try isel.uav_relocs.append(zcu.gpa, .{
10973 .uav = uav,10973 .uav = uav,
src/codegen/c.zig+8-9
...@@ -789,7 +789,7 @@ pub const DeclGen = struct {...@@ -789,7 +789,7 @@ pub const DeclGen = struct {
789789
790 // Render an undefined pointer if we have a pointer to a zero-bit or comptime type.790 // Render an undefined pointer if we have a pointer to a zero-bit or comptime type.
791 const ptr_ty: Type = .fromInterned(uav.orig_ty);791 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)) {
793 return dg.writeCValue(w, .{ .undef = ptr_ty });793 return dg.writeCValue(w, .{ .undef = ptr_ty });
794 }794 }
795795
...@@ -862,7 +862,7 @@ pub const DeclGen = struct {...@@ -862,7 +862,7 @@ pub const DeclGen = struct {
862 // Render an undefined pointer if we have a pointer to a zero-bit or comptime type.862 // Render an undefined pointer if we have a pointer to a zero-bit or comptime type.
863 const nav_ty: Type = .fromInterned(ip.getNav(owner_nav).typeOf(ip));863 const nav_ty: Type = .fromInterned(ip.getNav(owner_nav).typeOf(ip));
864 const ptr_ty = try pt.navPtrType(owner_nav);864 const ptr_ty = try pt.navPtrType(owner_nav);
865 if (!nav_ty.isFnOrHasRuntimeBits(zcu)) {865 if (!nav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) {
866 return dg.writeCValue(w, .{ .undef = ptr_ty });866 return dg.writeCValue(w, .{ .undef = ptr_ty });
867 }867 }
868868
...@@ -1043,7 +1043,6 @@ pub const DeclGen = struct {...@@ -1043,7 +1043,6 @@ pub const DeclGen = struct {
1043 .undefined => unreachable,1043 .undefined => unreachable,
1044 .void => unreachable,1044 .void => unreachable,
1045 .null => unreachable,1045 .null => unreachable,
1046 .empty_tuple => unreachable,
1047 .@"unreachable" => unreachable,1046 .@"unreachable" => unreachable,
10481047
1049 .false => try w.writeAll("false"),1048 .false => try w.writeAll("false"),
...@@ -3077,7 +3076,7 @@ pub fn genDecl(o: *Object) Error!void {...@@ -3077,7 +3076,7 @@ pub fn genDecl(o: *Object) Error!void {
3077 const nav = ip.getNav(o.dg.pass.nav);3076 const nav = ip.getNav(o.dg.pass.nav);
3078 const nav_ty: Type = .fromInterned(nav.typeOf(ip));3077 const nav_ty: Type = .fromInterned(nav.typeOf(ip));
30793078
3080 if (!nav_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return;3079 if (!nav_ty.hasRuntimeBits(zcu)) return;
3081 switch (ip.indexToKey(nav.status.fully_resolved.val)) {3080 switch (ip.indexToKey(nav.status.fully_resolved.val)) {
3082 .@"extern" => |@"extern"| {3081 .@"extern" => |@"extern"| {
3083 if (!ip.isFunctionType(nav_ty.toIntern())) return o.dg.renderFwdDecl(o.dg.pass.nav, .{3082 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 {...@@ -3676,7 +3675,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
36763675
3677 const inst_ty = f.typeOfIndex(inst);3676 const inst_ty = f.typeOfIndex(inst);
3678 const ptr_ty = f.typeOf(bin_op.lhs);3677 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
3681 const ptr = try f.resolveInst(bin_op.lhs);3680 const ptr = try f.resolveInst(bin_op.lhs);
3682 const index = try f.resolveInst(bin_op.rhs);3681 const index = try f.resolveInst(bin_op.rhs);
...@@ -3792,7 +3791,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3792,7 +3791,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
3792 const zcu = pt.zcu;3791 const zcu = pt.zcu;
3793 const inst_ty = f.typeOfIndex(inst);3792 const inst_ty = f.typeOfIndex(inst);
3794 const elem_ty = inst_ty.childType(zcu);3793 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
3797 const local = try f.allocLocalValue(.{3796 const local = try f.allocLocalValue(.{
3798 .ctype = try f.ctypeFromType(elem_ty, .complete),3797 .ctype = try f.ctypeFromType(elem_ty, .complete),
...@@ -3829,7 +3828,7 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3829,7 +3828,7 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
3829 const zcu = pt.zcu;3828 const zcu = pt.zcu;
3830 const inst_ty = f.typeOfIndex(inst);3829 const inst_ty = f.typeOfIndex(inst);
3831 const elem_ty = inst_ty.childType(zcu);3830 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
3834 const local = try f.allocLocalValue(.{3833 const local = try f.allocLocalValue(.{
3835 .ctype = try f.ctypeFromType(elem_ty, .complete),3834 .ctype = try f.ctypeFromType(elem_ty, .complete),
...@@ -4502,7 +4501,7 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {...@@ -4502,7 +4501,7 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
45024501
4503 const inst_ty = f.typeOfIndex(inst);4502 const inst_ty = f.typeOfIndex(inst);
4504 const inst_scalar_ty = inst_ty.scalarType(zcu);4503 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);
4506 if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) return f.moveCValue(inst, inst_ty, lhs);4505 if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) return f.moveCValue(inst, inst_ty, lhs);
4507 const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete);4506 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...@@ -7037,7 +7036,7 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index, function_paren: []const u8) !CV
7037 try w.writeAll(", ");7036 try w.writeAll(", ");
7038 try writeArrayLen(f, dest_ptr, dest_ty);7037 try writeArrayLen(f, dest_ptr, dest_ty);
7039 try w.writeAll(" * sizeof(");7038 try w.writeAll(" * sizeof(");
7040 try f.renderType(w, dest_ty.indexablePtrElem(zcu));7039 try f.renderType(w, dest_ty.indexableElem(zcu));
7041 try w.writeAll("));");7040 try w.writeAll("));");
7042 try f.object.newline();7041 try f.object.newline();
70437042
src/codegen/llvm.zig+7-8
...@@ -3725,7 +3725,6 @@ pub const Object = struct {...@@ -3725,7 +3725,6 @@ pub const Object = struct {
3725 .undefined => unreachable, // non-runtime value3725 .undefined => unreachable, // non-runtime value
3726 .void => unreachable, // non-runtime value3726 .void => unreachable, // non-runtime value
3727 .null => unreachable, // non-runtime value3727 .null => unreachable, // non-runtime value
3728 .empty_tuple => unreachable, // non-runtime value
3729 .@"unreachable" => unreachable, // non-runtime value3728 .@"unreachable" => unreachable, // non-runtime value
37303729
3731 .false => .false,3730 .false => .false,
...@@ -4604,7 +4603,7 @@ pub const NavGen = struct {...@@ -4604,7 +4603,7 @@ pub const NavGen = struct {
4604 _ = try o.resolveLlvmFunction(pt, owner_nav);4603 _ = try o.resolveLlvmFunction(pt, owner_nav);
4605 } else {4604 } else {
4606 const variable_index = try o.resolveGlobalNav(pt, nav_index);4605 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);
4608 if (resolved.@"linksection".toSlice(ip)) |section|4607 if (resolved.@"linksection".toSlice(ip)) |section|
4609 variable_index.setSection(try o.builder.string(section), &o.builder);4608 variable_index.setSection(try o.builder.string(section), &o.builder);
4610 if (is_const) variable_index.setMutability(.constant, &o.builder);4609 if (is_const) variable_index.setMutability(.constant, &o.builder);
...@@ -5953,7 +5952,7 @@ pub const FuncGen = struct {...@@ -5953,7 +5952,7 @@ pub const FuncGen = struct {
5953 return .none;5952 return .none;
5954 }5953 }
59555954
5956 const have_block_result = inst_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu);5955 const have_block_result = inst_ty.hasRuntimeBits(zcu);
59575956
5958 var breaks: BreakList = if (have_block_result) .{ .list = .{} } else .{ .len = 0 };5957 var breaks: BreakList = if (have_block_result) .{ .list = .{} } else .{ .len = 0 };
5959 defer if (have_block_result) breaks.list.deinit(self.gpa);5958 defer if (have_block_result) breaks.list.deinit(self.gpa);
...@@ -6000,7 +5999,7 @@ pub const FuncGen = struct {...@@ -6000,7 +5999,7 @@ pub const FuncGen = struct {
60005999
6001 // Add the values to the lists only if the break provides a value.6000 // Add the values to the lists only if the break provides a value.
6002 const operand_ty = self.typeOf(branch.operand);6001 const operand_ty = self.typeOf(branch.operand);
6003 if (operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {6002 if (operand_ty.hasRuntimeBits(zcu)) {
6004 const val = try self.resolveInst(branch.operand);6003 const val = try self.resolveInst(branch.operand);
60056004
6006 // For the phi node, we need the basic blocks and the values of the6005 // For the phi node, we need the basic blocks and the values of the
...@@ -9581,7 +9580,7 @@ pub const FuncGen = struct {...@@ -9581,7 +9580,7 @@ pub const FuncGen = struct {
9581 const zcu = pt.zcu;9580 const zcu = pt.zcu;
9582 const ptr_ty = self.typeOfIndex(inst);9581 const ptr_ty = self.typeOfIndex(inst);
9583 const pointee_type = ptr_ty.childType(zcu);9582 const pointee_type = ptr_ty.childType(zcu);
9584 if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime(zcu))9583 if (!pointee_type.hasRuntimeBits(zcu))
9585 return (try o.lowerPtrToVoid(pt, ptr_ty)).toValue();9584 return (try o.lowerPtrToVoid(pt, ptr_ty)).toValue();
95869585
9587 const pointee_llvm_ty = try o.lowerType(pt, pointee_type);9586 const pointee_llvm_ty = try o.lowerType(pt, pointee_type);
...@@ -9595,7 +9594,7 @@ pub const FuncGen = struct {...@@ -9595,7 +9594,7 @@ pub const FuncGen = struct {
9595 const zcu = pt.zcu;9594 const zcu = pt.zcu;
9596 const ptr_ty = self.typeOfIndex(inst);9595 const ptr_ty = self.typeOfIndex(inst);
9597 const ret_ty = ptr_ty.childType(zcu);9596 const ret_ty = ptr_ty.childType(zcu);
9598 if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu))9597 if (!ret_ty.hasRuntimeBits(zcu))
9599 return (try o.lowerPtrToVoid(pt, ptr_ty)).toValue();9598 return (try o.lowerPtrToVoid(pt, ptr_ty)).toValue();
9600 if (self.ret_ptr != .none) return self.ret_ptr;9599 if (self.ret_ptr != .none) return self.ret_ptr;
9601 const ret_llvm_ty = try o.lowerType(pt, ret_ty);9600 const ret_llvm_ty = try o.lowerType(pt, ret_ty);
...@@ -9897,7 +9896,7 @@ pub const FuncGen = struct {...@@ -9897,7 +9896,7 @@ pub const FuncGen = struct {
9897 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;9896 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
9898 const ptr_ty = self.typeOf(bin_op.lhs);9897 const ptr_ty = self.typeOf(bin_op.lhs);
9899 const operand_ty = ptr_ty.childType(zcu);9898 const operand_ty = ptr_ty.childType(zcu);
9900 if (!operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return .none;9899 if (!operand_ty.hasRuntimeBits(zcu)) return .none;
9901 const ptr = try self.resolveInst(bin_op.lhs);9900 const ptr = try self.resolveInst(bin_op.lhs);
9902 var element = try self.resolveInst(bin_op.rhs);9901 var element = try self.resolveInst(bin_op.rhs);
9903 const llvm_abi_ty = try o.getAtomicAbiType(pt, operand_ty, false);9902 const llvm_abi_ty = try o.getAtomicAbiType(pt, operand_ty, false);
...@@ -11478,7 +11477,7 @@ pub const FuncGen = struct {...@@ -11478,7 +11477,7 @@ pub const FuncGen = struct {
11478 const zcu = pt.zcu;11477 const zcu = pt.zcu;
11479 const info = ptr_ty.ptrInfo(zcu);11478 const info = ptr_ty.ptrInfo(zcu);
11480 const elem_ty = Type.fromInterned(info.child);11479 const elem_ty = Type.fromInterned(info.child);
11481 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {11480 if (!elem_ty.hasRuntimeBits(zcu)) {
11482 return;11481 return;
11483 }11482 }
11484 const ptr_alignment = ptr_ty.ptrAlignment(zcu).toLlvm();11483 const ptr_alignment = ptr_ty.ptrAlignment(zcu).toLlvm();
src/codegen/riscv64/CodeGen.zig+2-2
...@@ -2673,7 +2673,7 @@ fn genBinOp(...@@ -2673,7 +2673,7 @@ fn genBinOp(
2673 defer func.register_manager.unlockReg(tmp_lock);2673 defer func.register_manager.unlockReg(tmp_lock);
26742674
2675 // RISC-V has no immediate mul, so we copy the size to a temporary register2675 // 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);
2677 const elem_size_reg = try func.copyToTmpRegister(Type.u64, .{ .immediate = elem_size });2677 const elem_size_reg = try func.copyToTmpRegister(Type.u64, .{ .immediate = elem_size });
26782678
2679 try func.genBinOp(2679 try func.genBinOp(
...@@ -3913,7 +3913,7 @@ fn airPtrElemVal(func: *Func, inst: Air.Inst.Index) !void {...@@ -3913,7 +3913,7 @@ fn airPtrElemVal(func: *Func, inst: Air.Inst.Index) !void {
3913 const base_ptr_ty = func.typeOf(bin_op.lhs);3913 const base_ptr_ty = func.typeOf(bin_op.lhs);
39143914
3915 const result: MCValue = if (!is_volatile and func.liveness.isUnused(inst)) .unreach else result: {3915 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);
3917 if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none;3917 if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none;
3918 const base_ptr_mcv = try func.resolveInst(bin_op.lhs);3918 const base_ptr_mcv = try func.resolveInst(bin_op.lhs);
3919 const base_ptr_lock: ?RegisterLock = switch (base_ptr_mcv) {3919 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 {...@@ -821,7 +821,6 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
821 .undefined,821 .undefined,
822 .void,822 .void,
823 .null,823 .null,
824 .empty_tuple,
825 .@"unreachable",824 .@"unreachable",
826 => unreachable, // non-runtime values825 => unreachable, // non-runtime values
827826
...@@ -1150,7 +1149,7 @@ fn constantUavRef(...@@ -1150,7 +1149,7 @@ fn constantUavRef(
1150 }1149 }
11511150
1152 // const is_fn_body = decl_ty.zigTypeTag(zcu) == .@"fn";1151 // const is_fn_body = decl_ty.zigTypeTag(zcu) == .@"fn";
1153 if (!uav_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {1152 if (!uav_ty.hasRuntimeBits(zcu)) {
1154 // Pointer to nothing - return undefined1153 // Pointer to nothing - return undefined
1155 return cg.module.constUndef(ty_id);1154 return cg.module.constUndef(ty_id);
1156 }1155 }
...@@ -1196,7 +1195,7 @@ fn constantNavRef(cg: *CodeGen, ty: Type, nav_index: InternPool.Nav.Index) !Id {...@@ -1196,7 +1195,7 @@ fn constantNavRef(cg: *CodeGen, ty: Type, nav_index: InternPool.Nav.Index) !Id {
1196 },1195 },
1197 }1196 }
11981197
1199 if (!nav_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {1198 if (!nav_ty.hasRuntimeBits(zcu)) {
1200 // Pointer to nothing - return undefined.1199 // Pointer to nothing - return undefined.
1201 return cg.module.constUndef(ty_id);1200 return cg.module.constUndef(ty_id);
1202 }1201 }
...@@ -4381,7 +4380,7 @@ fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4381,7 +4380,7 @@ fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4381fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id {4380fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id {
4382 const zcu = cg.module.zcu;4381 const zcu = cg.module.zcu;
4383 // Construct new pointer type for the resulting pointer4382 // Construct new pointer type for the resulting pointer
4384 const elem_ty = ptr_ty.indexablePtrElem(zcu);4383 const elem_ty = ptr_ty.indexableElem(zcu);
4385 const elem_ty_id = try cg.resolveType(elem_ty, .indirect);4384 const elem_ty_id = try cg.resolveType(elem_ty, .indirect);
4386 const elem_ptr_ty_id = try cg.module.ptrType(elem_ty_id, cg.module.storageClass(ptr_ty.ptrAddressSpace(zcu)));4385 const elem_ptr_ty_id = try cg.module.ptrType(elem_ty_id, cg.module.storageClass(ptr_ty.ptrAddressSpace(zcu)));
4387 if (ptr_ty.isSinglePointer(zcu)) {4386 if (ptr_ty.isSinglePointer(zcu)) {
...@@ -5028,7 +5027,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)...@@ -5028,7 +5027,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
5028 const gpa = cg.module.gpa;5027 const gpa = cg.module.gpa;
5029 const zcu = cg.module.zcu;5028 const zcu = cg.module.zcu;
5030 const ty = cg.typeOfIndex(inst);5029 const ty = cg.typeOfIndex(inst);
5031 const have_block_result = ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu);5030 const have_block_result = ty.hasRuntimeBits(zcu);
50325031
5033 const cf = switch (cg.control_flow) {5032 const cf = switch (cg.control_flow) {
5034 .structured => |*cf| cf,5033 .structured => |*cf| cf,
...@@ -5166,7 +5165,7 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -5166,7 +5165,7 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
51665165
5167 switch (cg.control_flow) {5166 switch (cg.control_flow) {
5168 .structured => |*cf| {5167 .structured => |*cf| {
5169 if (operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {5168 if (operand_ty.hasRuntimeBits(zcu)) {
5170 const operand_id = try cg.resolve(br.operand);5169 const operand_id = try cg.resolve(br.operand);
5171 const block_result_var_id = cf.block_results.get(br.block_inst).?;5170 const block_result_var_id = cf.block_results.get(br.block_inst).?;
5172 try cg.store(operand_ty, block_result_var_id, operand_id, .{});5171 try cg.store(operand_ty, block_result_var_id, operand_id, .{});
...@@ -5177,7 +5176,7 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -5177,7 +5176,7 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
5177 },5176 },
5178 .unstructured => |cf| {5177 .unstructured => |cf| {
5179 const block = cf.blocks.get(br.block_inst).?;5178 const block = cf.blocks.get(br.block_inst).?;
5180 if (operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {5179 if (operand_ty.hasRuntimeBits(zcu)) {
5181 const operand_id = try cg.resolve(br.operand);5180 const operand_id = try cg.resolve(br.operand);
5182 // block_label should not be undefined here, lest there5181 // block_label should not be undefined here, lest there
5183 // is a br or br_void in the function's body.5182 // 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 {...@@ -2099,7 +2099,7 @@ fn airRetPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2099 const child_type = cg.typeOfIndex(inst).childType(zcu);2099 const child_type = cg.typeOfIndex(inst).childType(zcu);
21002100
2101 const result = result: {2101 const result = result: {
2102 if (!child_type.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {2102 if (!child_type.hasRuntimeBits(zcu)) {
2103 break :result try cg.allocStack(Type.usize); // create pointer to void2103 break :result try cg.allocStack(Type.usize); // create pointer to void
2104 }2104 }
21052105
...@@ -3161,7 +3161,6 @@ fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue {...@@ -3161,7 +3161,6 @@ fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue {
3161 .undefined,3161 .undefined,
3162 .void,3162 .void,
3163 .null,3163 .null,
3164 .empty_tuple,
3165 .@"unreachable",3164 .@"unreachable",
3166 => unreachable, // non-runtime values3165 => unreachable, // non-runtime values
3167 .false, .true => return .{ .imm32 = switch (simple_value) {3166 .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 {...@@ -104121,7 +104121,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
104121 },104121 },
104122 .slice_elem_val, .ptr_elem_val => {104122 .slice_elem_val, .ptr_elem_val => {
104123 const bin_op = air_datas[@intFromEnum(inst)].bin_op;104123 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);
104125 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });104125 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
104126 try ops[0].toSlicePtr(cg);104126 try ops[0].toSlicePtr(cg);
104127 var res: [1]Temp = undefined;104127 var res: [1]Temp = undefined;
...@@ -188179,8 +188179,8 @@ const Select = struct {...@@ -188179,8 +188179,8 @@ const Select = struct {
188179 .signed => false,188179 .signed => false,
188180 .unsigned => size.bitSize(cg.target) >= int_info.bits,188180 .unsigned => size.bitSize(cg.target) >= int_info.bits,
188181 } else false,188181 } else false,
188182 .elem_size_is => |size| size == ty.indexablePtrElem(zcu).abiSize(zcu),188182 .elem_size_is => |size| size == ty.indexableElem(zcu).abiSize(zcu),
188183 .po2_elem_size => std.math.isPowerOfTwo(ty.indexablePtrElem(zcu).abiSize(zcu)),188183 .po2_elem_size => std.math.isPowerOfTwo(ty.indexableElem(zcu).abiSize(zcu)),
188184 };188184 };
188185 }188185 }
188186 };188186 };
...@@ -189941,9 +189941,9 @@ const Select = struct {...@@ -189941,9 +189941,9 @@ const Select = struct {
189941 op.flags.base.ref.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu),189941 op.flags.base.ref.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu),
189942 @divExact(op.flags.base.size.bitSize(s.cg.target), 8),189942 @divExact(op.flags.base.size.bitSize(s.cg.target), 8),
189943 )),189943 )),
189944 .elem_size => @intCast(op.flags.base.ref.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).scalarType(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).scalarType(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)),
189947 .src0_elem_size_mul_src1 => @intCast(Select.Operand.Ref.src0.typeOf(s).indexableElem(s.cg.pt.zcu).abiSize(s.cg.pt.zcu) *189947 .src0_elem_size_mul_src1 => @intCast(Select.Operand.Ref.src0.typeOf(s).indexableElem(s.cg.pt.zcu).abiSize(s.cg.pt.zcu) *
189948 Select.Operand.Ref.src1.valueOf(s).immediate),189948 Select.Operand.Ref.src1.valueOf(s).immediate),
189949 .vector_index => switch (op.flags.base.ref.typeOf(s).ptrInfo(s.cg.pt.zcu).flags.vector_index) {189949 .vector_index => switch (op.flags.base.ref.typeOf(s).ptrInfo(s.cg.pt.zcu).flags.vector_index) {
...@@ -189953,7 +189953,7 @@ const Select = struct {...@@ -189953,7 +189953,7 @@ const Select = struct {
189953 .src1 => @intCast(Select.Operand.Ref.src1.valueOf(s).immediate),189953 .src1 => @intCast(Select.Operand.Ref.src1.valueOf(s).immediate),
189954 .src1_sub_bit_size => @as(SignedImm, @intCast(Select.Operand.Ref.src1.valueOf(s).immediate)) -189954 .src1_sub_bit_size => @as(SignedImm, @intCast(Select.Operand.Ref.src1.valueOf(s).immediate)) -
189955 @as(SignedImm, @intCast(s.cg.nonBoolScalarBitSize(op.flags.base.ref.typeOf(s)))),189955 @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))),
189957 .elem_mask => @as(u8, std.math.maxInt(u8)) >> @intCast(189957 .elem_mask => @as(u8, std.math.maxInt(u8)) >> @intCast(
189958 8 - ((s.cg.unalignedSize(op.flags.base.ref.typeOf(s)) - 1) %189958 8 - ((s.cg.unalignedSize(op.flags.base.ref.typeOf(s)) - 1) %
189959 @divExact(op.flags.base.size.bitSize(s.cg.target), 8) + 1 >>189959 @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...@@ -1552,7 +1552,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
1552 const sec_si = try coff.navSection(zcu, nav.status.fully_resolved);1552 const sec_si = try coff.navSection(zcu, nav.status.fully_resolved);
1553 try coff.nodes.ensureUnusedCapacity(gpa, 1);1553 try coff.nodes.ensureUnusedCapacity(gpa, 1);
1554 const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{1554 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(),
1556 .moved = true,1556 .moved = true,
1557 });1557 });
1558 coff.nodes.appendAssumeCapacity(.{ .nav = nmi });1558 coff.nodes.appendAssumeCapacity(.{ .nav = nmi });
src/link/Elf/ZigObject.zig+1-1
...@@ -1479,7 +1479,7 @@ fn updateTlv(...@@ -1479,7 +1479,7 @@ fn updateTlv(
14791479
1480 log.debug("updateTlv {f}({d})", .{ nav.fqn.fmt(ip), nav_index });1480 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
1484 const sym = self.symbol(sym_index);1484 const sym = self.symbol(sym_index);
1485 const esym = &self.symtab.items(.elf_sym)[sym.esym_index];1485 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)...@@ -2906,7 +2906,7 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
2906 try elf.nodes.ensureUnusedCapacity(gpa, 1);2906 try elf.nodes.ensureUnusedCapacity(gpa, 1);
2907 const sec_si = elf.navSection(ip, nav.status.fully_resolved);2907 const sec_si = elf.navSection(ip, nav.status.fully_resolved);
2908 const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{2908 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(),
2910 .moved = true,2910 .moved = true,
2911 });2911 });
2912 elf.nodes.appendAssumeCapacity(.{ .nav = nmi });2912 elf.nodes.appendAssumeCapacity(.{ .nav = nmi });
src/link/MachO/ZigObject.zig+4-4
...@@ -925,7 +925,7 @@ pub fn updateNav(...@@ -925,7 +925,7 @@ pub fn updateNav(
925925
926 const sect_index = try self.getNavOutputSection(macho_file, zcu, nav_index, code);926 const sect_index = try self.getNavOutputSection(macho_file, zcu, nav_index, code);
927 if (isThreadlocal(macho_file, nav_index))927 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)
929 else929 else
930 try self.updateNavCode(macho_file, pt, nav_index, sym_index, sect_index, code);930 try self.updateNavCode(macho_file, pt, nav_index, sym_index, sect_index, code);
931931
...@@ -1030,13 +1030,13 @@ fn updateNavCode(...@@ -1030,13 +1030,13 @@ fn updateNavCode(
1030fn updateTlv(1030fn updateTlv(
1031 self: *ZigObject,1031 self: *ZigObject,
1032 macho_file: *MachO,1032 macho_file: *MachO,
1033 pt: Zcu.PerThread,1033 zcu: *Zcu,
1034 nav_index: InternPool.Nav.Index,1034 nav_index: InternPool.Nav.Index,
1035 sym_index: Symbol.Index,1035 sym_index: Symbol.Index,
1036 sect_index: u8,1036 sect_index: u8,
1037 code: []const u8,1037 code: []const u8,
1038) !void {1038) !void {
1039 const ip = &pt.zcu.intern_pool;1039 const ip = &zcu.intern_pool;
1040 const nav = ip.getNav(nav_index);1040 const nav = ip.getNav(nav_index);
10411041
1042 log.debug("updateTlv {f} (0x{x})", .{ nav.fqn.fmt(ip), nav_index });1042 log.debug("updateTlv {f} (0x{x})", .{ nav.fqn.fmt(ip), nav_index });
...@@ -1045,7 +1045,7 @@ fn updateTlv(...@@ -1045,7 +1045,7 @@ fn updateTlv(
1045 const init_sym_index = try self.createTlvInitializer(1045 const init_sym_index = try self.createTlvInitializer(
1046 macho_file,1046 macho_file,
1047 nav.fqn.toSlice(ip),1047 nav.fqn.toSlice(ip),
1048 pt.navAlignment(nav_index),1048 zcu.navAlignment(nav_index),
1049 sect_index,1049 sect_index,
1050 code,1050 code,
1051 );1051 );
src/print_value.zig+26-12
...@@ -72,8 +72,13 @@ pub fn print(...@@ -72,8 +72,13 @@ pub fn print(
72 .undef => try writer.writeAll("undefined"),72 .undef => try writer.writeAll("undefined"),
73 .simple_value => |simple_value| switch (simple_value) {73 .simple_value => |simple_value| switch (simple_value) {
74 .void => try writer.writeAll("{}"),74 .void => try writer.writeAll("{}"),
75 .empty_tuple => try writer.writeAll(".{}"),75
76 else => try writer.writeAll(@tagName(simple_value)),76 .undefined,
77 .null,
78 .true,
79 .false,
80 .@"unreachable",
81 => try writer.writeAll(@tagName(simple_value)),
77 },82 },
78 .variable => try writer.writeAll("(variable)"),83 .variable => try writer.writeAll("(variable)"),
79 .@"extern" => |e| try writer.print("(extern '{f}')", .{e.name.fmt(ip)}),84 .@"extern" => |e| try writer.print("(extern '{f}')", .{e.name.fmt(ip)}),
...@@ -248,17 +253,26 @@ fn printAggregate(...@@ -248,17 +253,26 @@ fn printAggregate(
248 const len = ty.arrayLen(zcu);253 const len = ty.arrayLen(zcu);
249254
250 if (is_ref) try writer.writeByte('&');255 if (is_ref) try writer.writeByte('&');
251 try writer.writeAll(".{ ");256 switch (len) {
252257 0 => try writer.writeAll(".{}"),
253 const max_len = @min(len, max_aggregate_items);258 1 => {
254 for (0..max_len) |i| {259 try writer.writeAll(".{");
255 if (i != 0) try writer.writeAll(", ");260 try print(try val.fieldValue(pt, 0), writer, level - 1, pt, opt_sema);
256 try print(try val.fieldValue(pt, i), writer, level - 1, pt, opt_sema);261 try writer.writeByte('}');
257 }262 },
258 if (len > max_aggregate_items) {263 else => {
259 try writer.writeAll(", ...");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 },
260 }275 }
261 return writer.writeAll(" }");
262}276}
263277
264fn printPtr(278fn printPtr(
src/print_zir.zig+15-11
...@@ -1439,10 +1439,10 @@ const Writer = struct {...@@ -1439,10 +1439,10 @@ const Writer = struct {
14391439
1440 try stream.print("{s}, ", .{@tagName(struct_decl.name_strategy)});1440 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| {
1443 assert(struct_decl.layout == .@"packed");1443 assert(struct_decl.layout == .@"packed");
1444 try stream.writeAll("packed(");1444 try stream.writeAll("packed(");
1445 try self.writeInstRef(stream, struct_decl.backing_int_type);1445 try self.writeBracedDecl(stream, backing_int_type_body);
1446 try stream.writeAll("), ");1446 try stream.writeAll("), ");
1447 } else {1447 } else {
1448 try stream.print("{s}, ", .{@tagName(struct_decl.layout)});1448 try stream.print("{s}, ", .{@tagName(struct_decl.layout)});
...@@ -1507,18 +1507,18 @@ const Writer = struct {...@@ -1507,18 +1507,18 @@ const Writer = struct {
1507 .@"packed" => try stream.writeAll("packed, "),1507 .@"packed" => try stream.writeAll("packed, "),
1508 .packed_explicit => {1508 .packed_explicit => {
1509 try stream.writeAll("packed(");1509 try stream.writeAll("packed(");
1510 try self.writeInstRef(stream, union_decl.arg_type);1510 try self.writeBracedDecl(stream, union_decl.arg_type_body.?);
1511 try stream.writeAll("), ");1511 try stream.writeAll("), ");
1512 },1512 },
1513 .tagged_explicit => {1513 .tagged_explicit => {
1514 try stream.writeAll("auto(");1514 try stream.writeAll("tagged(");
1515 try self.writeInstRef(stream, union_decl.arg_type);1515 try self.writeBracedDecl(stream, union_decl.arg_type_body.?);
1516 try stream.writeAll("), ");1516 try stream.writeAll("), ");
1517 },1517 },
1518 .tagged_enum => try stream.writeAll("auto(enum)"),1518 .tagged_enum => try stream.writeAll("tagged(enum), "),
1519 .tagged_enum_explicit => {1519 .tagged_enum_explicit => {
1520 try stream.writeAll("auto(enum(");1520 try stream.writeAll("tagged(enum(");
1521 try self.writeInstRef(stream, union_decl.arg_type);1521 try self.writeBracedDecl(stream, union_decl.arg_type_body.?);
1522 try stream.writeAll(")), ");1522 try stream.writeAll(")), ");
1523 },1523 },
1524 }1524 }
...@@ -1577,7 +1577,11 @@ const Writer = struct {...@@ -1577,7 +1577,11 @@ const Writer = struct {
15771577
1578 try stream.print("{s}, ", .{@tagName(enum_decl.name_strategy)});1578 try stream.print("{s}, ", .{@tagName(enum_decl.name_strategy)});
1579 try self.writeFlag(stream, "nonexhaustive, ", enum_decl.nonexhaustive);1579 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
1582 try self.writeCaptures(stream, enum_decl.captures, enum_decl.capture_names);1586 try self.writeCaptures(stream, enum_decl.captures, enum_decl.capture_names);
1583 try stream.writeAll(", ");1587 try stream.writeAll(", ");
...@@ -1585,9 +1589,9 @@ const Writer = struct {...@@ -1585,9 +1589,9 @@ const Writer = struct {
1585 try stream.writeAll(", ");1589 try stream.writeAll(", ");
15861590
1587 if (enum_decl.field_names.len == 0) {1591 if (enum_decl.field_names.len == 0) {
1588 try stream.writeAll(", {}) ");1592 try stream.writeAll("{}) ");
1589 } else {1593 } else {
1590 try stream.writeAll(", {\n");1594 try stream.writeAll("{\n");
1591 self.indent += 2;1595 self.indent += 2;
15921596
1593 var it = enum_decl.iterateFields();1597 var it = enum_decl.iterateFields();