| author | |
| committer | |
| log | 3086c7977bee8cfe41c385d3ba389971b9a28380 |
| tree | f44098abd363cdb96722c1887e69c5d1033658e2 |
| parent | 6e49697ef576e86799c8365492082fdee9d216a9 |
| signature |
27 files changed, 3033 insertions(+), 2957 deletions(-)
lib/std/zig.zig+9| ... | ... | @@ -837,6 +837,10 @@ pub const SimpleComptimeReason = enum(u32) { |
| 837 | 837 | tuple_field_types, |
| 838 | 838 | enum_field_names, |
| 839 | 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, | |
| 840 | 844 | |
| 841 | 845 | // Evaluating at comptime because decl/field name must be comptime-known. |
| 842 | 846 | decl_name, |
| ... | ... | @@ -925,6 +929,11 @@ pub const SimpleComptimeReason = enum(u32) { |
| 925 | 929 | .enum_field_names => "enum field names must be comptime-known", |
| 926 | 930 | .enum_field_values => "enum field values must be comptime-known", |
| 927 | 931 | |
| 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 | 937 | .decl_name => "declaration name must be comptime-known", |
| 929 | 938 | .field_name => "field name must be comptime-known", |
| 930 | 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 | 4922 | |
| 4923 | 4923 | astgen.advanceSourceCursorToNode(node); |
| 4924 | 4924 | |
| 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 | 4925 | const decl_inst = try gz.reserveInstructionIndex(); |
| 4936 | 4926 | |
| 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 | 4928 | try gz.setStruct(decl_inst, .{ |
| 4939 | 4929 | .src_node = node, |
| 4940 | 4930 | .name_strat = name_strat, |
| 4941 | 4931 | .layout = layout, |
| 4942 | .backing_int_type = .none, | |
| 4932 | .backing_int_type_body_len = null, | |
| 4943 | 4933 | .decls_len = 0, |
| 4944 | 4934 | .fields_len = 0, |
| 4945 | 4935 | .any_field_aligns = false, |
| ... | ... | @@ -4993,6 +4983,22 @@ fn structDeclInner( |
| 4993 | 4983 | ); |
| 4994 | 4984 | if (field_comptime_bits) |bits| @memset(bits.get(astgen), 0); |
| 4995 | 4985 | |
| 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 | 5002 | const old_hasher = astgen.src_hasher; |
| 4997 | 5003 | defer astgen.src_hasher = old_hasher; |
| 4998 | 5004 | astgen.src_hasher = .init(.{}); |
| ... | ... | @@ -5076,7 +5082,7 @@ fn structDeclInner( |
| 5076 | 5082 | .src_node = node, |
| 5077 | 5083 | .name_strat = name_strat, |
| 5078 | 5084 | .layout = layout, |
| 5079 | .backing_int_type = backing_int_type_ref, | |
| 5085 | .backing_int_type_body_len = backing_int_type_body_len, | |
| 5080 | 5086 | .decls_len = scan_result.decls_len, |
| 5081 | 5087 | .fields_len = scan_result.fields_len, |
| 5082 | 5088 | .any_field_aligns = scan_result.any_field_aligns, |
| ... | ... | @@ -5220,11 +5226,6 @@ fn unionDeclInner( |
| 5220 | 5226 | |
| 5221 | 5227 | astgen.advanceSourceCursorToNode(node); |
| 5222 | 5228 | |
| 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 | 5229 | const decl_inst = try gz.reserveInstructionIndex(); |
| 5229 | 5230 | |
| 5230 | 5231 | var namespace: Scope.Namespace = .{ |
| ... | ... | @@ -5262,6 +5263,17 @@ fn unionDeclInner( |
| 5262 | 5263 | const field_align_body_lens = try scratch.addOptionalSlice(scan_result.any_field_aligns, scan_result.fields_len); |
| 5263 | 5264 | const field_value_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, scan_result.fields_len); |
| 5264 | 5265 | |
| 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 | 5277 | const old_hasher = astgen.src_hasher; |
| 5266 | 5278 | defer astgen.src_hasher = old_hasher; |
| 5267 | 5279 | astgen.src_hasher = .init(.{}); |
| ... | ... | @@ -5358,7 +5370,7 @@ fn unionDeclInner( |
| 5358 | 5370 | .@"extern" => .@"extern", |
| 5359 | 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 | 5374 | .decls_len = scan_result.decls_len, |
| 5363 | 5375 | .fields_len = scan_result.fields_len, |
| 5364 | 5376 | .any_field_aligns = scan_result.any_field_aligns, |
| ... | ... | @@ -5420,11 +5432,6 @@ fn containerDecl( |
| 5420 | 5432 | |
| 5421 | 5433 | astgen.advanceSourceCursorToNode(node); |
| 5422 | 5434 | |
| 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 | 5435 | const decl_inst = try gz.reserveInstructionIndex(); |
| 5429 | 5436 | |
| 5430 | 5437 | var namespace: Scope.Namespace = .{ |
| ... | ... | @@ -5461,6 +5468,17 @@ fn containerDecl( |
| 5461 | 5468 | const field_names = try scratch.addSlice(fields_len); |
| 5462 | 5469 | const field_value_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, fields_len); |
| 5463 | 5470 | |
| 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 | 5482 | const old_hasher = astgen.src_hasher; |
| 5465 | 5483 | defer astgen.src_hasher = old_hasher; |
| 5466 | 5484 | astgen.src_hasher = .init(.{}); |
| ... | ... | @@ -5508,7 +5526,7 @@ fn containerDecl( |
| 5508 | 5526 | field_names.get(astgen)[field_idx] = @intFromEnum(try astgen.identAsString(member.ast.main_token)); |
| 5509 | 5527 | |
| 5510 | 5528 | if (member.ast.value_expr.unwrap()) |value_node| { |
| 5511 | if (tag_type_ref == .none) { | |
| 5529 | if (tag_type_body_len == null) { | |
| 5512 | 5530 | return astgen.failNodeNotes(node, "explicitly valued enum missing integer tag type", .{}, &.{ |
| 5513 | 5531 | try astgen.errNoteNode(value_node, "tag value specified here", .{}), |
| 5514 | 5532 | }); |
| ... | ... | @@ -5535,7 +5553,7 @@ fn containerDecl( |
| 5535 | 5553 | try gz.setEnum(decl_inst, .{ |
| 5536 | 5554 | .src_node = node, |
| 5537 | 5555 | .name_strat = name_strat, |
| 5538 | .tag_type = tag_type_ref, | |
| 5556 | .tag_type_body_len = tag_type_body_len, | |
| 5539 | 5557 | .nonexhaustive = scan_result.has_underscore_field, |
| 5540 | 5558 | .decls_len = scan_result.decls_len, |
| 5541 | 5559 | .fields_len = fields_len, |
| ... | ... | @@ -12406,7 +12424,7 @@ const GenZir = struct { |
| 12406 | 12424 | src_node: Ast.Node.Index, |
| 12407 | 12425 | name_strat: Zir.Inst.NameStrategy, |
| 12408 | 12426 | layout: std.builtin.Type.ContainerLayout, |
| 12409 | backing_int_type: Zir.Inst.Ref, | |
| 12427 | backing_int_type_body_len: ?u32, | |
| 12410 | 12428 | decls_len: u32, |
| 12411 | 12429 | fields_len: u32, |
| 12412 | 12430 | any_field_aligns: bool, |
| ... | ... | @@ -12430,7 +12448,7 @@ const GenZir = struct { |
| 12430 | 12448 | const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash); |
| 12431 | 12449 | |
| 12432 | 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 | 12452 | captures_len * 2 + // `capture`, `capture_name` |
| 12435 | 12453 | args.remaining.len); |
| 12436 | 12454 | |
| ... | ... | @@ -12446,7 +12464,7 @@ const GenZir = struct { |
| 12446 | 12464 | if (captures_len != 0) astgen.extra.appendAssumeCapacity(captures_len); |
| 12447 | 12465 | if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len); |
| 12448 | 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 | 12468 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures)); |
| 12451 | 12469 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names)); |
| 12452 | 12470 | astgen.extra.appendSliceAssumeCapacity(args.remaining); |
| ... | ... | @@ -12461,7 +12479,7 @@ const GenZir = struct { |
| 12461 | 12479 | .has_fields_len = args.fields_len != 0, |
| 12462 | 12480 | .name_strategy = args.name_strat, |
| 12463 | 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 | 12483 | .any_field_aligns = args.any_field_aligns, |
| 12466 | 12484 | .any_field_defaults = args.any_field_defaults, |
| 12467 | 12485 | .any_comptime_fields = args.any_comptime_fields, |
| ... | ... | @@ -12475,7 +12493,7 @@ const GenZir = struct { |
| 12475 | 12493 | src_node: Ast.Node.Index, |
| 12476 | 12494 | name_strat: Zir.Inst.NameStrategy, |
| 12477 | 12495 | kind: Zir.Inst.UnionDecl.Kind, |
| 12478 | arg_type: Zir.Inst.Ref, | |
| 12496 | arg_type_body_len: ?u32, | |
| 12479 | 12497 | decls_len: u32, |
| 12480 | 12498 | fields_len: u32, |
| 12481 | 12499 | any_field_aligns: bool, |
| ... | ... | @@ -12497,7 +12515,7 @@ const GenZir = struct { |
| 12497 | 12515 | const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash); |
| 12498 | 12516 | |
| 12499 | 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 | 12519 | captures_len * 2 + // `capture`, `capture_name` |
| 12502 | 12520 | args.remaining.len); |
| 12503 | 12521 | |
| ... | ... | @@ -12514,10 +12532,9 @@ const GenZir = struct { |
| 12514 | 12532 | if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len); |
| 12515 | 12533 | if (args.fields_len != 0) astgen.extra.appendAssumeCapacity(args.fields_len); |
| 12516 | 12534 | if (args.kind.hasArgType()) { |
| 12517 | assert(args.arg_type != .none); | |
| 12518 | astgen.extra.appendAssumeCapacity(@intFromEnum(args.arg_type)); | |
| 12535 | astgen.extra.appendAssumeCapacity(args.arg_type_body_len.?); | |
| 12519 | 12536 | } else { |
| 12520 | assert(args.arg_type == .none); | |
| 12537 | assert(args.arg_type_body_len == null); | |
| 12521 | 12538 | } |
| 12522 | 12539 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures)); |
| 12523 | 12540 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names)); |
| ... | ... | @@ -12525,28 +12542,26 @@ const GenZir = struct { |
| 12525 | 12542 | |
| 12526 | 12543 | astgen.instructions.set(@intFromEnum(inst), .{ |
| 12527 | 12544 | .tag = .extended, |
| 12528 | .data = .{ | |
| 12529 | .extended = .{ | |
| 12530 | .opcode = .union_decl, | |
| 12531 | .small = @bitCast(Zir.Inst.UnionDecl.Small{ | |
| 12532 | .has_captures_len = captures_len != 0, | |
| 12533 | .has_decls_len = args.decls_len != 0, | |
| 12534 | .has_fields_len = args.fields_len != 0, | |
| 12535 | .name_strategy = args.name_strat, | |
| 12536 | .kind = args.kind, | |
| 12537 | .any_field_aligns = args.any_field_aligns, | |
| 12538 | .any_field_values = args.any_field_values, | |
| 12539 | }), | |
| 12540 | .operand = payload_index, | |
| 12541 | }, | |
| 12542 | }, | |
| 12545 | .data = .{ .extended = .{ | |
| 12546 | .opcode = .union_decl, | |
| 12547 | .small = @bitCast(Zir.Inst.UnionDecl.Small{ | |
| 12548 | .has_captures_len = captures_len != 0, | |
| 12549 | .has_decls_len = args.decls_len != 0, | |
| 12550 | .has_fields_len = args.fields_len != 0, | |
| 12551 | .name_strategy = args.name_strat, | |
| 12552 | .kind = args.kind, | |
| 12553 | .any_field_aligns = args.any_field_aligns, | |
| 12554 | .any_field_values = args.any_field_values, | |
| 12555 | }), | |
| 12556 | .operand = payload_index, | |
| 12557 | } }, | |
| 12543 | 12558 | }); |
| 12544 | 12559 | } |
| 12545 | 12560 | |
| 12546 | 12561 | fn setEnum(gz: *GenZir, inst: Zir.Inst.Index, args: struct { |
| 12547 | 12562 | src_node: Ast.Node.Index, |
| 12548 | 12563 | name_strat: Zir.Inst.NameStrategy, |
| 12549 | tag_type: Zir.Inst.Ref, | |
| 12564 | tag_type_body_len: ?u32, | |
| 12550 | 12565 | nonexhaustive: bool, |
| 12551 | 12566 | decls_len: u32, |
| 12552 | 12567 | fields_len: u32, |
| ... | ... | @@ -12568,7 +12583,7 @@ const GenZir = struct { |
| 12568 | 12583 | const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash); |
| 12569 | 12584 | |
| 12570 | 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 | 12587 | captures_len * 2 + // `capture`, `capture_name` |
| 12573 | 12588 | args.remaining.len); |
| 12574 | 12589 | |
| ... | ... | @@ -12584,7 +12599,7 @@ const GenZir = struct { |
| 12584 | 12599 | if (captures_len != 0) astgen.extra.appendAssumeCapacity(captures_len); |
| 12585 | 12600 | if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len); |
| 12586 | 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 | 12603 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures)); |
| 12589 | 12604 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names)); |
| 12590 | 12605 | astgen.extra.appendSliceAssumeCapacity(args.remaining); |
| ... | ... | @@ -12598,7 +12613,7 @@ const GenZir = struct { |
| 12598 | 12613 | .has_decls_len = args.decls_len != 0, |
| 12599 | 12614 | .has_fields_len = args.fields_len != 0, |
| 12600 | 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 | 12617 | .nonexhaustive = args.nonexhaustive, |
| 12603 | 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 | 3465 | /// 0. captures_len: u32 // if `has_captures_len` |
| 3466 | 3466 | /// 1. decls_len: u32, // if `has_decls_len` |
| 3467 | 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 | 3469 | /// 4. capture: Capture // for every `captures_len` |
| 3470 | 3470 | /// 5. capture_name: NullTerminatedString // for every `captures_len` |
| 3471 | 3471 | /// 6. decl: Index, // for every `decls_len`; points to a `declaration` instruction |
| ... | ... | @@ -3475,7 +3475,8 @@ pub const Inst = struct { |
| 3475 | 3475 | /// 10. field_default_body_len: u32 // for every `fields_len` if `any_field_defaults` |
| 3476 | 3476 | /// 11. field_comptime_bits: u32 // one bit per `fields_len` if `any_comptime_fields` |
| 3477 | 3477 | /// // LSB is first field, minimum number of `u32` needed |
| 3478 | /// 12. body_inst: Inst.Index // type body, then align body, then default body, for each field | |
| 3478 | /// 12. backing_int_body_inst: Inst.Index // for each `backing_int_body_len` | |
| 3479 | /// 13. body_inst: Inst.Index // type body, then align body, then default body, for each field | |
| 3479 | 3480 | pub const StructDecl = struct { |
| 3480 | 3481 | // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`. |
| 3481 | 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 | 3623 | /// 0. captures_len: u32, // if has_captures_len |
| 3623 | 3624 | /// 1. decls_len: u32, // if has_decls_len |
| 3624 | 3625 | /// 2. fields_len: u32, // if has_fields_len |
| 3625 | /// 3. tag_type: Ref, // if has_tag_type | |
| 3626 | /// 3. tag_type_body_len: u32, // if has_tag_type | |
| 3626 | 3627 | /// 4. capture: Capture // for every `captures_len` |
| 3627 | 3628 | /// 5. capture_name: NullTerminatedString // for every `captures_len` |
| 3628 | 3629 | /// 6. decl: Index, // for every `decls_len`; points to a `declaration` instruction |
| 3629 | 3630 | /// 7. field_name: NullTerminatedString // for every `fields_len` |
| 3630 | 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 field | |
| 3632 | /// 9. tag_type_body_inst: Inst.Index // for each `tag_type_body_len` | |
| 3633 | /// 10. body_inst: Inst.Index // value body for each field | |
| 3632 | 3634 | pub const EnumDecl = struct { |
| 3633 | 3635 | // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`. |
| 3634 | 3636 | // This hash contains the source of all fields, and the backing type if specified. |
| ... | ... | @@ -3656,7 +3658,7 @@ pub const Inst = struct { |
| 3656 | 3658 | /// 0. captures_len: u32 // if `has_captures_len` |
| 3657 | 3659 | /// 1. decls_len: u32, // if `has_decls_len` |
| 3658 | 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 | 3662 | /// 4. capture: Capture // for every `captures_len` |
| 3661 | 3663 | /// 5. capture_name: NullTerminatedString // for every `captures_len` |
| 3662 | 3664 | /// 6. decl: Index, // for every `decls_len`; points to a `declaration` instruction |
| ... | ... | @@ -3664,7 +3666,8 @@ pub const Inst = struct { |
| 3664 | 3666 | /// 8. field_type_body_len: u32 // for every `fields_len` |
| 3665 | 3667 | /// 9 . field_align_body_len: u32 // for every `fields_len` if `any_field_aligns` |
| 3666 | 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 field | |
| 3669 | /// 11. arg_type_body_inst: Inst.Index // for each `arg_type_body_len` | |
| 3670 | /// 12. body_inst: Inst.Index // type body, then align body, then value body, for each field | |
| 3668 | 3671 | pub const UnionDecl = struct { |
| 3669 | 3672 | // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`. |
| 3670 | 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 | 5238 | } |
| 5236 | 5239 | } |
| 5237 | 5240 | |
| 5238 | /// MLUGG TODO: maybe delete these two? | |
| 5239 | pub 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 | } | |
| 5250 | 5241 | pub fn typeDecls(zir: Zir, type_decl: Inst.Index) []const Zir.Inst.Index { |
| 5251 | 5242 | const inst = zir.instructions.get(@intFromEnum(type_decl)); |
| 5252 | 5243 | assert(inst.tag == .extended); |
| ... | ... | @@ -5281,11 +5272,11 @@ pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDe |
| 5281 | 5272 | extra_index += 1; |
| 5282 | 5273 | break :blk fields_len; |
| 5283 | 5274 | } else 0; |
| 5284 | const backing_int_type: Inst.Ref = if (small.has_backing_int_type) ty: { | |
| 5285 | const ty = zir.extra[extra_index]; | |
| 5275 | const backing_int_type_body_len: u32 = if (small.has_backing_int_type) len: { | |
| 5276 | const body_len = zir.extra[extra_index]; | |
| 5286 | 5277 | extra_index += 1; |
| 5287 | break :ty @enumFromInt(ty); | |
| 5288 | } else .none; | |
| 5278 | break :len body_len; | |
| 5279 | } else 0; | |
| 5289 | 5280 | const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]); |
| 5290 | 5281 | extra_index += captures_len; |
| 5291 | 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 | 5303 | extra_index += bits_len; |
| 5313 | 5304 | break :bits bits; |
| 5314 | 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 | 5311 | const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]); |
| 5316 | 5312 | return .{ |
| 5317 | 5313 | .src_line = extra.data.src_line, |
| ... | ... | @@ -5321,7 +5317,7 @@ pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDe |
| 5321 | 5317 | .capture_names = capture_names, |
| 5322 | 5318 | .decls = decls, |
| 5323 | 5319 | .layout = small.layout, |
| 5324 | .backing_int_type = backing_int_type, | |
| 5320 | .backing_int_type_body = backing_int_type_body, | |
| 5325 | 5321 | .field_names = field_names, |
| 5326 | 5322 | .field_type_body_lens = field_type_body_lens, |
| 5327 | 5323 | .field_align_body_lens = field_align_body_lens, |
| ... | ... | @@ -5341,7 +5337,7 @@ pub const UnwrappedStructDecl = struct { |
| 5341 | 5337 | decls: []const Inst.Index, |
| 5342 | 5338 | |
| 5343 | 5339 | layout: std.builtin.Type.ContainerLayout, |
| 5344 | backing_int_type: Inst.Ref, | |
| 5340 | backing_int_type_body: ?[]const Inst.Index, | |
| 5345 | 5341 | |
| 5346 | 5342 | field_names: []const NullTerminatedString, |
| 5347 | 5343 | field_type_body_lens: []const u32, |
| ... | ... | @@ -5427,11 +5423,11 @@ pub fn getUnionDecl(zir: *const Zir, union_decl: Inst.Index) UnwrappedUnionDecl |
| 5427 | 5423 | extra_index += 1; |
| 5428 | 5424 | break :blk fields_len; |
| 5429 | 5425 | } else 0; |
| 5430 | const arg_type: Inst.Ref = if (small.kind.hasArgType()) ty: { | |
| 5431 | const ty = zir.extra[extra_index]; | |
| 5426 | const arg_type_body_len: u32 = if (small.kind.hasArgType()) len: { | |
| 5427 | const body_len = zir.extra[extra_index]; | |
| 5432 | 5428 | extra_index += 1; |
| 5433 | break :ty @enumFromInt(ty); | |
| 5434 | } else .none; | |
| 5429 | break :len body_len; | |
| 5430 | } else 0; | |
| 5435 | 5431 | const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]); |
| 5436 | 5432 | extra_index += captures_len; |
| 5437 | 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 | 5448 | extra_index += fields_len; |
| 5453 | 5449 | break :lens @ptrCast(lens); |
| 5454 | 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 | 5456 | const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]); |
| 5456 | 5457 | return .{ |
| 5457 | 5458 | .src_line = extra.data.src_line, |
| ... | ... | @@ -5461,7 +5462,7 @@ pub fn getUnionDecl(zir: *const Zir, union_decl: Inst.Index) UnwrappedUnionDecl |
| 5461 | 5462 | .capture_names = capture_names, |
| 5462 | 5463 | .decls = decls, |
| 5463 | 5464 | .kind = small.kind, |
| 5464 | .arg_type = arg_type, | |
| 5465 | .arg_type_body = arg_type_body, | |
| 5465 | 5466 | .field_names = field_names, |
| 5466 | 5467 | .field_type_body_lens = field_type_body_lens, |
| 5467 | 5468 | .field_align_body_lens = field_align_body_lens, |
| ... | ... | @@ -5480,7 +5481,7 @@ pub const UnwrappedUnionDecl = struct { |
| 5480 | 5481 | decls: []const Inst.Index, |
| 5481 | 5482 | |
| 5482 | 5483 | kind: Inst.UnionDecl.Kind, |
| 5483 | arg_type: Inst.Ref, | |
| 5484 | arg_type_body: ?[]const Inst.Index, | |
| 5484 | 5485 | |
| 5485 | 5486 | field_names: []const NullTerminatedString, |
| 5486 | 5487 | field_type_body_lens: []const u32, |
| ... | ... | @@ -5556,11 +5557,11 @@ pub fn getEnumDecl(zir: *const Zir, enum_decl: Inst.Index) UnwrappedEnumDecl { |
| 5556 | 5557 | extra_index += 1; |
| 5557 | 5558 | break :blk fields_len; |
| 5558 | 5559 | } else 0; |
| 5559 | const tag_type: Inst.Ref = if (small.has_tag_type) ty: { | |
| 5560 | const ty = zir.extra[extra_index]; | |
| 5560 | const tag_type_body_len: u32 = if (small.has_tag_type) len: { | |
| 5561 | const body_len = zir.extra[extra_index]; | |
| 5561 | 5562 | extra_index += 1; |
| 5562 | break :ty @enumFromInt(ty); | |
| 5563 | } else .none; | |
| 5563 | break :len body_len; | |
| 5564 | } else 0; | |
| 5564 | 5565 | const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]); |
| 5565 | 5566 | extra_index += captures_len; |
| 5566 | 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 | 5575 | extra_index += fields_len; |
| 5575 | 5576 | break :lens @ptrCast(lens); |
| 5576 | 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 | 5583 | const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]); |
| 5578 | 5584 | return .{ |
| 5579 | 5585 | .src_line = extra.data.src_line, |
| ... | ... | @@ -5582,7 +5588,7 @@ pub fn getEnumDecl(zir: *const Zir, enum_decl: Inst.Index) UnwrappedEnumDecl { |
| 5582 | 5588 | .captures = captures, |
| 5583 | 5589 | .capture_names = capture_names, |
| 5584 | 5590 | .decls = decls, |
| 5585 | .tag_type = tag_type, | |
| 5591 | .tag_type_body = tag_type_body, | |
| 5586 | 5592 | .nonexhaustive = small.nonexhaustive, |
| 5587 | 5593 | .field_names = field_names, |
| 5588 | 5594 | .field_value_body_lens = field_value_body_lens, |
| ... | ... | @@ -5599,7 +5605,7 @@ pub const UnwrappedEnumDecl = struct { |
| 5599 | 5605 | |
| 5600 | 5606 | decls: []const Inst.Index, |
| 5601 | 5607 | |
| 5602 | tag_type: Inst.Ref, | |
| 5608 | tag_type_body: ?[]const Inst.Index, | |
| 5603 | 5609 | nonexhaustive: bool, |
| 5604 | 5610 | |
| 5605 | 5611 | field_names: []const NullTerminatedString, |
src/Compilation.zig+6-6| ... | ... | @@ -3713,7 +3713,7 @@ const Header = extern struct { |
| 3713 | 3713 | nav_val_deps_len: u32, |
| 3714 | 3714 | nav_ty_deps_len: u32, |
| 3715 | 3715 | type_layout_deps_len: u32, |
| 3716 | type_inits_deps_len: u32, | |
| 3716 | struct_defaults_deps_len: u32, | |
| 3717 | 3717 | func_ies_deps_len: u32, |
| 3718 | 3718 | zon_file_deps_len: u32, |
| 3719 | 3719 | embed_file_deps_len: u32, |
| ... | ... | @@ -3763,7 +3763,7 @@ pub fn saveState(comp: *Compilation) !void { |
| 3763 | 3763 | .nav_val_deps_len = @intCast(ip.nav_val_deps.count()), |
| 3764 | 3764 | .nav_ty_deps_len = @intCast(ip.nav_ty_deps.count()), |
| 3765 | 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 | 3767 | .func_ies_deps_len = @intCast(ip.func_ies_deps.count()), |
| 3768 | 3768 | .zon_file_deps_len = @intCast(ip.zon_file_deps.count()), |
| 3769 | 3769 | .embed_file_deps_len = @intCast(ip.embed_file_deps.count()), |
| ... | ... | @@ -3800,8 +3800,8 @@ pub fn saveState(comp: *Compilation) !void { |
| 3800 | 3800 | addBuf(&bufs, @ptrCast(ip.nav_ty_deps.values())); |
| 3801 | 3801 | addBuf(&bufs, @ptrCast(ip.type_layout_deps.keys())); |
| 3802 | 3802 | addBuf(&bufs, @ptrCast(ip.type_layout_deps.values())); |
| 3803 | addBuf(&bufs, @ptrCast(ip.type_inits_deps.keys())); | |
| 3804 | addBuf(&bufs, @ptrCast(ip.type_inits_deps.values())); | |
| 3803 | addBuf(&bufs, @ptrCast(ip.struct_defaults_deps.keys())); | |
| 3804 | addBuf(&bufs, @ptrCast(ip.struct_defaults_deps.values())); | |
| 3805 | 3805 | addBuf(&bufs, @ptrCast(ip.func_ies_deps.keys())); |
| 3806 | 3806 | addBuf(&bufs, @ptrCast(ip.func_ies_deps.values())); |
| 3807 | 3807 | addBuf(&bufs, @ptrCast(ip.zon_file_deps.keys())); |
| ... | ... | @@ -4481,7 +4481,7 @@ pub fn addModuleErrorMsg( |
| 4481 | 4481 | const root_name: ?[]const u8 = switch (ref.referencer.unwrap()) { |
| 4482 | 4482 | .@"comptime" => "comptime", |
| 4483 | 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 | 4485 | .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip), |
| 4486 | 4486 | .memoized_state => null, |
| 4487 | 4487 | }; |
| ... | ... | @@ -5251,7 +5251,7 @@ fn processOneJob(tid: Zcu.PerThread.Id, comp: *Compilation, job: Job) JobError!v |
| 5251 | 5251 | .nav_ty => |nav| pt.ensureNavTypeUpToDate(nav), |
| 5252 | 5252 | .nav_val => |nav| pt.ensureNavValUpToDate(nav), |
| 5253 | 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 | 5255 | .memoized_state => |stage| pt.ensureMemoizedStateUpToDate(stage), |
| 5256 | 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 | 307 | switch (dependee) { |
| 308 | 308 | .src_hash, .namespace, .namespace_name, .zon_file, .embed_file => try w.print("{f}", .{zcu.fmtDependee(dependee)}), |
| 309 | 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 | 311 | .memoized_state => |stage| try w.print("memoized_state {s}", .{@tagName(stage)}), |
| 312 | 312 | } |
| 313 | 313 | try w.writeByte('\n'); |
| ... | ... | @@ -374,8 +374,8 @@ fn parseAnalUnit(str: []const u8) ?AnalUnit { |
| 374 | 374 | return .wrap(.{ .nav_ty = @enumFromInt(parseIndex(idx_str) orelse return null) }); |
| 375 | 375 | } else if (std.mem.eql(u8, kind, "type_layout")) { |
| 376 | 376 | return .wrap(.{ .type_layout = @enumFromInt(parseIndex(idx_str) orelse return null) }); |
| 377 | } else if (std.mem.eql(u8, kind, "type_inits")) { | |
| 378 | return .wrap(.{ .type_inits = @enumFromInt(parseIndex(idx_str) orelse return null) }); | |
| 377 | } else if (std.mem.eql(u8, kind, "struct_defaults")) { | |
| 378 | return .wrap(.{ .struct_defaults = @enumFromInt(parseIndex(idx_str) orelse return null) }); | |
| 379 | 379 | } else if (std.mem.eql(u8, kind, "func")) { |
| 380 | 380 | return .wrap(.{ .func = @enumFromInt(parseIndex(idx_str) orelse return null) }); |
| 381 | 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 | 50 | /// Dependencies on a function's inferred error set. Key is the function body, not the IES. |
| 51 | 51 | /// Value is index into `dep_entries` of the first dependency on this function's IES. |
| 52 | 52 | func_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 | 54 | /// Value is index into `dep_entries` of the first dependency on this type's layout. |
| 55 | 55 | type_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 | 57 | /// Value is index into `dep_entries` of the first dependency on this type's inits. |
| 58 | type_inits_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index), | |
| 58 | struct_defaults_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index), | |
| 59 | 59 | /// Dependencies on a ZON file. Triggered by `@import` of ZON. |
| 60 | 60 | /// Value is index into `dep_entries` of the first dependency on this ZON file. |
| 61 | 61 | zon_file_deps: std.AutoArrayHashMapUnmanaged(FileIndex, DepEntry.Index), |
| ... | ... | @@ -110,7 +110,7 @@ pub const empty: InternPool = .{ |
| 110 | 110 | .nav_ty_deps = .empty, |
| 111 | 111 | .func_ies_deps = .empty, |
| 112 | 112 | .type_layout_deps = .empty, |
| 113 | .type_inits_deps = .empty, | |
| 113 | .struct_defaults_deps = .empty, | |
| 114 | 114 | .zon_file_deps = .empty, |
| 115 | 115 | .embed_file_deps = .empty, |
| 116 | 116 | .namespace_deps = .empty, |
| ... | ... | @@ -422,7 +422,7 @@ pub const AnalUnit = packed struct(u64) { |
| 422 | 422 | nav_val, |
| 423 | 423 | nav_ty, |
| 424 | 424 | type_layout, |
| 425 | type_inits, | |
| 425 | struct_defaults, | |
| 426 | 426 | func, |
| 427 | 427 | memoized_state, |
| 428 | 428 | }; |
| ... | ... | @@ -434,11 +434,10 @@ pub const AnalUnit = packed struct(u64) { |
| 434 | 434 | nav_val: Nav.Index, |
| 435 | 435 | /// This `AnalUnit` resolves the type of the given `Nav`. |
| 436 | 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 | 438 | type_layout: InternPool.Index, |
| 439 | /// This `AnalUnit` resolves the field inits of the given `struct` or `enum` type. | |
| 440 | /// The type may be a union's auto-generated tag enum, if the union has explicit field values. | |
| 441 | type_inits: InternPool.Index, | |
| 439 | /// This `AnalUnit` resolves the default field values of the given `struct` type. | |
| 440 | struct_defaults: InternPool.Index, | |
| 442 | 441 | /// This `AnalUnit` analyzes the body of the given runtime function. |
| 443 | 442 | func: InternPool.Index, |
| 444 | 443 | /// This `AnalUnit` resolves all state which is memoized in fields on `Zcu`. |
| ... | ... | @@ -852,7 +851,7 @@ pub const Dependee = union(enum) { |
| 852 | 851 | /// Index is the function, not its IES. |
| 853 | 852 | func_ies: Index, |
| 854 | 853 | type_layout: Index, |
| 855 | type_inits: Index, | |
| 854 | struct_defaults: Index, | |
| 856 | 855 | zon_file: FileIndex, |
| 857 | 856 | embed_file: Zcu.EmbedFile.Index, |
| 858 | 857 | namespace: TrackedInst.Index, |
| ... | ... | @@ -906,7 +905,7 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI |
| 906 | 905 | .nav_ty => |x| ip.nav_ty_deps.get(x), |
| 907 | 906 | .func_ies => |x| ip.func_ies_deps.get(x), |
| 908 | 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 | 909 | .zon_file => |x| ip.zon_file_deps.get(x), |
| 911 | 910 | .embed_file => |x| ip.embed_file_deps.get(x), |
| 912 | 911 | .namespace => |x| ip.namespace_deps.get(x), |
| ... | ... | @@ -981,7 +980,7 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend |
| 981 | 980 | .nav_ty => ip.nav_ty_deps, |
| 982 | 981 | .func_ies => ip.func_ies_deps, |
| 983 | 982 | .type_layout => ip.type_layout_deps, |
| 984 | .type_inits => ip.type_inits_deps, | |
| 983 | .struct_defaults => ip.struct_defaults_deps, | |
| 985 | 984 | .zon_file => ip.zon_file_deps, |
| 986 | 985 | .embed_file => ip.embed_file_deps, |
| 987 | 986 | .namespace => ip.namespace_deps, |
| ... | ... | @@ -2248,10 +2247,6 @@ pub const Key = union(enum) { |
| 2248 | 2247 | pub const Declared = struct { |
| 2249 | 2248 | /// A `struct_decl`, `union_decl`, `enum_decl`, or `opaque_decl` instruction. |
| 2250 | 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 | 2250 | /// The captured values of this type. These values must be fully resolved per the language spec. |
| 2256 | 2251 | captures: union(enum) { |
| 2257 | 2252 | owned: CaptureValue.Slice, |
| ... | ... | @@ -2745,7 +2740,6 @@ pub const Key = union(enum) { |
| 2745 | 2740 | switch (namespace_type) { |
| 2746 | 2741 | .declared => |declared| { |
| 2747 | 2742 | std.hash.autoHash(&hasher, declared.zir_index); |
| 2748 | std.hash.autoHash(&hasher, declared.arg_ty); | |
| 2749 | 2743 | const captures = switch (declared.captures) { |
| 2750 | 2744 | .owned => |cvs| cvs.get(ip), |
| 2751 | 2745 | .external => |cvs| cvs, |
| ... | ... | @@ -3155,7 +3149,6 @@ pub const Key = union(enum) { |
| 3155 | 3149 | .declared => |a_d| { |
| 3156 | 3150 | const b_d = b_info.declared; |
| 3157 | 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 | 3152 | const a_captures = switch (a_d.captures) { |
| 3160 | 3153 | .owned => |s| s.get(ip), |
| 3161 | 3154 | .external => |cvs| cvs, |
| ... | ... | @@ -3295,7 +3288,6 @@ pub const Key = union(enum) { |
| 3295 | 3288 | .void => .void_type, |
| 3296 | 3289 | .null => .null_type, |
| 3297 | 3290 | .false, .true => .bool_type, |
| 3298 | .empty_tuple => .empty_tuple_type, | |
| 3299 | 3291 | .@"unreachable" => .noreturn_type, |
| 3300 | 3292 | }, |
| 3301 | 3293 | |
| ... | ... | @@ -3308,6 +3300,7 @@ pub const LoadedStructType = struct { |
| 3308 | 3300 | /// Index of the `struct_decl` or `reify` ZIR instruction. |
| 3309 | 3301 | zir_index: TrackedInst.Index, |
| 3310 | 3302 | captures: CaptureValue.Slice, |
| 3303 | is_reified: bool, | |
| 3311 | 3304 | |
| 3312 | 3305 | // TODO: the non-fqn will be needed by the new dwarf structure |
| 3313 | 3306 | /// The name of this struct type. |
| ... | ... | @@ -3319,10 +3312,9 @@ pub const LoadedStructType = struct { |
| 3319 | 3312 | |
| 3320 | 3313 | layout: std.builtin.Type.ContainerLayout, |
| 3321 | 3314 | /// May be `undefined` if `layout != .@"packed"`. |
| 3322 | packed_backing_mode: PackedBackingMode, | |
| 3323 | /// May be `undefined` if `layout != .@"packed", | |
| 3324 | packed_backing_int_type: Index, | |
| 3315 | packed_backing_mode: BackingTypeMode, | |
| 3325 | 3316 | |
| 3317 | // The remaining fields are only valid once the struct's layout is resolved. | |
| 3326 | 3318 | field_name_map: MapIndex, |
| 3327 | 3319 | field_names: NullTerminatedString.Slice, |
| 3328 | 3320 | field_types: Index.Slice, |
| ... | ... | @@ -3331,11 +3323,11 @@ pub const LoadedStructType = struct { |
| 3331 | 3323 | field_is_comptime_bits: ComptimeBits, |
| 3332 | 3324 | field_runtime_order: RuntimeOrder.Slice, |
| 3333 | 3325 | field_offsets: Offsets, |
| 3334 | ||
| 3335 | // These fields are only valid once the layout is resolved, and are never valid for `layout == .@"packed"`. | |
| 3326 | packed_backing_int_type: Index, | |
| 3336 | 3327 | has_no_possible_value: bool, |
| 3337 | 3328 | has_one_possible_value: bool, |
| 3338 | 3329 | comptime_only: bool, |
| 3330 | has_runtime_bits: bool, | |
| 3339 | 3331 | size: u32, |
| 3340 | 3332 | alignment: Alignment, |
| 3341 | 3333 | |
| ... | ... | @@ -3478,6 +3470,7 @@ pub const LoadedUnionType = struct { |
| 3478 | 3470 | /// Index of the `union_decl` or `reify` ZIR instruction. |
| 3479 | 3471 | zir_index: TrackedInst.Index, |
| 3480 | 3472 | captures: CaptureValue.Slice, |
| 3473 | is_reified: bool, | |
| 3481 | 3474 | |
| 3482 | 3475 | // TODO: the non-fqn will be needed by the new dwarf structure |
| 3483 | 3476 | /// The name of this union type. |
| ... | ... | @@ -3488,23 +3481,26 @@ pub const LoadedUnionType = struct { |
| 3488 | 3481 | namespace: NamespaceIndex, |
| 3489 | 3482 | |
| 3490 | 3483 | layout: std.builtin.Type.ContainerLayout, |
| 3491 | runtime_tag: RuntimeTag, | |
| 3492 | /// Even if `runtime_tag == .none`, this is populated with the union's "hypothetical" tag type. | |
| 3493 | enum_tag_type: Index, | |
| 3484 | enum_tag_mode: BackingTypeMode, | |
| 3494 | 3485 | /// May be `undefined` if `layout != .@"packed"`. |
| 3495 | packed_backing_mode: PackedBackingMode, | |
| 3496 | /// May be `undefined` if `layout != .@"packed", | |
| 3497 | packed_backing_int_type: Index, | |
| 3486 | packed_backing_mode: BackingTypeMode, | |
| 3487 | ||
| 3488 | /// Only reified unions store field names; typically they should be loaded from `enum_tag_type` | |
| 3489 | /// instead. Reified unions store them because type resolution needs them in order to validate | |
| 3490 | /// or populate `enum_tag_type`. | |
| 3491 | reified_field_names: NullTerminatedString.Slice, | |
| 3498 | 3492 | |
| 3499 | // Field names are not stored here, because fields are guaranteed to map one-to-one to the | |
| 3500 | // fields of the enum tag type. If you need field names, load them from `enum_tag_type`. | |
| 3493 | // The remaining fields are only valid once the union's layout is resolved. | |
| 3501 | 3494 | field_types: Index.Slice, |
| 3502 | 3495 | field_aligns: Alignment.Slice, |
| 3503 | ||
| 3504 | // These fields are only valid once the layout is resolved, and are never valid for `layout == .@"packed"`. | |
| 3496 | runtime_tag: RuntimeTag, | |
| 3497 | /// Even if `runtime_tag == .none`, this is populated with the union's "hypothetical" tag type. | |
| 3498 | enum_tag_type: Index, | |
| 3499 | packed_backing_int_type: Index, | |
| 3505 | 3500 | has_no_possible_value: bool, |
| 3506 | 3501 | has_one_possible_value: bool, |
| 3507 | 3502 | comptime_only: bool, |
| 3503 | has_runtime_bits: bool, | |
| 3508 | 3504 | size: u32, |
| 3509 | 3505 | padding: u32, |
| 3510 | 3506 | alignment: Alignment, |
| ... | ... | @@ -3523,6 +3519,7 @@ pub const LoadedEnumType = struct { |
| 3523 | 3519 | captures: CaptureValue.Slice, |
| 3524 | 3520 | /// If `zir_index` is `.none`, this is the union type for which this enum is the tag type. |
| 3525 | 3521 | owner_union: Index, |
| 3522 | is_reified: bool, | |
| 3526 | 3523 | |
| 3527 | 3524 | // TODO: the non-fqn will be needed by the new dwarf structure |
| 3528 | 3525 | /// The name of this enum type. |
| ... | ... | @@ -3532,19 +3529,14 @@ pub const LoadedEnumType = struct { |
| 3532 | 3529 | name_nav: Nav.Index.Optional, |
| 3533 | 3530 | namespace: NamespaceIndex, |
| 3534 | 3531 | |
| 3535 | /// An integer type which is used for the numerical value of the enum. Populated immediately, regardless | |
| 3536 | /// of whether the integer tag type was explicitly provided or inferred by the compiler. | |
| 3537 | int_tag_type: Index, | |
| 3538 | int_tag_is_explicit: bool, | |
| 3532 | int_tag_mode: BackingTypeMode, | |
| 3539 | 3533 | nonexhaustive: bool, |
| 3540 | 3534 | |
| 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 | 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 | 3538 | field_names: NullTerminatedString.Slice, |
| 3547 | /// Empty if `field_value_map` is `.none`. | |
| 3539 | field_value_map: OptionalMapIndex, | |
| 3548 | 3540 | field_values: Index.Slice, |
| 3549 | 3541 | |
| 3550 | 3542 | /// Look up field index based on field name. |
| ... | ... | @@ -3596,7 +3588,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { |
| 3596 | 3588 | const extra_items = extra_list.view().items(.@"0"); |
| 3597 | 3589 | const item = unwrapped_index.getItem(ip); |
| 3598 | 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 | 3592 | .type_struct_packed_auto => .{ .auto, false }, |
| 3601 | 3593 | .type_struct_packed_explicit => .{ .explicit, false }, |
| 3602 | 3594 | .type_struct_packed_auto_defaults => .{ .auto, true }, |
| ... | ... | @@ -3667,6 +3659,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { |
| 3667 | 3659 | return .{ |
| 3668 | 3660 | .zir_index = extra.data.zir_index, |
| 3669 | 3661 | .captures = captures, |
| 3662 | .is_reified = extra.data.flags.any_captures == .reified, | |
| 3670 | 3663 | .name = extra.data.name, |
| 3671 | 3664 | .name_nav = extra.data.name_nav, |
| 3672 | 3665 | .namespace = extra.data.namespace, |
| ... | ... | @@ -3675,7 +3668,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { |
| 3675 | 3668 | .@"extern" => .@"extern", |
| 3676 | 3669 | }, |
| 3677 | 3670 | .packed_backing_mode = undefined, |
| 3678 | .packed_backing_int_type = undefined, | |
| 3671 | ||
| 3679 | 3672 | .field_name_map = extra.data.field_name_map, |
| 3680 | 3673 | .field_names = field_names, |
| 3681 | 3674 | .field_types = field_types, |
| ... | ... | @@ -3684,9 +3677,11 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { |
| 3684 | 3677 | .field_is_comptime_bits = field_is_comptime_bits, |
| 3685 | 3678 | .field_runtime_order = field_runtime_order, |
| 3686 | 3679 | .field_offsets = field_offsets, |
| 3680 | .packed_backing_int_type = .none, | |
| 3687 | 3681 | .has_no_possible_value = extra.data.flags.has_no_possible_value, |
| 3688 | 3682 | .has_one_possible_value = extra.data.flags.has_one_possible_value, |
| 3689 | 3683 | .comptime_only = extra.data.flags.comptime_only, |
| 3684 | .has_runtime_bits = extra.data.flags.has_runtime_bits, | |
| 3690 | 3685 | .size = extra.data.size, |
| 3691 | 3686 | .alignment = extra.data.flags.alignment, |
| 3692 | 3687 | }; |
| ... | ... | @@ -3728,12 +3723,13 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { |
| 3728 | 3723 | return .{ |
| 3729 | 3724 | .zir_index = extra.data.zir_index, |
| 3730 | 3725 | .captures = captures, |
| 3726 | .is_reified = extra.data.captures_len == .reified, | |
| 3731 | 3727 | .name = extra.data.name, |
| 3732 | 3728 | .name_nav = extra.data.name_nav, |
| 3733 | 3729 | .namespace = extra.data.namespace, |
| 3734 | 3730 | .layout = .@"packed", |
| 3735 | 3731 | .packed_backing_mode = backing_mode, |
| 3736 | .packed_backing_int_type = extra.data.backing_int_type, | |
| 3732 | ||
| 3737 | 3733 | .field_name_map = extra.data.field_name_map, |
| 3738 | 3734 | .field_names = field_names, |
| 3739 | 3735 | .field_types = field_types, |
| ... | ... | @@ -3742,9 +3738,11 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { |
| 3742 | 3738 | .field_is_comptime_bits = .empty, |
| 3743 | 3739 | .field_runtime_order = .empty, |
| 3744 | 3740 | .field_offsets = .empty, |
| 3741 | .packed_backing_int_type = extra.data.backing_int_type, | |
| 3745 | 3742 | .has_no_possible_value = undefined, |
| 3746 | 3743 | .has_one_possible_value = undefined, |
| 3747 | 3744 | .comptime_only = undefined, |
| 3745 | .has_runtime_bits = undefined, | |
| 3748 | 3746 | .size = undefined, |
| 3749 | 3747 | .alignment = undefined, |
| 3750 | 3748 | }; |
| ... | ... | @@ -3756,7 +3754,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { |
| 3756 | 3754 | const extra_items = extra_list.view().items(.@"0"); |
| 3757 | 3755 | const item = unwrapped_index.getItem(ip); |
| 3758 | 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 | 3758 | .type_union_packed_auto => .auto, |
| 3761 | 3759 | .type_union_packed_explicit => .explicit, |
| 3762 | 3760 | .type_union => { |
| ... | ... | @@ -3779,6 +3777,12 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { |
| 3779 | 3777 | }, |
| 3780 | 3778 | }; |
| 3781 | 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 | 3786 | const field_types: Index.Slice = .{ |
| 3783 | 3787 | .tid = unwrapped_index.tid, |
| 3784 | 3788 | .start = extra_index, |
| ... | ... | @@ -3795,6 +3799,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { |
| 3795 | 3799 | return .{ |
| 3796 | 3800 | .zir_index = extra.data.zir_index, |
| 3797 | 3801 | .captures = captures, |
| 3802 | .is_reified = extra.data.flags.any_captures == .reified, | |
| 3798 | 3803 | .name = extra.data.name, |
| 3799 | 3804 | .name_nav = extra.data.name_nav, |
| 3800 | 3805 | .namespace = extra.data.namespace, |
| ... | ... | @@ -3803,14 +3808,17 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { |
| 3803 | 3808 | .@"extern" => .@"extern", |
| 3804 | 3809 | }, |
| 3805 | 3810 | .runtime_tag = extra.data.flags.runtime_tag, |
| 3811 | .enum_tag_mode = extra.data.flags.enum_tag_mode, | |
| 3806 | 3812 | .enum_tag_type = extra.data.enum_tag_type, |
| 3807 | 3813 | .packed_backing_mode = undefined, |
| 3808 | 3814 | .packed_backing_int_type = undefined, |
| 3815 | .reified_field_names = reified_field_names, | |
| 3809 | 3816 | .field_types = field_types, |
| 3810 | 3817 | .field_aligns = field_aligns, |
| 3811 | 3818 | .has_no_possible_value = extra.data.flags.has_no_possible_value, |
| 3812 | 3819 | .has_one_possible_value = extra.data.flags.has_one_possible_value, |
| 3813 | 3820 | .comptime_only = extra.data.flags.comptime_only, |
| 3821 | .has_runtime_bits = extra.data.flags.has_runtime_bits, | |
| 3814 | 3822 | .size = extra.data.size, |
| 3815 | 3823 | .padding = extra.data.padding, |
| 3816 | 3824 | .alignment = extra.data.flags.alignment, |
| ... | ... | @@ -3832,6 +3840,12 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { |
| 3832 | 3840 | }, |
| 3833 | 3841 | }; |
| 3834 | 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 | 3849 | const field_types: Index.Slice = .{ |
| 3836 | 3850 | .tid = unwrapped_index.tid, |
| 3837 | 3851 | .start = extra_index, |
| ... | ... | @@ -3841,19 +3855,23 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { |
| 3841 | 3855 | return .{ |
| 3842 | 3856 | .zir_index = extra.data.zir_index, |
| 3843 | 3857 | .captures = captures, |
| 3858 | .is_reified = extra.data.captures_len == .reified, | |
| 3844 | 3859 | .name = extra.data.name, |
| 3845 | 3860 | .name_nav = extra.data.name_nav, |
| 3846 | 3861 | .namespace = extra.data.namespace, |
| 3847 | 3862 | .layout = .@"packed", |
| 3848 | 3863 | .runtime_tag = .none, |
| 3864 | .enum_tag_mode = .auto, | |
| 3849 | 3865 | .enum_tag_type = extra.data.enum_tag_type, |
| 3850 | 3866 | .packed_backing_mode = backing_mode, |
| 3851 | 3867 | .packed_backing_int_type = extra.data.backing_int_type, |
| 3868 | .reified_field_names = reified_field_names, | |
| 3852 | 3869 | .field_types = field_types, |
| 3853 | 3870 | .field_aligns = .empty, |
| 3854 | 3871 | .has_no_possible_value = undefined, |
| 3855 | 3872 | .has_one_possible_value = undefined, |
| 3856 | 3873 | .comptime_only = undefined, |
| 3874 | .has_runtime_bits = undefined, | |
| 3857 | 3875 | .size = undefined, |
| 3858 | 3876 | .padding = undefined, |
| 3859 | 3877 | .alignment = undefined, |
| ... | ... | @@ -3917,12 +3935,13 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType { |
| 3917 | 3935 | return .{ |
| 3918 | 3936 | .zir_index = zir_index, |
| 3919 | 3937 | .captures = captures, |
| 3938 | .is_reified = extra.data.captures_len == .reified, | |
| 3920 | 3939 | .owner_union = owner_union, |
| 3921 | 3940 | .name = extra.data.name, |
| 3922 | 3941 | .name_nav = extra.data.name_nav, |
| 3923 | 3942 | .namespace = extra.data.namespace, |
| 3924 | 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 | 3945 | .nonexhaustive = nonexhaustive, |
| 3927 | 3946 | .field_name_map = extra.data.field_name_map, |
| 3928 | 3947 | .field_value_map = field_value_map, |
| ... | ... | @@ -4160,7 +4179,7 @@ pub const Index = enum(u32) { |
| 4160 | 4179 | }; |
| 4161 | 4180 | |
| 4162 | 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 | 4183 | indexes: []const Index, |
| 4165 | 4184 | |
| 4166 | 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 | 4384 | }) void { |
| 4366 | 4385 | _ = self; |
| 4367 | 4386 | const map_fields = @typeInfo(@typeInfo(@TypeOf(tag_to_encoding_map)).pointer.child).@"struct".fields; |
| 4368 | @setEvalBranchQuota(2_000); | |
| 4387 | @setEvalBranchQuota(3_000); | |
| 4369 | 4388 | inline for (@typeInfo(Tag).@"enum".fields, 0..) |tag, start| { |
| 4370 | 4389 | inline for (0..map_fields.len) |offset| { |
| 4371 | 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 | 4816 | .{ .simple_value = .null }, |
| 4798 | 4817 | .{ .simple_value = .true }, |
| 4799 | 4818 | .{ .simple_value = .false }, |
| 4800 | .{ .simple_value = .empty_tuple }, | |
| 4819 | ||
| 4820 | .{ .aggregate = .{ | |
| 4821 | .ty = .empty_tuple_type, | |
| 4822 | .storage = .{ .elems = &.{} }, | |
| 4823 | } }, | |
| 4801 | 4824 | }; |
| 4802 | 4825 | |
| 4803 | 4826 | /// How many items in the InternPool are statically known. |
| ... | ... | @@ -5601,10 +5624,12 @@ pub const Tag = enum(u8) { |
| 5601 | 5624 | has_no_possible_value: bool, |
| 5602 | 5625 | /// Whether the struct is comptime-only. Always `false` until layout resolved. |
| 5603 | 5626 | comptime_only: bool, |
| 5627 | /// Whether the struct has runtime bits. Always `false` until layout resolved. | |
| 5628 | has_runtime_bits: bool, | |
| 5604 | 5629 | /// Alignment of the whole struct. Always `.none` until layout resolved. |
| 5605 | 5630 | alignment: Alignment, |
| 5606 | 5631 | |
| 5607 | _: u17 = 0, | |
| 5632 | _: u16 = 0, | |
| 5608 | 5633 | }; |
| 5609 | 5634 | }; |
| 5610 | 5635 | |
| ... | ... | @@ -5625,21 +5650,25 @@ pub const Tag = enum(u8) { |
| 5625 | 5650 | name_nav: Nav.Index.Optional, |
| 5626 | 5651 | namespace: NamespaceIndex, |
| 5627 | 5652 | |
| 5628 | /// The corresponding `PackedBackingMode` depends on the item's `Tag`. | |
| 5653 | /// The corresponding `BackingTypeMode` depends on the item's `Tag`. | |
| 5629 | 5654 | backing_int_type: Index, |
| 5630 | 5655 | |
| 5631 | 5656 | fields_len: u32, |
| 5632 | 5657 | field_name_map: MapIndex, |
| 5633 | 5658 | }; |
| 5634 | 5659 | |
| 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 | 5665 | /// Trailing: |
| 5638 | 5666 | /// 0. type_hash: PackedU64 // if `any_captures == .reified` |
| 5639 | 5667 | /// 1. captures_len: u32 // if `any_captures == .true` |
| 5640 | 5668 | /// 2. capture: CaptureValue // if `any_captures == .true`; for each `captures_len` |
| 5641 | /// 3. field_type: Index // for each `fields_len` | |
| 5642 | /// 4. field_align: Alignment // for each `fields_len` if `any_field_aligns` | |
| 5669 | /// 3. reified_field_name: NullTerminatedString // if `any_captures == .reified`; for each `fields_len` | |
| 5670 | /// 4. field_type: Index // for each `fields_len` | |
| 5671 | /// 5. field_align: Alignment // for each `fields_len` if `any_field_aligns` | |
| 5643 | 5672 | pub const TypeUnion = struct { |
| 5644 | 5673 | zir_index: TrackedInst.Index, |
| 5645 | 5674 | |
| ... | ... | @@ -5652,7 +5681,6 @@ pub const Tag = enum(u8) { |
| 5652 | 5681 | /// This could be provided through the tag type, but it is more convenient |
| 5653 | 5682 | /// to store it directly. This is also necessary for `dumpStatsFallible` to |
| 5654 | 5683 | /// work on unresolved types. |
| 5655 | /// MLUGG TODO: reconsider, because we resolve the tag type eagerly now. | |
| 5656 | 5684 | fields_len: u32, |
| 5657 | 5685 | |
| 5658 | 5686 | /// Always 0 until layout resolved. |
| ... | ... | @@ -5669,7 +5697,7 @@ pub const Tag = enum(u8) { |
| 5669 | 5697 | /// |
| 5670 | 5698 | /// For `union(enum(E))` syntax, this is `false`, but the generated enum tag type is |
| 5671 | 5699 | /// considered to have an explicitly specified integer tag type. |
| 5672 | explicit_tag_type: bool, | |
| 5700 | enum_tag_mode: BackingTypeMode, | |
| 5673 | 5701 | |
| 5674 | 5702 | /// `packed` layout is represented separately by `TypeStructPacked`. |
| 5675 | 5703 | layout: enum(u1) { auto, @"extern" }, |
| ... | ... | @@ -5685,19 +5713,25 @@ pub const Tag = enum(u8) { |
| 5685 | 5713 | has_no_possible_value: bool, |
| 5686 | 5714 | /// Whether the union is comptime-only. Always `false` until layout resolved. |
| 5687 | 5715 | comptime_only: bool, |
| 5716 | /// Whether the union has runtime bits. Always `false` until layout resolved. | |
| 5717 | has_runtime_bits: bool, | |
| 5688 | 5718 | /// Alignment of the whole union. Always `.none` until layout resolved. |
| 5689 | 5719 | alignment: Alignment, |
| 5690 | 5720 | |
| 5691 | _: u16 = 0, | |
| 5721 | _: u15 = 0, | |
| 5692 | 5722 | }; |
| 5693 | 5723 | }; |
| 5694 | 5724 | |
| 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 | 5730 | /// Trailing: |
| 5698 | 5731 | /// 0. type_hash: PackedU64 // if `captures_len == .reified` |
| 5699 | 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 | 5735 | pub const TypeUnionPacked = struct { |
| 5702 | 5736 | zir_index: TrackedInst.Index, |
| 5703 | 5737 | captures_len: enum(u32) { |
| ... | ... | @@ -5709,7 +5743,7 @@ pub const Tag = enum(u8) { |
| 5709 | 5743 | name_nav: Nav.Index.Optional, |
| 5710 | 5744 | namespace: NamespaceIndex, |
| 5711 | 5745 | |
| 5712 | /// The corresponding `PackedBackingMode` depends on the item's `Tag`. | |
| 5746 | /// The corresponding `BackingTypeMode` depends on the item's `Tag`. | |
| 5713 | 5747 | backing_int_type: Index, |
| 5714 | 5748 | /// Although packed unions do not semantically have a tag type, the compiler still assigns |
| 5715 | 5749 | /// them a "hypothetical" tag type. |
| ... | ... | @@ -5718,7 +5752,6 @@ pub const Tag = enum(u8) { |
| 5718 | 5752 | /// This could be provided through the tag type, but it is more convenient |
| 5719 | 5753 | /// to store it directly. This is also necessary for `dumpStatsFallible` to |
| 5720 | 5754 | /// work on unresolved types. |
| 5721 | /// MLUGG TODO: reconsider, because we resolve the tag type eagerly now. | |
| 5722 | 5755 | fields_len: u32, |
| 5723 | 5756 | }; |
| 5724 | 5757 | |
| ... | ... | @@ -5742,8 +5775,7 @@ pub const Tag = enum(u8) { |
| 5742 | 5775 | namespace: NamespaceIndex, |
| 5743 | 5776 | |
| 5744 | 5777 | /// An integer type which is used for the numerical value of the enum. Whether this was |
| 5745 | /// user-provided or inferred by the compiler depends on the tag. Either way, the field | |
| 5746 | /// is populated immediately (i.e. does not require any type resolution). | |
| 5778 | /// user-provided or inferred by the compiler depends on the tag. | |
| 5747 | 5779 | int_tag_type: Index, |
| 5748 | 5780 | |
| 5749 | 5781 | fields_len: u32, |
| ... | ... | @@ -5762,13 +5794,17 @@ pub const Tag = enum(u8) { |
| 5762 | 5794 | }; |
| 5763 | 5795 | }; |
| 5764 | 5796 | |
| 5765 | /// Differentiates between user-provided and compiler-generated backing types for packed aggregates. | |
| 5766 | pub const PackedBackingMode = enum(u1) { | |
| 5767 | /// The backing type was explicitly provided by the user, i.e. `packed struct(T)` or `packed union(T)`. | |
| 5768 | /// Type resolution simply *validates* that type. | |
| 5797 | /// Differentiates between user-provided and compiler-generated backing types for packed and tagged types. | |
| 5798 | pub const BackingTypeMode = enum(u1) { | |
| 5799 | /// The backing type was explicitly provided by the user. For instance: | |
| 5800 | /// union(T) | |
| 5801 | /// enum(T) | |
| 5802 | /// packed struct(T) | |
| 5803 | /// packed union(T) | |
| 5804 | /// Type layout resolution will evaluate the user-provided expression and validate that type. | |
| 5769 | 5805 | explicit, |
| 5770 | /// No backing type was explicitly provided by the user. Type layout resolution will populate the | |
| 5771 | /// backing type based on the field types; before then it is invalid (probably `.none`). | |
| 5806 | /// No backing type was explicitly provided by the user. Type layout resolution will populate | |
| 5807 | /// an inferred/generated type. | |
| 5772 | 5808 | auto, |
| 5773 | 5809 | }; |
| 5774 | 5810 | |
| ... | ... | @@ -5852,8 +5888,6 @@ pub const SimpleValue = enum(u32) { |
| 5852 | 5888 | void = @intFromEnum(Index.void_value), |
| 5853 | 5889 | /// This is untyped `null`. |
| 5854 | 5890 | null = @intFromEnum(Index.null_value), |
| 5855 | /// This is the untyped empty struct/array literal: `.{}` | |
| 5856 | empty_tuple = @intFromEnum(Index.empty_tuple), | |
| 5857 | 5891 | true = @intFromEnum(Index.bool_true), |
| 5858 | 5892 | false = @intFromEnum(Index.bool_false), |
| 5859 | 5893 | @"unreachable" = @intFromEnum(Index.unreachable_value), |
| ... | ... | @@ -6395,7 +6429,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator, io: Io) void { |
| 6395 | 6429 | ip.nav_ty_deps.deinit(gpa); |
| 6396 | 6430 | ip.func_ies_deps.deinit(gpa); |
| 6397 | 6431 | ip.type_layout_deps.deinit(gpa); |
| 6398 | ip.type_inits_deps.deinit(gpa); | |
| 6432 | ip.struct_defaults_deps.deinit(gpa); | |
| 6399 | 6433 | ip.zon_file_deps.deinit(gpa); |
| 6400 | 6434 | ip.embed_file_deps.deinit(gpa); |
| 6401 | 6435 | ip.namespace_deps.deinit(gpa); |
| ... | ... | @@ -6544,12 +6578,10 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 6544 | 6578 | } }, |
| 6545 | 6579 | .false => .{ .declared = .{ |
| 6546 | 6580 | .zir_index = extra.data.zir_index, |
| 6547 | .arg_ty = .none, | |
| 6548 | 6581 | .captures = .{ .owned = .empty }, |
| 6549 | 6582 | } }, |
| 6550 | 6583 | .true => .{ .declared = .{ |
| 6551 | 6584 | .zir_index = extra.data.zir_index, |
| 6552 | .arg_ty = .none, | |
| 6553 | 6585 | .captures = .{ .owned = .{ |
| 6554 | 6586 | .tid = unwrapped_index.tid, |
| 6555 | 6587 | .start = extra.end + 1, |
| ... | ... | @@ -6572,11 +6604,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 6572 | 6604 | } }, |
| 6573 | 6605 | _ => .{ .declared = .{ |
| 6574 | 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 | 6607 | .captures = .{ .owned = .{ |
| 6581 | 6608 | .tid = unwrapped_index.tid, |
| 6582 | 6609 | .start = extra.end, |
| ... | ... | @@ -6595,12 +6622,10 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 6595 | 6622 | } }, |
| 6596 | 6623 | .false => .{ .declared = .{ |
| 6597 | 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 | 6625 | .captures = .{ .owned = .empty }, |
| 6600 | 6626 | } }, |
| 6601 | 6627 | .true => .{ .declared = .{ |
| 6602 | 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 | 6629 | .captures = .{ .owned = .{ |
| 6605 | 6630 | .tid = unwrapped_index.tid, |
| 6606 | 6631 | .start = extra.end + 1, |
| ... | ... | @@ -6619,11 +6644,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 6619 | 6644 | } }, |
| 6620 | 6645 | _ => .{ .declared = .{ |
| 6621 | 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 | 6647 | .captures = .{ .owned = .{ |
| 6628 | 6648 | .tid = unwrapped_index.tid, |
| 6629 | 6649 | .start = extra.end, |
| ... | ... | @@ -6645,11 +6665,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 6645 | 6665 | } }, |
| 6646 | 6666 | _ => .{ .declared = .{ |
| 6647 | 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 | 6668 | .captures = .{ .owned = .{ |
| 6654 | 6669 | .tid = unwrapped_index.tid, |
| 6655 | 6670 | .start = extra.end + 1, |
| ... | ... | @@ -6662,7 +6677,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 6662 | 6677 | const extra = extraDataTrail(unwrapped_index.getExtra(ip), Tag.TypeOpaque, data); |
| 6663 | 6678 | break :ns .{ .declared = .{ |
| 6664 | 6679 | .zir_index = extra.data.zir_index, |
| 6665 | .arg_ty = .none, | |
| 6666 | 6680 | .captures = .{ .owned = .{ |
| 6667 | 6681 | .tid = unwrapped_index.tid, |
| 6668 | 6682 | .start = extra.end, |
| ... | ... | @@ -6883,7 +6897,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 6883 | 6897 | }, |
| 6884 | 6898 | .type_array_small, |
| 6885 | 6899 | .type_vector, |
| 6886 | // MLUGG TODO: is this still possible? also, i hate .only_possible_value, it should die in a fire. | |
| 6887 | 6900 | .type_struct_packed_auto, |
| 6888 | 6901 | .type_struct_packed_explicit, |
| 6889 | 6902 | => .{ .aggregate = .{ |
| ... | ... | @@ -6894,7 +6907,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 6894 | 6907 | // There is only one possible value precisely due to the |
| 6895 | 6908 | // fact that this values slice is fully populated! |
| 6896 | 6909 | .type_struct, |
| 6897 | // MLUGG TODO: is this still possible? also, i hate .only_possible_value, it should die in a fire. | |
| 6898 | 6910 | .type_struct_packed_auto_defaults, |
| 6899 | 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 | 7457 | }); |
| 7446 | 7458 | }, |
| 7447 | 7459 | |
| 7448 | .struct_type => unreachable, // use getStructType() instead | |
| 7449 | .tuple_type => unreachable, // use getTupleType() instead | |
| 7450 | .union_type => unreachable, // use getUnionType() instead | |
| 7451 | .opaque_type => unreachable, // use getOpaqueType() instead | |
| 7460 | .struct_type => unreachable, // instead use: getDeclaredStructType, getReifiedStructType | |
| 7461 | .union_type => unreachable, // instead use: getDeclaredUnionType, getReifiedUnionType | |
| 7462 | .enum_type => unreachable, // instead use: getDeclaredEnumType, getReifiedEnumType, getGeneratedEnumTagType | |
| 7463 | .opaque_type => unreachable, // instead use: getDeclaredOpaqueType | |
| 7452 | 7464 | |
| 7453 | .enum_type => unreachable, // use getEnumType() instead | |
| 7465 | .tuple_type => unreachable, // use getTupleType() instead | |
| 7454 | 7466 | .func_type => unreachable, // use getFuncType() instead |
| 7455 | 7467 | .@"extern" => unreachable, // use getExtern() instead |
| 7456 | 7468 | .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 | 8084 | return gop.put(); |
| 8073 | 8085 | } |
| 8074 | 8086 | |
| 8075 | pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct { | |
| 8087 | pub 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 | ||
| 8246 | pub fn getReifiedStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct { | |
| 8247 | zir_index: TrackedInst.Index, | |
| 8248 | type_hash: u64, | |
| 8076 | 8249 | fields_len: u32, |
| 8077 | 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 | 8251 | any_comptime_fields: bool, |
| 8084 | 8252 | any_field_defaults: bool, |
| 8085 | 8253 | any_field_aligns: bool, |
| 8086 | key: union(enum) { | |
| 8087 | declared: struct { | |
| 8088 | zir_index: TrackedInst.Index, | |
| 8089 | captures: []const CaptureValue, | |
| 8090 | }, | |
| 8091 | reified: struct { | |
| 8092 | zir_index: TrackedInst.Index, | |
| 8093 | type_hash: u64, | |
| 8094 | }, | |
| 8095 | }, | |
| 8254 | /// Explicitly specified backing int type. `.none` if not packed or if backing type is inferred. | |
| 8255 | packed_backing_int_type: Index, | |
| 8096 | 8256 | }) Allocator.Error!WipContainerType.Result { |
| 8097 | const key: Key = .{ .struct_type = switch (ini.key) { | |
| 8098 | .declared => |d| .{ .declared = .{ | |
| 8099 | .zir_index = d.zir_index, | |
| 8100 | .arg_ty = switch (ini.layout) { | |
| 8101 | .auto, .@"extern" => .none, | |
| 8102 | .@"packed" => ini.explicit_packed_backing_type, | |
| 8103 | }, | |
| 8104 | .captures = .{ .external = d.captures }, | |
| 8105 | } }, | |
| 8106 | .reified => |r| .{ .reified = .{ | |
| 8107 | .zir_index = r.zir_index, | |
| 8108 | .type_hash = r.type_hash, | |
| 8109 | } }, | |
| 8110 | } }; | |
| 8111 | var gop = try ip.getOrPutKey(gpa, io, tid, key); | |
| 8257 | var gop = try ip.getOrPutKey(gpa, io, tid, .{ .struct_type = .{ .reified = .{ | |
| 8258 | .zir_index = ini.zir_index, | |
| 8259 | .type_hash = ini.type_hash, | |
| 8260 | } } }); | |
| 8112 | 8261 | defer gop.deinit(); |
| 8113 | 8262 | if (gop == .existing) return .{ .existing = gop.existing }; |
| 8114 | 8263 | |
| ... | ... | @@ -8120,46 +8269,37 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread |
| 8120 | 8269 | const field_name_map = try ip.addMap(gpa, io, tid, ini.fields_len); |
| 8121 | 8270 | errdefer local.mutate.maps.len -= 1; |
| 8122 | 8271 | |
| 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 | 8272 | const is_extern = switch (ini.layout) { |
| 8129 | 8273 | .auto => false, |
| 8130 | 8274 | .@"extern" => true, |
| 8131 | 8275 | .@"packed" => { |
| 8132 | 8276 | try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStructPacked).@"struct".fields.len + |
| 8133 | type_hash_captures_extra_len + | |
| 8277 | 2 + // type_hash | |
| 8134 | 8278 | ini.fields_len + // field_name |
| 8135 | 8279 | ini.fields_len + // field_type |
| 8136 | 8280 | (if (ini.any_field_defaults) ini.fields_len else 0)); // field_default |
| 8137 | 8281 | |
| 8138 | 8282 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStructPacked{ |
| 8139 | .zir_index = zir_index, | |
| 8140 | .captures_len = switch (ini.key) { | |
| 8141 | .declared => |d| @enumFromInt(d.captures.len), | |
| 8142 | .reified => .reified, | |
| 8143 | }, | |
| 8283 | .zir_index = ini.zir_index, | |
| 8284 | .captures_len = .reified, | |
| 8144 | 8285 | .name = undefined, // set by `finish` |
| 8145 | 8286 | .name_nav = undefined, // set by `finish` |
| 8146 | 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 | 8289 | .fields_len = ini.fields_len, |
| 8149 | 8290 | .field_name_map = field_name_map, |
| 8150 | 8291 | }); |
| 8151 | switch (ini.key) { | |
| 8152 | .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}), | |
| 8153 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), | |
| 8154 | } | |
| 8292 | _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); // type_hash | |
| 8155 | 8293 | const field_names_start = extra.mutate.len; |
| 8156 | 8294 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name |
| 8295 | const field_types_start = extra.mutate.len; | |
| 8157 | 8296 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type |
| 8297 | const field_defaults_start = extra.mutate.len; | |
| 8158 | 8298 | if (ini.any_field_defaults) { |
| 8159 | 8299 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_default |
| 8160 | 8300 | } |
| 8161 | 8301 | items.appendAssumeCapacity(.{ |
| 8162 | .tag = switch (ini.explicit_packed_backing_type) { | |
| 8302 | .tag = switch (ini.packed_backing_int_type) { | |
| 8163 | 8303 | .none => if (ini.any_field_defaults) .type_struct_packed_auto_defaults else .type_struct_packed_auto, |
| 8164 | 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 | 8311 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?, |
| 8172 | 8312 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name_nav").?, |
| 8173 | 8313 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?, |
| 8174 | .tag_type_index = null, | |
| 8175 | .fields_len = ini.fields_len, | |
| 8176 | .field_name_map = field_name_map, | |
| 8177 | .field_names_start = field_names_start, | |
| 8178 | .field_comptime_bits_start = null, | |
| 8314 | .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len }, | |
| 8315 | .field_types = .{ .tid = tid, .start = field_types_start, .len = ini.fields_len }, | |
| 8316 | .field_values = if (ini.any_field_defaults) | |
| 8317 | .{ .tid = tid, .start = field_defaults_start, .len = ini.fields_len } | |
| 8318 | else | |
| 8319 | undefined, | |
| 8320 | .field_aligns = undefined, | |
| 8321 | .field_is_comptime_bits = undefined, | |
| 8179 | 8322 | } }; |
| 8180 | 8323 | }, |
| 8181 | 8324 | }; |
| 8182 | 8325 | |
| 8183 | 8326 | try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStruct).@"struct".fields.len + |
| 8184 | type_hash_captures_extra_len + | |
| 8327 | 2 + // type_hash | |
| 8185 | 8328 | ini.fields_len + // field_name |
| 8186 | 8329 | ini.fields_len + // field_type |
| 8187 | 8330 | (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 | 8334 | ini.fields_len); // field_offset |
| 8192 | 8335 | |
| 8193 | 8336 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStruct{ |
| 8194 | .zir_index = zir_index, | |
| 8337 | .zir_index = ini.zir_index, | |
| 8195 | 8338 | .name = undefined, // set by `finish` |
| 8196 | 8339 | .name_nav = undefined, // set by `finish` |
| 8197 | 8340 | .namespace = undefined, // set by `finish` |
| ... | ... | @@ -8199,10 +8342,7 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread |
| 8199 | 8342 | .field_name_map = field_name_map, |
| 8200 | 8343 | .size = 0, |
| 8201 | 8344 | .flags = .{ |
| 8202 | .any_captures = switch (ini.key) { | |
| 8203 | .declared => |d| if (d.captures.len != 0) .true else .false, | |
| 8204 | .reified => .reified, | |
| 8205 | }, | |
| 8345 | .any_captures = .reified, | |
| 8206 | 8346 | .layout = if (is_extern) .@"extern" else .auto, |
| 8207 | 8347 | .any_comptime_fields = ini.any_comptime_fields, |
| 8208 | 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 | 8350 | .has_one_possible_value = false, |
| 8211 | 8351 | .has_no_possible_value = false, |
| 8212 | 8352 | .comptime_only = false, |
| 8353 | .has_runtime_bits = false, | |
| 8213 | 8354 | .alignment = .none, |
| 8214 | 8355 | }, |
| 8215 | 8356 | }); |
| 8216 | switch (ini.key) { | |
| 8217 | .declared => |d| if (d.captures.len != 0) { | |
| 8218 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); | |
| 8219 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}); | |
| 8220 | }, | |
| 8221 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), | |
| 8222 | } | |
| 8357 | _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); // type_hash | |
| 8223 | 8358 | const field_names_start = extra.mutate.len; |
| 8224 | 8359 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name |
| 8360 | const field_types_start = extra.mutate.len; | |
| 8225 | 8361 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type |
| 8362 | const field_defaults_start = extra.mutate.len; | |
| 8226 | 8363 | if (ini.any_field_defaults) { |
| 8227 | 8364 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_default |
| 8228 | 8365 | } |
| 8366 | const field_aligns_start = extra.mutate.len; | |
| 8229 | 8367 | if (ini.any_field_aligns) { |
| 8230 | 8368 | 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: { | |
| 8233 | const start = extra.mutate.len; | |
| 8370 | const field_is_comptime_bits_start = extra.mutate.len; | |
| 8371 | if (ini.any_comptime_fields) { | |
| 8234 | 8372 | extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 31) / 32); // field_is_comptime_bits |
| 8235 | break :start start; | |
| 8236 | } else null; | |
| 8373 | } | |
| 8237 | 8374 | if (!is_extern) { |
| 8238 | 8375 | 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 | 8385 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name").?, |
| 8249 | 8386 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name_nav").?, |
| 8250 | 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 | ||
| 8405 | pub 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 | 8498 | .fields_len = ini.fields_len, |
| 8253 | .field_name_map = field_name_map, | |
| 8254 | .field_names_start = field_names_start, | |
| 8255 | .field_comptime_bits_start = field_comptime_bits_start, | |
| 8499 | .size = 0, | |
| 8500 | .padding = 0, | |
| 8501 | .flags = .{ | |
| 8502 | .any_captures = if (ini.captures.len != 0) .true else .false, | |
| 8503 | .enum_tag_mode = ini.enum_tag_mode, | |
| 8504 | .layout = if (is_extern) .@"extern" else .auto, | |
| 8505 | .any_field_aligns = ini.any_field_aligns, | |
| 8506 | .runtime_tag = ini.runtime_tag, | |
| 8507 | .has_one_possible_value = false, | |
| 8508 | .has_no_possible_value = false, | |
| 8509 | .comptime_only = false, | |
| 8510 | .has_runtime_bits = false, | |
| 8511 | .alignment = .none, | |
| 8512 | }, | |
| 8513 | }); | |
| 8514 | if (ini.captures.len > 0) { | |
| 8515 | extra.appendAssumeCapacity(.{@intCast(ini.captures.len)}); // captures_len | |
| 8516 | extra.appendSliceAssumeCapacity(.{@ptrCast(ini.captures)}); // capture | |
| 8517 | } | |
| 8518 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type | |
| 8519 | if (ini.any_field_aligns) { | |
| 8520 | extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 3) / 4); // field_align | |
| 8521 | } | |
| 8522 | items.appendAssumeCapacity(.{ | |
| 8523 | .tag = .type_union, | |
| 8524 | .data = extra_index, | |
| 8525 | }); | |
| 8526 | return .{ .wip = .{ | |
| 8527 | .index = gop.put(), | |
| 8528 | .tid = tid, | |
| 8529 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?, | |
| 8530 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name_nav").?, | |
| 8531 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?, | |
| 8532 | .field_names = undefined, | |
| 8533 | .field_types = undefined, | |
| 8534 | .field_values = undefined, | |
| 8535 | .field_aligns = undefined, | |
| 8536 | .field_is_comptime_bits = undefined, | |
| 8256 | 8537 | } }; |
| 8257 | 8538 | } |
| 8258 | 8539 | |
| 8259 | pub fn getUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct { | |
| 8540 | pub fn getReifiedUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct { | |
| 8541 | zir_index: TrackedInst.Index, | |
| 8542 | type_hash: u64, | |
| 8260 | 8543 | fields_len: u32, |
| 8261 | 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 | 8545 | any_field_aligns: bool, |
| 8270 | key: union(enum) { | |
| 8271 | declared: struct { | |
| 8272 | zir_index: TrackedInst.Index, | |
| 8273 | captures: []const CaptureValue, | |
| 8274 | /// This is the `T` in one of the following: | |
| 8275 | /// * `union(T)` (enum tag type) | |
| 8276 | /// * `union(enum(T))` (int tag type) | |
| 8277 | /// * `packed union(T)` (int backing type) | |
| 8278 | /// Or `.none` otherwise. | |
| 8279 | arg_ty: InternPool.Index, | |
| 8280 | }, | |
| 8281 | reified: struct { | |
| 8282 | zir_index: TrackedInst.Index, | |
| 8283 | type_hash: u64, | |
| 8284 | }, | |
| 8285 | }, | |
| 8546 | runtime_tag: LoadedUnionType.RuntimeTag, | |
| 8547 | /// Explicitly specified enum tag type. `.none` if `runtime_tag != .tagged`. | |
| 8548 | enum_tag_type: Index, | |
| 8549 | /// Explicitly specified backing int type. `.none` if not packed or if backing type is inferred. | |
| 8550 | packed_backing_int_type: Index, | |
| 8286 | 8551 | }) Allocator.Error!WipContainerType.Result { |
| 8287 | if (ini.explicit_packed_backing_type != .none) { | |
| 8288 | assert(ip.zigTypeTag(ini.explicit_packed_backing_type) == .int); | |
| 8289 | if (ini.key == .declared) assert(ini.key.declared.arg_ty == ini.explicit_packed_backing_type); | |
| 8290 | } | |
| 8291 | const key: Key = .{ .union_type = switch (ini.key) { | |
| 8292 | .declared => |d| .{ .declared = .{ | |
| 8293 | .zir_index = d.zir_index, | |
| 8294 | .arg_ty = d.arg_ty, | |
| 8295 | .captures = .{ .external = d.captures }, | |
| 8296 | } }, | |
| 8297 | .reified => |r| .{ .reified = .{ | |
| 8298 | .zir_index = r.zir_index, | |
| 8299 | .type_hash = r.type_hash, | |
| 8300 | } }, | |
| 8301 | } }; | |
| 8302 | var gop = try ip.getOrPutKey(gpa, io, tid, key); | |
| 8552 | var gop = try ip.getOrPutKey(gpa, io, tid, .{ .union_type = .{ .reified = .{ | |
| 8553 | .zir_index = ini.zir_index, | |
| 8554 | .type_hash = ini.type_hash, | |
| 8555 | } } }); | |
| 8303 | 8556 | defer gop.deinit(); |
| 8304 | 8557 | if (gop == .existing) return .{ .existing = gop.existing }; |
| 8305 | 8558 | |
| ... | ... | @@ -8308,98 +8561,86 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread. |
| 8308 | 8561 | const extra = local.getMutableExtra(gpa, io); |
| 8309 | 8562 | try items.ensureUnusedCapacity(1); |
| 8310 | 8563 | |
| 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 | 8564 | const is_extern = switch (ini.layout) { |
| 8317 | 8565 | .auto => false, |
| 8318 | 8566 | .@"extern" => true, |
| 8319 | 8567 | .@"packed" => { |
| 8320 | 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 | 8571 | ini.fields_len); // field_type |
| 8323 | 8572 | |
| 8324 | 8573 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnionPacked{ |
| 8325 | .zir_index = zir_index, | |
| 8326 | .captures_len = switch (ini.key) { | |
| 8327 | .declared => |d| @enumFromInt(d.captures.len), | |
| 8328 | .reified => .reified, | |
| 8329 | }, | |
| 8574 | .zir_index = ini.zir_index, | |
| 8575 | .captures_len = .reified, | |
| 8330 | 8576 | .name = undefined, // set by `finish` |
| 8331 | 8577 | .name_nav = undefined, // set by `finish` |
| 8332 | 8578 | .namespace = undefined, // set by `finish` |
| 8333 | .backing_int_type = ini.explicit_packed_backing_type, | |
| 8334 | .enum_tag_type = .none, // set by `setTagType` | |
| 8579 | .backing_int_type = ini.packed_backing_int_type, | |
| 8580 | .enum_tag_type = .none, | |
| 8335 | 8581 | .fields_len = ini.fields_len, |
| 8336 | 8582 | }); |
| 8337 | switch (ini.key) { | |
| 8338 | .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}), | |
| 8339 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), | |
| 8340 | } | |
| 8583 | _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); // type_hash | |
| 8584 | const field_names_start = extra.mutate.len; | |
| 8585 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // reified_field_name | |
| 8586 | const field_types_start = extra.mutate.len; | |
| 8341 | 8587 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type |
| 8342 | 8588 | items.appendAssumeCapacity(.{ |
| 8343 | .tag = switch (ini.explicit_packed_backing_type) { | |
| 8589 | .tag = switch (ini.packed_backing_int_type) { | |
| 8344 | 8590 | .none => .type_union_packed_auto, |
| 8345 | 8591 | else => .type_union_packed_explicit, |
| 8346 | 8592 | }, |
| 8347 | 8593 | .data = extra_index, |
| 8348 | 8594 | }); |
| 8349 | return .{ | |
| 8350 | .wip = .{ | |
| 8351 | .index = gop.put(), | |
| 8352 | .tid = tid, | |
| 8353 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name").?, | |
| 8354 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name_nav").?, | |
| 8355 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "namespace").?, | |
| 8356 | .tag_type_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "enum_tag_type").?, | |
| 8357 | .fields_len = 0, // the fields come from the enum, so nothing to set | |
| 8358 | .field_name_map = undefined, | |
| 8359 | .field_names_start = undefined, | |
| 8360 | .field_comptime_bits_start = undefined, | |
| 8361 | }, | |
| 8362 | }; | |
| 8595 | return .{ .wip = .{ | |
| 8596 | .index = gop.put(), | |
| 8597 | .tid = tid, | |
| 8598 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name").?, | |
| 8599 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name_nav").?, | |
| 8600 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "namespace").?, | |
| 8601 | .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len }, | |
| 8602 | .field_types = .{ .tid = tid, .start = field_types_start, .len = ini.fields_len }, | |
| 8603 | .field_values = undefined, | |
| 8604 | .field_aligns = undefined, | |
| 8605 | .field_is_comptime_bits = undefined, | |
| 8606 | } }; | |
| 8363 | 8607 | }, |
| 8364 | 8608 | }; |
| 8365 | 8609 | |
| 8366 | 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 | 8613 | ini.fields_len + // field_type |
| 8369 | 8614 | (if (ini.any_field_aligns) (ini.fields_len + 3) / 4 else 0)); // field_align |
| 8370 | 8615 | |
| 8371 | 8616 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{ |
| 8372 | .zir_index = zir_index, | |
| 8617 | .zir_index = ini.zir_index, | |
| 8373 | 8618 | .name = undefined, // set by `finish` |
| 8374 | 8619 | .name_nav = undefined, // set by `finish` |
| 8375 | 8620 | .namespace = undefined, // set by `finish` |
| 8376 | .enum_tag_type = .none, // set by `setTagType` | |
| 8621 | .enum_tag_type = ini.enum_tag_type, | |
| 8377 | 8622 | .fields_len = ini.fields_len, |
| 8378 | 8623 | .size = 0, |
| 8379 | 8624 | .padding = 0, |
| 8380 | 8625 | .flags = .{ |
| 8381 | .any_captures = switch (ini.key) { | |
| 8382 | .declared => |d| if (d.captures.len != 0) .true else .false, | |
| 8383 | .reified => .reified, | |
| 8384 | }, | |
| 8385 | .explicit_tag_type = ini.have_explicit_enum_tag, | |
| 8626 | .any_captures = .reified, | |
| 8627 | .enum_tag_mode = if (ini.enum_tag_type == .none) .auto else .explicit, | |
| 8386 | 8628 | .layout = if (is_extern) .@"extern" else .auto, |
| 8387 | 8629 | .any_field_aligns = ini.any_field_aligns, |
| 8388 | 8630 | .runtime_tag = ini.runtime_tag, |
| 8389 | 8631 | .has_one_possible_value = false, |
| 8390 | 8632 | .has_no_possible_value = false, |
| 8391 | 8633 | .comptime_only = false, |
| 8634 | .has_runtime_bits = false, | |
| 8392 | 8635 | .alignment = .none, |
| 8393 | 8636 | }, |
| 8394 | 8637 | }); |
| 8395 | switch (ini.key) { | |
| 8396 | .declared => |d| if (d.captures.len != 0) { | |
| 8397 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); | |
| 8398 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}); | |
| 8399 | }, | |
| 8400 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), | |
| 8401 | } | |
| 8638 | _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); | |
| 8639 | const field_names_start = extra.mutate.len; | |
| 8640 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // reified_field_name | |
| 8641 | const field_types_start = extra.mutate.len; | |
| 8402 | 8642 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type |
| 8643 | const field_aligns_start = extra.mutate.len; | |
| 8403 | 8644 | if (ini.any_field_aligns) { |
| 8404 | 8645 | 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 | 8648 | .tag = .type_union, |
| 8408 | 8649 | .data = extra_index, |
| 8409 | 8650 | }); |
| 8410 | return .{ | |
| 8411 | .wip = .{ | |
| 8412 | .index = gop.put(), | |
| 8413 | .tid = tid, | |
| 8414 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?, | |
| 8415 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name_nav").?, | |
| 8416 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?, | |
| 8417 | .tag_type_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "enum_tag_type").?, | |
| 8418 | .fields_len = 0, // the fields come from the enum, so nothing to set | |
| 8419 | .field_name_map = undefined, | |
| 8420 | .field_names_start = undefined, | |
| 8421 | .field_comptime_bits_start = undefined, | |
| 8422 | }, | |
| 8423 | }; | |
| 8651 | return .{ .wip = .{ | |
| 8652 | .index = gop.put(), | |
| 8653 | .tid = tid, | |
| 8654 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?, | |
| 8655 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name_nav").?, | |
| 8656 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?, | |
| 8657 | .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len }, | |
| 8658 | .field_types = .{ .tid = tid, .start = field_types_start, .len = ini.fields_len }, | |
| 8659 | .field_values = undefined, | |
| 8660 | .field_aligns = if (ini.any_field_aligns) | |
| 8661 | .{ .tid = tid, .start = field_aligns_start, .len = ini.fields_len } | |
| 8662 | else | |
| 8663 | undefined, | |
| 8664 | .field_is_comptime_bits = undefined, | |
| 8665 | } }; | |
| 8424 | 8666 | } |
| 8425 | 8667 | |
| 8426 | pub fn getEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct { | |
| 8668 | pub 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 | ||
| 8757 | pub fn getReifiedEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct { | |
| 8758 | zir_index: TrackedInst.Index, | |
| 8759 | type_hash: u64, | |
| 8427 | 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 | 8761 | nonexhaustive: bool, |
| 8432 | key: union(enum) { | |
| 8433 | declared: struct { | |
| 8434 | zir_index: TrackedInst.Index, | |
| 8435 | captures: []const CaptureValue, | |
| 8436 | }, | |
| 8437 | reified: struct { | |
| 8438 | zir_index: TrackedInst.Index, | |
| 8439 | type_hash: u64, | |
| 8440 | }, | |
| 8441 | generated_union_tag: Index, | |
| 8442 | }, | |
| 8762 | /// Explicitly specified int tag type, or `.none` if the int tag type is inferred. | |
| 8763 | int_tag_type: Index, | |
| 8443 | 8764 | }) Allocator.Error!WipContainerType.Result { |
| 8444 | const key: Key = .{ .enum_type = switch (ini.key) { | |
| 8445 | .declared => |d| .{ .declared = .{ | |
| 8446 | .zir_index = d.zir_index, | |
| 8447 | .arg_ty = ini.explicit_int_tag_type, | |
| 8448 | .captures = .{ .external = d.captures }, | |
| 8449 | } }, | |
| 8450 | .reified => |r| .{ .reified = .{ | |
| 8451 | .zir_index = r.zir_index, | |
| 8452 | .type_hash = r.type_hash, | |
| 8453 | } }, | |
| 8454 | .generated_union_tag => |u| .{ .generated_union_tag = u }, | |
| 8455 | } }; | |
| 8456 | var gop = try ip.getOrPutKey(gpa, io, tid, key); | |
| 8765 | var gop = try ip.getOrPutKey(gpa, io, tid, .{ .enum_type = .{ .reified = .{ | |
| 8766 | .zir_index = ini.zir_index, | |
| 8767 | .type_hash = ini.type_hash, | |
| 8768 | } } }); | |
| 8457 | 8769 | defer gop.deinit(); |
| 8458 | 8770 | if (gop == .existing) return .{ .existing = gop.existing }; |
| 8459 | 8771 | |
| ... | ... | @@ -8464,7 +8776,7 @@ pub fn getEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.I |
| 8464 | 8776 | |
| 8465 | 8777 | const tag: Tag, const have_values: bool = if (ini.nonexhaustive) |
| 8466 | 8778 | .{ .type_enum_nonexhaustive, true } |
| 8467 | else if (ini.explicit_int_tag_type != .none) | |
| 8779 | else if (ini.int_tag_type != .none) | |
| 8468 | 8780 | .{ .type_enum_explicit, true } |
| 8469 | 8781 | else |
| 8470 | 8782 | .{ .type_enum_auto, false }; |
| ... | ... | @@ -8476,44 +8788,27 @@ pub fn getEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.I |
| 8476 | 8788 | errdefer local.mutate.maps.len -= @intFromBool(have_values); |
| 8477 | 8789 | |
| 8478 | 8790 | try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeEnum).@"struct".fields.len + |
| 8479 | switch (ini.key) { | |
| 8480 | .declared => |d| 1 + d.captures.len, // `zir_index` and `capture` | |
| 8481 | .reified => 3, // `zir_index` and `type_hash` | |
| 8482 | .generated_union_tag => 1, // owner_union | |
| 8483 | } + | |
| 8791 | 1 + // zir_index | |
| 8792 | 2 + // type_hash | |
| 8484 | 8793 | @intFromBool(have_values) + // field_value_map |
| 8485 | 8794 | ini.fields_len + // field_name |
| 8486 | 8795 | (if (have_values) ini.fields_len else 0)); // field_value |
| 8487 | 8796 | |
| 8488 | 8797 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeEnum{ |
| 8489 | .captures_len = switch (ini.key) { | |
| 8490 | .declared => |d| @enumFromInt(d.captures.len), | |
| 8491 | .reified => .reified, | |
| 8492 | .generated_union_tag => .generated_union_tag, | |
| 8493 | }, | |
| 8798 | .captures_len = .reified, | |
| 8494 | 8799 | .name = undefined, // set by `finish` |
| 8495 | 8800 | .name_nav = undefined, // set by `finish` |
| 8496 | 8801 | .namespace = undefined, // set by `finish` |
| 8497 | .int_tag_type = ini.explicit_int_tag_type, | |
| 8802 | .int_tag_type = ini.int_tag_type, | |
| 8498 | 8803 | .fields_len = ini.fields_len, |
| 8499 | 8804 | .field_name_map = field_name_map, |
| 8500 | 8805 | }); |
| 8501 | switch (ini.key) { | |
| 8502 | .declared => |d| { | |
| 8503 | extra.appendAssumeCapacity(.{@intFromEnum(d.zir_index)}); // zir_index | |
| 8504 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}); // capture | |
| 8505 | }, | |
| 8506 | .reified => |r| { | |
| 8507 | extra.appendAssumeCapacity(.{@intFromEnum(r.zir_index)}); // zir_index | |
| 8508 | _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)); // type_hash | |
| 8509 | }, | |
| 8510 | .generated_union_tag => |owner_union| { | |
| 8511 | extra.appendAssumeCapacity(.{@intFromEnum(owner_union)}); // owner_union | |
| 8512 | }, | |
| 8513 | } | |
| 8514 | if (have_values) extra.appendAssumeCapacity(.{@intFromEnum(field_value_map)}); | |
| 8806 | extra.appendAssumeCapacity(.{@intFromEnum(ini.zir_index)}); // zir_index | |
| 8807 | _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); // type_hash | |
| 8808 | if (have_values) extra.appendAssumeCapacity(.{@intFromEnum(field_value_map)}); // field_value_map | |
| 8515 | 8809 | const field_names_start = extra.mutate.len; |
| 8516 | 8810 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name |
| 8811 | const field_values_start = extra.mutate.len; | |
| 8517 | 8812 | if (have_values) extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_value |
| 8518 | 8813 | items.appendAssumeCapacity(.{ |
| 8519 | 8814 | .tag = tag, |
| ... | ... | @@ -8525,22 +8820,91 @@ pub fn getEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.I |
| 8525 | 8820 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name").?, |
| 8526 | 8821 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name_nav").?, |
| 8527 | 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 | ||
| 8834 | pub 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 | 8873 | .fields_len = ini.fields_len, |
| 8530 | 8874 | .field_name_map = field_name_map, |
| 8531 | .field_names_start = field_names_start, | |
| 8532 | .field_comptime_bits_start = null, | |
| 8875 | }); | |
| 8876 | extra.appendAssumeCapacity(.{@intFromEnum(ini.union_type)}); // owner_union | |
| 8877 | if (have_values) extra.appendAssumeCapacity(.{@intFromEnum(field_value_map)}); | |
| 8878 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name | |
| 8879 | if (have_values) extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_value | |
| 8880 | items.appendAssumeCapacity(.{ | |
| 8881 | .tag = switch (ini.int_tag_mode) { | |
| 8882 | .auto => .type_enum_auto, | |
| 8883 | .explicit => .type_enum_explicit, | |
| 8884 | }, | |
| 8885 | .data = extra_index, | |
| 8886 | }); | |
| 8887 | return .{ .wip = .{ | |
| 8888 | .index = gop.put(), | |
| 8889 | .tid = tid, | |
| 8890 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name").?, | |
| 8891 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name_nav").?, | |
| 8892 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "namespace").?, | |
| 8893 | .field_names = undefined, | |
| 8894 | .field_types = undefined, | |
| 8895 | .field_values = undefined, | |
| 8896 | .field_aligns = undefined, | |
| 8897 | .field_is_comptime_bits = undefined, | |
| 8533 | 8898 | } }; |
| 8534 | 8899 | } |
| 8535 | 8900 | |
| 8536 | pub fn getOpaqueType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct { | |
| 8901 | pub fn getDeclaredOpaqueType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct { | |
| 8537 | 8902 | zir_index: TrackedInst.Index, |
| 8538 | 8903 | captures: []const CaptureValue, |
| 8539 | 8904 | }) Allocator.Error!WipContainerType.Result { |
| 8540 | 8905 | var gop = try ip.getOrPutKey(gpa, io, tid, .{ .opaque_type = .{ .declared = .{ |
| 8541 | 8906 | .zir_index = ini.zir_index, |
| 8542 | 8907 | .captures = .{ .external = ini.captures }, |
| 8543 | .arg_ty = .none, | |
| 8544 | 8908 | } } }); |
| 8545 | 8909 | defer gop.deinit(); |
| 8546 | 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 | 8933 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name").?, |
| 8570 | 8934 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name_nav").?, |
| 8571 | 8935 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "namespace").?, |
| 8572 | .tag_type_index = null, | |
| 8573 | .fields_len = 0, | |
| 8574 | .field_name_map = undefined, | |
| 8575 | .field_names_start = undefined, | |
| 8576 | .field_comptime_bits_start = undefined, | |
| 8936 | .field_names = undefined, | |
| 8937 | .field_types = undefined, | |
| 8938 | .field_values = undefined, | |
| 8939 | .field_aligns = undefined, | |
| 8940 | .field_is_comptime_bits = undefined, | |
| 8577 | 8941 | } }; |
| 8578 | 8942 | } |
| 8579 | 8943 | |
| ... | ... | @@ -8584,12 +8948,15 @@ pub const WipContainerType = struct { |
| 8584 | 8948 | name_nav_index: u32, |
| 8585 | 8949 | namespace_index: u32, |
| 8586 | 8950 | |
| 8587 | tag_type_index: ?u32, | |
| 8588 | ||
| 8589 | fields_len: u32, | |
| 8590 | field_name_map: MapIndex, | |
| 8591 | field_names_start: u32, | |
| 8592 | field_comptime_bits_start: ?u32, | |
| 8951 | // These fields are only populated when creating reified types, because reified types populate | |
| 8952 | // field information immediately, with type resolution only handling validation. This is in | |
| 8953 | // contrast to declared types, where field information is populated by the type resolution | |
| 8954 | // process evaluating ZIR expressions. | |
| 8955 | field_names: NullTerminatedString.Slice, | |
| 8956 | field_types: Index.Slice, | |
| 8957 | field_values: Index.Slice, | |
| 8958 | field_aligns: Alignment.Slice, | |
| 8959 | field_is_comptime_bits: LoadedStructType.ComptimeBits, | |
| 8593 | 8960 | |
| 8594 | 8961 | pub fn setName( |
| 8595 | 8962 | wip: WipContainerType, |
| ... | ... | @@ -8605,48 +8972,6 @@ pub const WipContainerType = struct { |
| 8605 | 8972 | extra_items[wip.name_nav_index] = @intFromEnum(name_nav); |
| 8606 | 8973 | } |
| 8607 | 8974 | |
| 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 | 8975 | pub fn finish( |
| 8651 | 8976 | wip: WipContainerType, |
| 8652 | 8977 | ip: *InternPool, |
| ... | ... | @@ -8657,14 +8982,6 @@ pub const WipContainerType = struct { |
| 8657 | 8982 | |
| 8658 | 8983 | extra_items[wip.namespace_index] = @intFromEnum(namespace); |
| 8659 | 8984 | |
| 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 | 8985 | return wip.index; |
| 8669 | 8986 | } |
| 8670 | 8987 | |
| ... | ... | @@ -9504,19 +9821,6 @@ fn addStringsToMap( |
| 9504 | 9821 | } |
| 9505 | 9822 | } |
| 9506 | 9823 | |
| 9507 | fn 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 | ||
| 9520 | 9824 | fn addMap(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, cap: usize) Allocator.Error!MapIndex { |
| 9521 | 9825 | const maps = ip.getLocal(tid).getMutableMaps(gpa, io); |
| 9522 | 9826 | const unwrapped: MapIndex.Unwrapped = .{ .tid = tid, .index = maps.mutate.len }; |
| ... | ... | @@ -10260,10 +10564,78 @@ pub fn dump(ip: *const InternPool) void { |
| 10260 | 10564 | const stderr = std.debug.lockStderr(&buffer); |
| 10261 | 10565 | defer std.debug.unlockStderr(); |
| 10262 | 10566 | const w = &stderr.file_writer.interface; |
| 10567 | dumpDependencyStatsFallible(ip, w) catch return; | |
| 10263 | 10568 | dumpStatsFallible(ip, w, std.heap.page_allocator) catch return; |
| 10264 | 10569 | dumpAllFallible(ip, w) catch return; |
| 10265 | 10570 | } |
| 10266 | 10571 | |
| 10572 | fn 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 | ||
| 10267 | 10639 | fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !void { |
| 10268 | 10640 | var items_len: usize = 0; |
| 10269 | 10641 | var extra_len: usize = 0; |
| ... | ... | @@ -10278,10 +10650,10 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo |
| 10278 | 10650 | const limbs_size = 8 * limbs_len; |
| 10279 | 10651 | |
| 10280 | 10652 | // 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; | |
| 10282 | 10654 | |
| 10283 | std.debug.print( | |
| 10284 | \\InternPool size: {d} bytes | |
| 10655 | try w.print( | |
| 10656 | \\InternPool values: {d} bytes | |
| 10285 | 10657 | \\ {d} items: {d} bytes |
| 10286 | 10658 | \\ {d} extra: {d} bytes |
| 10287 | 10659 | \\ {d} limbs: {d} bytes |
| ... | ... | @@ -10302,6 +10674,8 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo |
| 10302 | 10674 | }; |
| 10303 | 10675 | var counts = std.AutoArrayHashMap(Tag, TagStats).init(arena); |
| 10304 | 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 | 10679 | const items = local.shared.items.view().slice(); |
| 10306 | 10680 | const extra_list = local.shared.extra; |
| 10307 | 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 | 10936 | |
| 10563 | 10937 | fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void { |
| 10564 | 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 | 10941 | const items = local.shared.items.view(); |
| 10566 | 10942 | for ( |
| 10567 | 10943 | items.items(.tag)[0..local.mutate.items.len], |
| ... | ... | @@ -11981,22 +12357,42 @@ pub fn unwrapCoercedFunc(ip: *const InternPool, index: Index) Index { |
| 11981 | 12357 | }; |
| 11982 | 12358 | } |
| 11983 | 12359 | |
| 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. | |
| 11985 | 12363 | pub fn addFieldName( |
| 11986 | 12364 | ip: *InternPool, |
| 11987 | extra: Local.Extra, | |
| 11988 | names_map: MapIndex, | |
| 11989 | names_start: u32, | |
| 12365 | names: NullTerminatedString.Slice, | |
| 12366 | map: MapIndex, | |
| 11990 | 12367 | name: NullTerminatedString, |
| 11991 | 12368 | ) ?u32 { |
| 11992 | const extra_items = extra.view().items(.@"0"); | |
| 11993 | const map = names_map.get(ip); | |
| 11994 | const field_index = map.count(); | |
| 11995 | const strings = extra_items[names_start..][0..field_index]; | |
| 11996 | const adapter: NullTerminatedString.Adapter = .{ .strings = @ptrCast(strings) }; | |
| 11997 | const gop = map.getOrPutAssumeCapacityAdapted(name, adapter); | |
| 12369 | const m = map.get(ip); | |
| 12370 | const field_idx = m.count(); | |
| 12371 | const names_slice = names.get(ip); | |
| 12372 | names_slice[field_idx] = name; | |
| 12373 | const adapter: NullTerminatedString.Adapter = .{ .strings = names_slice[0..field_idx] }; | |
| 12374 | const gop = m.getOrPutAssumeCapacityAdapted(name, adapter); | |
| 11998 | 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. | |
| 12382 | pub 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 | 12396 | return null; |
| 12001 | 12397 | } |
| 12002 | 12398 | |
| ... | ... | @@ -12295,6 +12691,7 @@ pub fn resolveStructLayout( |
| 12295 | 12691 | has_no_possible_value: bool, |
| 12296 | 12692 | has_one_possible_value: bool, |
| 12297 | 12693 | comptime_only: bool, |
| 12694 | has_runtime_bits: bool, | |
| 12298 | 12695 | ) void { |
| 12299 | 12696 | const unwrapped_index = struct_type.unwrap(ip); |
| 12300 | 12697 | |
| ... | ... | @@ -12311,6 +12708,7 @@ pub fn resolveStructLayout( |
| 12311 | 12708 | flags.has_no_possible_value = has_no_possible_value; |
| 12312 | 12709 | flags.has_one_possible_value = has_one_possible_value; |
| 12313 | 12710 | flags.comptime_only = comptime_only; |
| 12711 | flags.has_runtime_bits = has_runtime_bits; | |
| 12314 | 12712 | flags.alignment = alignment; |
| 12315 | 12713 | } |
| 12316 | 12714 | |
| ... | ... | @@ -12322,12 +12720,14 @@ pub fn resolveUnionLayout( |
| 12322 | 12720 | ip: *InternPool, |
| 12323 | 12721 | io: Io, |
| 12324 | 12722 | union_type: Index, |
| 12723 | enum_tag_type: Index, | |
| 12325 | 12724 | size: u32, |
| 12326 | 12725 | padding: u32, |
| 12327 | 12726 | alignment: Alignment, |
| 12328 | 12727 | has_no_possible_value: bool, |
| 12329 | 12728 | has_one_possible_value: bool, |
| 12330 | 12729 | comptime_only: bool, |
| 12730 | has_runtime_bits: bool, | |
| 12331 | 12731 | ) void { |
| 12332 | 12732 | const unwrapped_index = union_type.unwrap(ip); |
| 12333 | 12733 | |
| ... | ... | @@ -12339,17 +12739,24 @@ pub fn resolveUnionLayout( |
| 12339 | 12739 | const item = unwrapped_index.getItem(ip); |
| 12340 | 12740 | assert(item.tag == .type_union); |
| 12341 | 12741 | |
| 12742 | extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "enum_tag_type").?] = @intFromEnum(enum_tag_type); | |
| 12342 | 12743 | extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "size").?] = size; |
| 12343 | 12744 | extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "padding").?] = padding; |
| 12344 | 12745 | const flags: *Tag.TypeUnion.Flags = @ptrCast(&extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "flags").?]); |
| 12345 | 12746 | flags.has_no_possible_value = has_no_possible_value; |
| 12346 | 12747 | flags.has_one_possible_value = has_one_possible_value; |
| 12347 | 12748 | flags.comptime_only = comptime_only; |
| 12749 | flags.has_runtime_bits = has_runtime_bits; | |
| 12348 | 12750 | flags.alignment = alignment; |
| 12349 | 12751 | } |
| 12350 | 12752 | |
| 12351 | 12753 | /// Asserts that `struct_type` is a packed struct type. |
| 12352 | pub fn resolvePackedStructBackingInt(ip: *InternPool, io: Io, struct_type: Index, backing_int_type: Index) void { | |
| 12754 | pub fn resolvePackedStructLayout( | |
| 12755 | ip: *InternPool, | |
| 12756 | io: Io, | |
| 12757 | struct_type: Index, | |
| 12758 | backing_int_type: Index, | |
| 12759 | ) void { | |
| 12353 | 12760 | const unwrapped_index = struct_type.unwrap(ip); |
| 12354 | 12761 | |
| 12355 | 12762 | const local = ip.getLocal(unwrapped_index.tid); |
| ... | ... | @@ -12371,7 +12778,13 @@ pub fn resolvePackedStructBackingInt(ip: *InternPool, io: Io, struct_type: Index |
| 12371 | 12778 | } |
| 12372 | 12779 | |
| 12373 | 12780 | /// Asserts that `union_type` is a packed union type. |
| 12374 | pub fn resolvePackedUnionBackingInt(ip: *InternPool, io: Io, union_type: Index, backing_int_type: Index) void { | |
| 12781 | pub 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 | 12788 | const unwrapped_index = union_type.unwrap(ip); |
| 12376 | 12789 | |
| 12377 | 12790 | const local = ip.getLocal(unwrapped_index.tid); |
| ... | ... | @@ -12387,5 +12800,32 @@ pub fn resolvePackedUnionBackingInt(ip: *InternPool, io: Io, union_type: Index, |
| 12387 | 12800 | else => unreachable, |
| 12388 | 12801 | } |
| 12389 | 12802 | |
| 12803 | extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnionPacked, "enum_tag_type").?] = @intFromEnum(enum_tag_type); | |
| 12390 | 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. | |
| 12808 | pub 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 | 397 | /// The name of the current "context" for naming namespace types. |
| 398 | 398 | /// The interpretation of this depends on the name strategy in ZIR, but the name |
| 399 | 399 | /// is always incorporated into the type name somehow. |
| 400 | /// See `Sema.createTypeName`. | |
| 400 | /// See `Sema.setTypeName`. | |
| 401 | 401 | type_name_ctx: InternPool.NullTerminatedString, |
| 402 | 402 | |
| 403 | 403 | /// Create a `LazySrcLoc` based on an `Offset` from the code being analyzed in this block. |
| ... | ... | @@ -1158,7 +1158,7 @@ fn analyzeBodyInner( |
| 1158 | 1158 | }, inst }); |
| 1159 | 1159 | } |
| 1160 | 1160 | |
| 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 | 1162 | // zig fmt: off |
| 1163 | 1163 | .alloc => try sema.zirAlloc(block, inst), |
| 1164 | 1164 | .alloc_inferred => try sema.zirAllocInferred(block, true), |
| ... | ... | @@ -1991,31 +1991,33 @@ fn analyzeBodyInner( |
| 1991 | 1991 | break :blk .void_value; |
| 1992 | 1992 | }, |
| 1993 | 1993 | }; |
| 1994 | if (sema.isNoReturn(air_inst)) { | |
| 1994 | if (sema.isNoReturn(air_ref)) { | |
| 1995 | 1995 | // We're going to assume that the body itself is noreturn, so let's ensure that now |
| 1996 | 1996 | assert(block.instructions.items.len > 0); |
| 1997 | 1997 | assert(sema.isNoReturn(block.instructions.items[block.instructions.items.len - 1].toRef())); |
| 1998 | 1998 | break; |
| 1999 | 1999 | } |
| 2000 | // <MLUGG TODO REMOVE THIS BLOCK, SILLY OPV CHECK> | |
| 2001 | if (air_inst.toIndex()) |air_inst_index| { | |
| 2002 | switch (sema.air_instructions.items(.tag)[@intFromEnum(air_inst_index)]) { | |
| 2003 | .inferred_alloc, .inferred_alloc_comptime => {}, | |
| 2004 | else => { | |
| 2005 | assert(sema.typeOf(air_inst).onePossibleValue(pt) catch @panic("") == null); | |
| 2006 | sema.typeOf(air_inst).assertHasLayout(zcu); | |
| 2007 | }, | |
| 2008 | } | |
| 2009 | } else { | |
| 2010 | switch (tags[@intFromEnum(inst)]) { | |
| 2011 | // MLUGG TODO: do we actually *want* this exception? we could arguably simplify things without it | |
| 2012 | // e.g. analyzeNavVal could stop doing ensureLayoutResolved in most cases (`extern` is an exception) and instead do `assertHasLayout` | |
| 2013 | .func, .func_inferred, .func_fancy => {}, // exception: we're in a func decl, layout will get resolved in a bit by `analyzeNavVal` | |
| 2014 | else => sema.typeOf(air_inst).assertHasLayout(zcu), | |
| 2000 | ||
| 2001 | // We must resolve the layout of a type before creating a value of that type. Therefore, | |
| 2002 | // the layout of the type of `air_ref` must already be resolved. | |
| 2003 | check_type: { | |
| 2004 | if (air_ref.toIndex()) |air_inst| switch (sema.air_instructions.items(.tag)[@intFromEnum(air_inst)]) { | |
| 2005 | .inferred_alloc, .inferred_alloc_comptime => break :check_type, | |
| 2006 | else => {}, | |
| 2007 | }; | |
| 2008 | sema.typeOf(air_ref).assertHasLayout(zcu); | |
| 2009 | // If the type has an OPV, `air_ref` must be that OPV: there is no other interned value | |
| 2010 | // it could be, and it would be a bug for the value to not be comptime-known when it has | |
| 2011 | // an OPV. Behind a `std.debug.runtime_safety` check because `onePossibleValue` mutates | |
| 2012 | // the InternPool so cannot be optimized out. | |
| 2013 | if (std.debug.runtime_safety) { | |
| 2014 | if (try sema.typeOf(air_ref).onePossibleValue(pt)) |opv| { | |
| 2015 | assert(air_ref == Air.Inst.Ref.fromValue(opv)); | |
| 2016 | } | |
| 2015 | 2017 | } |
| 2016 | 2018 | } |
| 2017 | // </MLUGG TODO REMOVE THIS BLOCK, SILLY OPV CHECK> | |
| 2018 | map.putAssumeCapacity(inst, air_inst); | |
| 2019 | ||
| 2020 | map.putAssumeCapacity(inst, air_ref); | |
| 2019 | 2021 | i += 1; |
| 2020 | 2022 | } |
| 2021 | 2023 | } |
| ... | ... | @@ -2097,7 +2099,7 @@ pub fn resolveConstStringIntern( |
| 2097 | 2099 | |
| 2098 | 2100 | fn resolveTypeOrPoison(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) !?Type { |
| 2099 | 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 | 2103 | if (ty.isGenericPoison()) return null; |
| 2102 | 2104 | return ty; |
| 2103 | 2105 | } |
| ... | ... | @@ -2216,11 +2218,12 @@ pub fn analyzeAsType( |
| 2216 | 2218 | sema: *Sema, |
| 2217 | 2219 | block: *Block, |
| 2218 | 2220 | src: LazySrcLoc, |
| 2221 | reason: std.zig.SimpleComptimeReason, | |
| 2219 | 2222 | air_inst: Air.Inst.Ref, |
| 2220 | 2223 | ) !Type { |
| 2221 | 2224 | const wanted_type: Type = .type; |
| 2222 | 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 | 2227 | return val.toType(); |
| 2225 | 2228 | } |
| 2226 | 2229 | |
| ... | ... | @@ -4112,9 +4115,11 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 4112 | 4115 | /// or error union pointed to, initializing these pointers along the way. |
| 4113 | 4116 | /// Given a `*E!?T`, returns a (valid) `*T`. |
| 4114 | 4117 | /// May invalidate already-stored payload data. |
| 4118 | /// Asserts that the layout of the pointer child type is already resolved. | |
| 4115 | 4119 | fn optEuBasePtrInit(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, src: LazySrcLoc) CompileError!Air.Inst.Ref { |
| 4116 | 4120 | const pt = sema.pt; |
| 4117 | 4121 | const zcu = pt.zcu; |
| 4122 | sema.typeOf(ptr).childType(zcu).assertHasLayout(zcu); | |
| 4118 | 4123 | var base_ptr = ptr; |
| 4119 | 4124 | while (true) switch (sema.typeOf(base_ptr).childType(zcu).zigTypeTag(zcu)) { |
| 4120 | 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 | 4133 | fn zirOptEuBasePtrInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 4129 | 4134 | const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; |
| 4130 | 4135 | const ptr = try sema.resolveInst(un_node.operand); |
| 4136 | try sema.ensureLayoutResolved(sema.typeOf(ptr).childType(sema.pt.zcu)); | |
| 4131 | 4137 | return sema.optEuBasePtrInit(block, ptr, block.nodeOffset(un_node.src_node)); |
| 4132 | 4138 | } |
| 4133 | 4139 | |
| ... | ... | @@ -4513,7 +4519,7 @@ fn validateStructInit( |
| 4513 | 4519 | if (struct_ty.structFieldIsComptime(i, zcu)) continue; |
| 4514 | 4520 | |
| 4515 | 4521 | if (!struct_ty.isTuple(zcu)) { |
| 4516 | try sema.ensureFieldInitsResolved(struct_ty); | |
| 4522 | try sema.ensureStructDefaultsResolved(struct_ty); | |
| 4517 | 4523 | } |
| 4518 | 4524 | |
| 4519 | 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 | 5743 | } |
| 5738 | 5744 | if (zcu.llvm_object != null and options.linkage == .internal) return; |
| 5739 | 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 | 5747 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 5742 | 5748 | const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)}); |
| 5743 | 5749 | errdefer msg.destroy(sema.gpa); |
| ... | ... | @@ -5789,7 +5795,7 @@ pub fn analyzeExport( |
| 5789 | 5795 | const exported_nav = ip.getNav(exported_nav_index); |
| 5790 | 5796 | const export_ty: Type = .fromInterned(exported_nav.typeOf(ip)); |
| 5791 | 5797 | |
| 5792 | if (!try sema.validateExternType(export_ty, .other)) { | |
| 5798 | if (!export_ty.validateExtern(.other, zcu)) { | |
| 5793 | 5799 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 5794 | 5800 | const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)}); |
| 5795 | 5801 | errdefer msg.destroy(gpa); |
| ... | ... | @@ -5827,7 +5833,7 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void { |
| 5827 | 5833 | .nav_val, |
| 5828 | 5834 | .nav_ty, |
| 5829 | 5835 | .type_layout, |
| 5830 | .type_inits, | |
| 5836 | .struct_defaults, | |
| 5831 | 5837 | .memoized_state, |
| 5832 | 5838 | => return, // does nothing outside a function |
| 5833 | 5839 | }; |
| ... | ... | @@ -5846,7 +5852,7 @@ fn zirDisableIntrinsics(sema: *Sema) CompileError!void { |
| 5846 | 5852 | .nav_val, |
| 5847 | 5853 | .nav_ty, |
| 5848 | 5854 | .type_layout, |
| 5849 | .type_inits, | |
| 5855 | .struct_defaults, | |
| 5850 | 5856 | .memoized_state, |
| 5851 | 5857 | => return, // does nothing outside a function |
| 5852 | 5858 | }; |
| ... | ... | @@ -6729,8 +6735,28 @@ fn analyzeCall( |
| 6729 | 6735 | } else func_src; |
| 6730 | 6736 | |
| 6731 | 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*... | |
| 6733 | const func_is_generic = !func_ty.fnHasRuntimeBits(zcu); | |
| 6738 | const any_comptime_params = func_ty_info.comptime_bits != 0 or ct: { | |
| 6739 | for (func_ty_info.param_types.get(ip)) |param_ty| { | |
| 6740 | if (Type.fromInterned(param_ty).comptimeOnly(zcu)) break :ct true; | |
| 6741 | } | |
| 6742 | break :ct Type.fromInterned(func_ty_info.return_type).comptimeOnly(zcu); | |
| 6743 | }; | |
| 6744 | const any_generic_types = generic: { | |
| 6745 | for (func_ty_info.param_types.get(ip)) |param_ty| { | |
| 6746 | if (param_ty == .generic_poison_type) break :generic true; | |
| 6747 | } | |
| 6748 | const ret_ty: Type = .fromInterned(func_ty_info.return_type); | |
| 6749 | if (ret_ty.toIntern() == .generic_poison_type) { | |
| 6750 | break :generic true; | |
| 6751 | } | |
| 6752 | if (ret_ty.zigTypeTag(zcu) == .error_union and | |
| 6753 | ret_ty.errorUnionPayload(zcu).toIntern() == .generic_poison_type) | |
| 6754 | { | |
| 6755 | break :generic true; | |
| 6756 | } | |
| 6757 | break :generic false; | |
| 6758 | }; | |
| 6759 | ||
| 6734 | 6760 | if (!callConvIsCallable(func_ty_info.cc)) { |
| 6735 | 6761 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 6736 | 6762 | const msg = try sema.errMsg( |
| ... | ... | @@ -6766,7 +6792,7 @@ fn analyzeCall( |
| 6766 | 6792 | else => unreachable, |
| 6767 | 6793 | } else .{ null, false }; |
| 6768 | 6794 | |
| 6769 | if (func_is_generic and func_val == null) { | |
| 6795 | if ((any_generic_types or any_comptime_params) and func_val == null) { | |
| 6770 | 6796 | return sema.failWithNeededComptime(block, func_src, .{ .simple = .generic_call_target }); |
| 6771 | 6797 | } |
| 6772 | 6798 | |
| ... | ... | @@ -6815,13 +6841,13 @@ fn analyzeCall( |
| 6815 | 6841 | // This is the `inst_map` used when evaluating generic parameters and return types. |
| 6816 | 6842 | var generic_inst_map: InstMap = .{}; |
| 6817 | 6843 | defer generic_inst_map.deinit(gpa); |
| 6818 | if (func_is_generic) { | |
| 6844 | if (any_generic_types) { | |
| 6819 | 6845 | try generic_inst_map.ensureSpaceForInstructions(gpa, fn_zir_info.param_body); |
| 6820 | 6846 | } |
| 6821 | 6847 | |
| 6822 | 6848 | // This exists so that `generic_block` below can include a "called from here" note back to this |
| 6823 | 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 | 6851 | .call_block = block, |
| 6826 | 6852 | .call_src = call_src, |
| 6827 | 6853 | .func = func_val.?.toIntern(), |
| ... | ... | @@ -6834,7 +6860,7 @@ fn analyzeCall( |
| 6834 | 6860 | // This is the block in which we evaluate generic function components: that is, generic parameter |
| 6835 | 6861 | // types and the generic return type. This must not be used if the function is not generic. |
| 6836 | 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 | 6864 | .parent = null, |
| 6839 | 6865 | .sema = sema, |
| 6840 | 6866 | .namespace = fn_nav.analysis.?.namespace, |
| ... | ... | @@ -6843,9 +6869,9 @@ fn analyzeCall( |
| 6843 | 6869 | .src_base_inst = fn_nav.analysis.?.zir_index, |
| 6844 | 6870 | .type_name_ctx = fn_nav.fqn, |
| 6845 | 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); | |
| 6847 | 6873 | |
| 6848 | if (func_is_generic) { | |
| 6874 | if (any_generic_types) { | |
| 6849 | 6875 | // We certainly depend on the generic owner's signature! |
| 6850 | 6876 | try sema.declareDependency(.{ .src_hash = fn_tracked_inst }); |
| 6851 | 6877 | } |
| ... | ... | @@ -6857,7 +6883,7 @@ fn analyzeCall( |
| 6857 | 6883 | if (raw != .generic_poison_type) break :ty .fromInterned(raw); |
| 6858 | 6884 | |
| 6859 | 6885 | // We must discover the generic parameter type. |
| 6860 | assert(func_is_generic); | |
| 6886 | assert(any_generic_types); | |
| 6861 | 6887 | const param_inst_idx = fn_zir_info.param_body[arg_idx]; |
| 6862 | 6888 | const param_inst = fn_zir.instructions.get(@intFromEnum(param_inst_idx)); |
| 6863 | 6889 | switch (param_inst.tag) { |
| ... | ... | @@ -6888,7 +6914,7 @@ fn analyzeCall( |
| 6888 | 6914 | } }; |
| 6889 | 6915 | |
| 6890 | 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); | |
| 6892 | 6918 | |
| 6893 | 6919 | if (!param_ty.isValidParamType(zcu)) { |
| 6894 | 6920 | const opaque_str = if (param_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else ""; |
| ... | ... | @@ -6906,7 +6932,7 @@ fn analyzeCall( |
| 6906 | 6932 | return arg.*; // terminate analysis here |
| 6907 | 6933 | } |
| 6908 | 6934 | |
| 6909 | if (func_is_generic) { | |
| 6935 | if (any_generic_types) { | |
| 6910 | 6936 | // We need to put the argument into `generic_inst_map` so that other parameters can refer to it. |
| 6911 | 6937 | const param_inst_idx = fn_zir_info.param_body[arg_idx]; |
| 6912 | 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 | 6974 | // calls (where it should be the IES of the instantiation). However, it's how we print this |
| 6949 | 6975 | // in error messages. |
| 6950 | 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); | |
| 6952 | 6978 | |
| 6953 | 6979 | const maybe_poison_bare = if (fn_zir_info.inferred_error_set) maybe_poison: { |
| 6954 | 6980 | break :maybe_poison ip.errorUnionPayload(func_ty_info.return_type); |
| ... | ... | @@ -6958,7 +6984,7 @@ fn analyzeCall( |
| 6958 | 6984 | |
| 6959 | 6985 | // Evaluate the generic return type. As with generic parameters, we switch out `sema.code` and `sema.inst_map`. |
| 6960 | 6986 | |
| 6961 | assert(func_is_generic); | |
| 6987 | assert(any_generic_types); | |
| 6962 | 6988 | |
| 6963 | 6989 | const old_code = sema.code; |
| 6964 | 6990 | const old_inst_map = sema.inst_map; |
| ... | ... | @@ -6981,7 +7007,7 @@ fn analyzeCall( |
| 6981 | 7007 | } else bare: { |
| 6982 | 7008 | assert(fn_zir_info.ret_ty_body.len != 0); |
| 6983 | 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 | 7012 | assert(bare_ty.toIntern() != .generic_poison_type); |
| 6987 | 7013 | |
| ... | ... | @@ -7035,7 +7061,7 @@ fn analyzeCall( |
| 7035 | 7061 | }); |
| 7036 | 7062 | if (func_ty_info.cc == .auto) { |
| 7037 | 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 | 7065 | .func => |owner_func| ip.funcSetHasErrorTrace(io, owner_func, true), |
| 7040 | 7066 | } |
| 7041 | 7067 | } |
| ... | ... | @@ -7043,7 +7069,7 @@ fn analyzeCall( |
| 7043 | 7069 | try sema.validateRuntimeValue(block, args_info.argSrc(block, arg_idx), arg); |
| 7044 | 7070 | } |
| 7045 | 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 }; | |
| 7047 | 7073 | |
| 7048 | 7074 | // Instantiate the generic function! |
| 7049 | 7075 | |
| ... | ... | @@ -7512,9 +7538,7 @@ fn zirArrayInitElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil |
| 7512 | 7538 | assert(indexable_ty.isIndexable(zcu)); // validated by a previous instruction |
| 7513 | 7539 | const elem_ty = switch (indexable_ty.zigTypeTag(zcu)) { |
| 7514 | 7540 | .@"struct" => indexable_ty.fieldType(@intFromEnum(bin.rhs), zcu), |
| 7515 | .array, .vector => indexable_ty.childType(zcu), | |
| 7516 | .pointer => indexable_ty.indexablePtrElem(zcu), | |
| 7517 | else => unreachable, | |
| 7541 | else => indexable_ty.indexableElem(zcu), | |
| 7518 | 7542 | }; |
| 7519 | 7543 | return .fromType(elem_ty); |
| 7520 | 7544 | } |
| ... | ... | @@ -7835,8 +7859,8 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr |
| 7835 | 7859 | }; |
| 7836 | 7860 | return sema.failWithOwnedErrorMsg(block, msg); |
| 7837 | 7861 | } |
| 7838 | const lhs_ty = try sema.analyzeAsType(block, lhs_src, lhs); | |
| 7839 | const rhs_ty = try sema.analyzeAsType(block, rhs_src, rhs); | |
| 7862 | const lhs_ty = try sema.analyzeAsType(block, lhs_src, .type, lhs); | |
| 7863 | const rhs_ty = try sema.analyzeAsType(block, rhs_src, .type, rhs); | |
| 7840 | 7864 | if (lhs_ty.zigTypeTag(zcu) != .error_set) |
| 7841 | 7865 | return sema.fail(block, lhs_src, "expected error set type, found '{f}'", .{lhs_ty.fmt(pt)}); |
| 7842 | 7866 | if (rhs_ty.zigTypeTag(zcu) != .error_set) |
| ... | ... | @@ -8017,12 +8041,13 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 8017 | 8041 | if (dest_ty.zigTypeTag(zcu) != .@"enum") { |
| 8018 | 8042 | return sema.fail(block, src, "expected enum, found '{f}'", .{dest_ty.fmt(pt)}); |
| 8019 | 8043 | } |
| 8044 | try sema.ensureLayoutResolved(dest_ty); | |
| 8020 | 8045 | _ = try sema.checkIntType(block, operand_src, operand_ty); |
| 8021 | 8046 | |
| 8022 | 8047 | if (try sema.resolveValue(operand)) |int_val| { |
| 8023 | 8048 | if (dest_ty.isNonexhaustiveEnum(zcu)) { |
| 8024 | 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 | 8051 | return Air.internedToRef((try pt.getCoerced(int_val, dest_ty)).toIntern()); |
| 8027 | 8052 | } |
| 8028 | 8053 | return sema.fail(block, src, "int value '{f}' out of range of non-exhaustive enum '{f}'", .{ |
| ... | ... | @@ -8077,10 +8102,14 @@ fn zirOptionalPayloadPtr( |
| 8077 | 8102 | const optional_ptr = try sema.resolveInst(inst_data.operand); |
| 8078 | 8103 | const src = block.nodeOffset(inst_data.src_node); |
| 8079 | 8104 | |
| 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 | 8109 | return sema.analyzeOptionalPayloadPtr(block, src, optional_ptr, safety_check, false); |
| 8081 | 8110 | } |
| 8082 | 8111 | |
| 8083 | /// MLUGG TODO: pre-resolved child? | |
| 8112 | /// Asserts that the layout of the pointer child type is already resolved. | |
| 8084 | 8113 | fn analyzeOptionalPayloadPtr( |
| 8085 | 8114 | sema: *Sema, |
| 8086 | 8115 | block: *Block, |
| ... | ... | @@ -8095,12 +8124,12 @@ fn analyzeOptionalPayloadPtr( |
| 8095 | 8124 | assert(optional_ptr_ty.zigTypeTag(zcu) == .pointer); |
| 8096 | 8125 | |
| 8097 | 8126 | const opt_type = optional_ptr_ty.childType(zcu); |
| 8127 | opt_type.assertHasLayout(zcu); | |
| 8098 | 8128 | if (opt_type.zigTypeTag(zcu) != .optional) { |
| 8099 | 8129 | return sema.failWithExpectedOptionalType(block, src, opt_type); |
| 8100 | 8130 | } |
| 8101 | 8131 | |
| 8102 | 8132 | const child_type = opt_type.optionalChild(zcu); |
| 8103 | try sema.ensureLayoutResolved(child_type); | |
| 8104 | 8133 | const child_pointer = try pt.ptrType(.{ |
| 8105 | 8134 | .child = child_type.toIntern(), |
| 8106 | 8135 | .flags = .{ |
| ... | ... | @@ -8283,10 +8312,14 @@ fn zirErrUnionPayloadPtr( |
| 8283 | 8312 | const operand = try sema.resolveInst(inst_data.operand); |
| 8284 | 8313 | const src = block.nodeOffset(inst_data.src_node); |
| 8285 | 8314 | |
| 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 | 8319 | return sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false); |
| 8287 | 8320 | } |
| 8288 | 8321 | |
| 8289 | /// MLUGG TODO LAYOUT: already-resolved child? | |
| 8322 | /// Asserts that the layout of the pointer child type is already resolved. | |
| 8290 | 8323 | fn analyzeErrUnionPayloadPtr( |
| 8291 | 8324 | sema: *Sema, |
| 8292 | 8325 | block: *Block, |
| ... | ... | @@ -8307,8 +8340,8 @@ fn analyzeErrUnionPayloadPtr( |
| 8307 | 8340 | } |
| 8308 | 8341 | |
| 8309 | 8342 | const err_union_ty = operand_ty.childType(zcu); |
| 8343 | err_union_ty.assertHasLayout(zcu); | |
| 8310 | 8344 | const payload_ty = err_union_ty.errorUnionPayload(zcu); |
| 8311 | try sema.ensureLayoutResolved(payload_ty); | |
| 8312 | 8345 | const operand_pointer_ty = try pt.ptrType(.{ |
| 8313 | 8346 | .child = payload_ty.toIntern(), |
| 8314 | 8347 | .flags = .{ |
| ... | ... | @@ -8744,7 +8777,7 @@ fn checkParamTypeCommon( |
| 8744 | 8777 | } |
| 8745 | 8778 | if (!param_ty.isGenericPoison() and |
| 8746 | 8779 | !target_util.fnCallConvAllowsZigTypes(cc) and |
| 8747 | !try sema.validateExternType(param_ty, .param_ty)) | |
| 8780 | !param_ty.validateExtern(.param_ty, zcu)) | |
| 8748 | 8781 | { |
| 8749 | 8782 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 8750 | 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 | 8851 | } |
| 8819 | 8852 | if (!bare_ret_ty.isGenericPoison() and |
| 8820 | 8853 | !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 | 8856 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 8824 | 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 | 9075 | |
| 9043 | 9076 | if (inferred_error_set) { |
| 9044 | 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 | 9079 | .owner_nav = sema.owner.unwrap().nav_val, |
| 9047 | 9080 | |
| 9048 | 9081 | .param_types = param_types, |
| ... | ... | @@ -9059,6 +9092,8 @@ fn funcCommon( |
| 9059 | 9092 | .lbrace_column = @as(u16, @truncate(src_locs.columns)), |
| 9060 | 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 | } |
| 9063 | 9098 | |
| 9064 | 9099 | const func_ty = try ip.getFuncType(gpa, io, pt.tid, .{ |
| ... | ... | @@ -9072,6 +9107,7 @@ fn funcCommon( |
| 9072 | 9107 | }); |
| 9073 | 9108 | |
| 9074 | 9109 | if (has_body) { |
| 9110 | try sema.ensureLayoutResolved(.fromInterned(func_ty)); | |
| 9075 | 9111 | return .fromIntern(try ip.getFuncDecl(gpa, io, pt.tid, .{ |
| 9076 | 9112 | .owner_nav = sema.owner.unwrap().nav_val, |
| 9077 | 9113 | .ty = func_ty, |
| ... | ... | @@ -9109,7 +9145,7 @@ fn zirParam( |
| 9109 | 9145 | } |
| 9110 | 9146 | |
| 9111 | 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 | }; |
| 9114 | 9150 | |
| 9115 | 9151 | try block.params.append(sema.arena, .{ |
| ... | ... | @@ -9948,6 +9984,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp |
| 9948 | 9984 | err_union_ty.fmt(pt), |
| 9949 | 9985 | }); |
| 9950 | 9986 | } |
| 9987 | try sema.ensureLayoutResolved(err_union_ty); | |
| 9951 | 9988 | |
| 9952 | 9989 | const non_err_cond = if (non_err_case.operand_is_ref) |
| 9953 | 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 | 12961 | const res_ty: InternPool.Index = b: { |
| 12925 | 12962 | if (extra.res_ty == .none) break :b .none; |
| 12926 | 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 | 12965 | if (res_ty.isGenericPoison()) break :b .none; |
| 12929 | 12966 | break :b res_ty.toIntern(); |
| 12930 | 12967 | }; |
| ... | ... | @@ -15683,8 +15720,8 @@ fn zirCmpEq( |
| 15683 | 15720 | return block.addBinOp(air_tag, lhs, rhs); |
| 15684 | 15721 | } |
| 15685 | 15722 | if (lhs_ty_tag == .type and rhs_ty_tag == .type) { |
| 15686 | const lhs_as_type = try sema.analyzeAsType(block, lhs_src, lhs); | |
| 15687 | const rhs_as_type = try sema.analyzeAsType(block, rhs_src, rhs); | |
| 15723 | const lhs_as_type = try sema.analyzeAsType(block, lhs_src, .type, lhs); | |
| 15724 | const rhs_as_type = try sema.analyzeAsType(block, rhs_src, .type, rhs); | |
| 15688 | 15725 | return if (lhs_as_type.eql(rhs_as_type, zcu) == (op == .eq)) .bool_true else .bool_false; |
| 15689 | 15726 | } |
| 15690 | 15727 | return sema.analyzeCmp(block, src, lhs, rhs, op, lhs_src, rhs_src, true); |
| ... | ... | @@ -15979,16 +16016,7 @@ fn zirThis( |
| 15979 | 16016 | extended: Zir.Inst.Extended.InstData, |
| 15980 | 16017 | ) CompileError!Air.Inst.Ref { |
| 15981 | 16018 | _ = extended; |
| 15982 | const zcu = sema.pt.zcu; | |
| 15983 | const namespace = zcu.namespacePtr(block.namespace); | |
| 15984 | ||
| 15985 | switch (zcu.intern_pool.indexToKey(namespace.owner_type)) { | |
| 15986 | .opaque_type, .struct_type, .union_type => {}, | |
| 15987 | // Enum inits are resolved eagerly. TODO MLUGG: honestly i don't think they SHOULD be lol | |
| 15988 | .enum_type => try sema.ensureFieldInitsResolved(.fromInterned(namespace.owner_type)), | |
| 15989 | else => unreachable, | |
| 15990 | } | |
| 15991 | return .fromIntern(namespace.owner_type); | |
| 16019 | return .fromIntern(sema.pt.zcu.namespacePtr(block.namespace).owner_type); | |
| 15992 | 16020 | } |
| 15993 | 16021 | |
| 15994 | 16022 | fn 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 | 16252 | const type_info_ty = try sema.getBuiltinType(src, .Type); |
| 16225 | 16253 | const type_info_tag_ty = type_info_ty.unionTagType(zcu).?; |
| 16226 | 16254 | |
| 16255 | try sema.ensureLayoutResolved(ty); | |
| 16256 | ||
| 16227 | 16257 | if (ty.typeDeclInst(zcu)) |type_decl_inst| { |
| 16228 | 16258 | try sema.declareDependency(.{ .namespace = type_decl_inst }); |
| 16229 | 16259 | } |
| 16230 | 16260 | |
| 16231 | try sema.ensureLayoutResolved(ty); | |
| 16232 | ||
| 16233 | 16261 | switch (ty.zigTypeTag(zcu)) { |
| 16234 | 16262 | .type, |
| 16235 | 16263 | .void, |
| ... | ... | @@ -16240,7 +16268,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16240 | 16268 | .undefined, |
| 16241 | 16269 | .null, |
| 16242 | 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 | )), | |
| 16244 | 16279 | |
| 16245 | 16280 | .@"fn" => { |
| 16246 | 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 | 16283 | |
| 16249 | 16284 | const func_ty_info = zcu.typeToFunc(ty).?; |
| 16250 | 16285 | const param_vals = try sema.arena.alloc(InternPool.Index, func_ty_info.param_types.len); |
| 16286 | var func_is_generic = false; | |
| 16251 | 16287 | for (param_vals, 0..) |*param_val, i| { |
| 16252 | 16288 | const param_ty = func_ty_info.param_types.get(ip)[i]; |
| 16253 | 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 | 16291 | const param_ty_val = try pt.intern(.{ .opt = .{ |
| 16255 | 16292 | .ty = try pt.intern(.{ .opt_type = .type_type }), |
| 16256 | 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 | 16337 | } }); |
| 16301 | 16338 | }; |
| 16302 | 16339 | |
| 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 | 16352 | const ret_ty_opt = try pt.intern(.{ .opt = .{ |
| 16304 | 16353 | .ty = try pt.intern(.{ .opt_type = .type_type }), |
| 16305 | .val = opt_val: { | |
| 16306 | const ret_ty: Type = .fromInterned(func_ty_info.return_type); | |
| 16307 | if (ret_ty.toIntern() == .generic_poison_type) break :opt_val .none; | |
| 16308 | if (ret_ty.zigTypeTag(zcu) == .error_union) { | |
| 16309 | if (ret_ty.errorUnionPayload(zcu).toIntern() == .generic_poison_type) { | |
| 16310 | break :opt_val .none; | |
| 16311 | } | |
| 16312 | } | |
| 16313 | break :opt_val ret_ty.toIntern(); | |
| 16314 | }, | |
| 16354 | .val = if (ret_ty_is_generic) .none else func_ty_info.return_type, | |
| 16315 | 16355 | } }); |
| 16316 | 16356 | |
| 16317 | 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 | 16360 | error.OutOfMemory => |e| return e, |
| 16321 | 16361 | }; |
| 16322 | 16362 | |
| 16323 | // MLUGG TODO | |
| 16324 | const func_is_generic = false; | |
| 16325 | ||
| 16326 | 16363 | const field_values: [5]InternPool.Index = .{ |
| 16327 | 16364 | // calling_convention: CallingConvention, |
| 16328 | 16365 | callconv_val.toIntern(), |
| ... | ... | @@ -16837,7 +16874,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16837 | 16874 | .struct_type => ip.loadStructType(ty.toIntern()), |
| 16838 | 16875 | else => unreachable, |
| 16839 | 16876 | }; |
| 16840 | try sema.ensureFieldInitsResolved(ty); // can't do this sooner, since it's not allowed on tuples | |
| 16877 | try sema.ensureStructDefaultsResolved(ty); // can't do this sooner, since it's not allowed on tuples | |
| 16841 | 16878 | struct_field_vals = try gpa.alloc(InternPool.Index, struct_type.field_types.len); |
| 16842 | 16879 | |
| 16843 | 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 | 18230 | |
| 18194 | 18231 | const elem_ty = blk: { |
| 18195 | 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 | 18234 | if (err == error.AnalysisFail and sema.err != null and sema.typeOf(air_inst).isSinglePointer(zcu)) { |
| 18198 | 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 | 18311 | } else if (inst_data.size != .one and elem_ty.zigTypeTag(zcu) == .@"opaque") { |
| 18275 | 18312 | return sema.fail(block, elem_ty_src, "indexable pointer to opaque type '{f}' not allowed", .{elem_ty.fmt(pt)}); |
| 18276 | 18313 | } else if (inst_data.size == .c) { |
| 18277 | if (!try sema.validateExternType(elem_ty, .other)) { | |
| 18314 | if (!elem_ty.validateExtern(.other, zcu)) { | |
| 18278 | 18315 | const msg = msg: { |
| 18279 | 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 | 18317 | errdefer msg.destroy(sema.gpa); |
| ... | ... | @@ -18288,11 +18325,11 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 18288 | 18325 | } |
| 18289 | 18326 | } |
| 18290 | 18327 | |
| 18291 | if (host_size != 0 and !elem_ty.packable(zcu)) { | |
| 18292 | return sema.failWithOwnedErrorMsg(block, msg: { | |
| 18328 | if (host_size != 0) { | |
| 18329 | if (elem_ty.unpackable(zcu)) |reason| return sema.failWithOwnedErrorMsg(block, msg: { | |
| 18293 | 18330 | const msg = try sema.errMsg(elem_ty_src, "bit-pointer cannot refer to value of type '{f}'", .{elem_ty.fmt(pt)}); |
| 18294 | 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 | 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 | 18492 | |
| 18456 | 18493 | fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 18457 | 18494 | const pt = sema.pt; |
| 18495 | const zcu = pt.zcu; | |
| 18496 | const ip = &zcu.intern_pool; | |
| 18458 | 18497 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; |
| 18459 | 18498 | const ty_src = block.builtinCallArgSrc(inst_data.src_node, 0); |
| 18460 | 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 | 18501 | const extra = sema.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data; |
| 18463 | 18502 | const union_ty = try sema.resolveType(block, ty_src, extra.union_type); |
| 18464 | 18503 | if (union_ty.zigTypeTag(pt.zcu) != .@"union") { |
| 18465 | 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 | 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 | ||
| 18472 | fn 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 | 18508 | const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src); |
| 18486 | 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 | } | |
| 18491 | 18510 | |
| 18492 | fn unionInitFromEnumTag( | |
| 18493 | sema: *Sema, | |
| 18494 | block: *Block, | |
| 18495 | init_src: LazySrcLoc, | |
| 18496 | union_ty: Type, | |
| 18497 | field_index: u32, | |
| 18498 | init: Air.Inst.Ref, | |
| 18499 | ) !Air.Inst.Ref { | |
| 18500 | const pt = sema.pt; | |
| 18501 | const zcu = pt.zcu; | |
| 18511 | const payload = try sema.coerce(block, field_ty, try sema.resolveInst(extra.init), payload_src); | |
| 18502 | 18512 | |
| 18503 | if (try sema.resolveValue(init)) |init_val| { | |
| 18513 | if (try sema.resolveValue(payload)) |payload_val| { | |
| 18504 | 18514 | const tag_ty = union_ty.unionTagTypeHypothetical(zcu); |
| 18505 | 18515 | const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index); |
| 18506 | return Air.internedToRef((try pt.internUnion(.{ | |
| 18507 | .ty = union_ty.toIntern(), | |
| 18508 | .tag = tag_val.toIntern(), | |
| 18509 | .val = init_val.toIntern(), | |
| 18510 | }))); | |
| 18516 | return .fromValue(try pt.unionValue(union_ty, tag_val, payload_val)); | |
| 18511 | 18517 | } |
| 18512 | 18518 | |
| 18513 | try sema.requireRuntimeBlock(block, init_src, null); | |
| 18514 | return block.addUnionInit(union_ty, field_index, init); | |
| 18519 | try sema.requireRuntimeBlock(block, payload_src, null); | |
| 18520 | return block.addUnionInit(union_ty, field_index, payload); | |
| 18515 | 18521 | } |
| 18516 | 18522 | |
| 18517 | 18523 | fn zirStructInit( |
| ... | ... | @@ -18588,9 +18594,6 @@ fn zirStructInit( |
| 18588 | 18594 | const field_ty = resolved_ty.fieldType(field_index, zcu); |
| 18589 | 18595 | field_inits[field_index] = try sema.coerce(block, field_ty, uncoerced_init, field_src); |
| 18590 | 18596 | if (resolved_ty.structFieldIsComptime(field_index, zcu)) { |
| 18591 | if (!resolved_ty.isTuple(zcu)) { | |
| 18592 | try sema.ensureFieldInitsResolved(resolved_ty); | |
| 18593 | } | |
| 18594 | 18597 | const default_value = (try resolved_ty.structFieldValueComptime(pt, field_index)).?; |
| 18595 | 18598 | const init_val = (try sema.resolveValue(field_inits[field_index])) orelse { |
| 18596 | 18599 | return sema.failWithNeededComptime(block, field_src, .{ .simple = .stored_to_comptime_field }); |
| ... | ... | @@ -18744,7 +18747,12 @@ fn finishStructInit( |
| 18744 | 18747 | continue; |
| 18745 | 18748 | } |
| 18746 | 18749 | |
| 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); | |
| 18748 | 18756 | |
| 18749 | 18757 | const field_default: InternPool.Index = d: { |
| 18750 | 18758 | if (struct_type.field_defaults.len == 0) break :d .none; |
| ... | ... | @@ -18935,55 +18943,54 @@ fn structInitAnon( |
| 18935 | 18943 | break :hash hasher.final(); |
| 18936 | 18944 | }; |
| 18937 | 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 | 18949 | .fields_len = extra_data.fields_len, |
| 18940 | 18950 | .layout = .auto, |
| 18941 | .explicit_packed_backing_type = .none, | |
| 18942 | 18951 | .any_comptime_fields = any_values, |
| 18943 | 18952 | .any_field_defaults = any_values, |
| 18944 | 18953 | .any_field_aligns = false, |
| 18945 | .key = .{ .reified = .{ | |
| 18946 | .zir_index = tracked_inst, | |
| 18947 | .type_hash = type_hash, | |
| 18948 | } }, | |
| 18954 | .packed_backing_int_type = .none, | |
| 18949 | 18955 | })) { |
| 18956 | .existing => |ty| .fromInterned(ty), | |
| 18950 | 18957 | .wip => |wip| ty: { |
| 18951 | 18958 | errdefer wip.cancel(ip, pt.tid); |
| 18952 | // MLUGG TODO obvs this sux | |
| 18953 | const anon_prefix = (try sema.createTypeName(block, .anon, "struct", inst)).anon_prefix; | |
| 18954 | wip.setName(ip, try ip.getOrPutStringFmt(gpa, io, pt.tid, "{s}_{d}", .{ anon_prefix, @intFromEnum(wip.index) }, .no_embedded_nulls), .none); | |
| 18955 | ||
| 18956 | const struct_type = ip.loadStructType(wip.index); | |
| 18957 | ||
| 18958 | for (names, values) |name, init_val| { | |
| 18959 | assert(wip.nextField(ip, name, init_val != .none) == null); // AstGen validated no duplicates for us | |
| 18959 | try sema.setTypeName(block, &wip, .anon, "struct", inst); | |
| 18960 | ||
| 18961 | // Reified structs have field information populated immediately. | |
| 18962 | @memcpy(wip.field_names.get(ip), names); | |
| 18963 | @memcpy(wip.field_types.get(ip), types); | |
| 18964 | if (any_values) { | |
| 18965 | @memcpy(wip.field_values.get(ip), values); | |
| 18966 | @memset(wip.field_is_comptime_bits.getAll(ip), 0); | |
| 18967 | for (values, 0..) |val, field_index| { | |
| 18968 | if (val == .none) continue; | |
| 18969 | const bit_bag_index = field_index / 32; | |
| 18970 | const mask = @as(u32, 1) << @intCast(field_index % 32); | |
| 18971 | wip.field_is_comptime_bits.getAll(ip)[bit_bag_index] |= mask; | |
| 18972 | } | |
| 18960 | 18973 | } |
| 18961 | 18974 | |
| 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 | 18975 | const new_namespace_index = try pt.createNamespace(.{ |
| 18970 | 18976 | .parent = block.namespace.toOptional(), |
| 18971 | 18977 | .owner_type = wip.index, |
| 18972 | 18978 | .file_scope = block.getFileScopeIndex(zcu), |
| 18973 | 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 | 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 | 18989 | break :ty .fromInterned(wip.finish(ip, new_namespace_index)); |
| 18983 | 18990 | }, |
| 18984 | .existing => |ty| .fromInterned(ty), | |
| 18985 | 18991 | }; |
| 18986 | 18992 | try sema.addTypeReferenceEntry(src, struct_ty); |
| 18993 | try sema.ensureLayoutResolved(struct_ty); | |
| 18987 | 18994 | |
| 18988 | 18995 | _ = opt_runtime_index orelse { |
| 18989 | 18996 | const struct_val = try pt.aggregateValue(struct_ty, values); |
| ... | ... | @@ -19338,6 +19345,7 @@ fn fieldType( |
| 19338 | 19345 | const pt = sema.pt; |
| 19339 | 19346 | const zcu = pt.zcu; |
| 19340 | 19347 | const ip = &zcu.intern_pool; |
| 19348 | aggregate_ty.assertHasLayout(zcu); | |
| 19341 | 19349 | var cur_ty = aggregate_ty; |
| 19342 | 19350 | while (true) { |
| 19343 | 19351 | switch (cur_ty.zigTypeTag(zcu)) { |
| ... | ... | @@ -19397,7 +19405,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { |
| 19397 | 19405 | .func => |func| if (ip.funcAnalysisUnordered(func).has_error_trace and block.ownerModule().error_tracing) { |
| 19398 | 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 | 19410 | return Air.internedToRef(try pt.intern(.{ .opt = .{ |
| 19403 | 19411 | .ty = opt_ptr_stack_trace_ty.toIntern(), |
| ... | ... | @@ -19823,7 +19831,7 @@ fn zirReifyPointer( |
| 19823 | 19831 | else => {}, |
| 19824 | 19832 | } |
| 19825 | 19833 | |
| 19826 | if (size == .c and !try sema.validateExternType(elem_ty, .other)) { | |
| 19834 | if (size == .c and !elem_ty.validateExtern(.other, zcu)) { | |
| 19827 | 19835 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 19828 | 19836 | const msg = try sema.errMsg(src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)}); |
| 19829 | 19837 | errdefer msg.destroy(gpa); |
| ... | ... | @@ -19988,6 +19996,7 @@ fn zirReifyStruct( |
| 19988 | 19996 | const name_strategy: Zir.Inst.NameStrategy = @enumFromInt(extended.small); |
| 19989 | 19997 | const extra = sema.code.extraData(Zir.Inst.ReifyStruct, extended.operand).data; |
| 19990 | 19998 | const tracked_inst = try block.trackZir(inst); |
| 19999 | ||
| 19991 | 20000 | const src: LazySrcLoc = .{ |
| 19992 | 20001 | .base_node_inst = tracked_inst, |
| 19993 | 20002 | .offset = .nodeOffset(.zero), |
| ... | ... | @@ -20039,7 +20048,7 @@ fn zirReifyStruct( |
| 20039 | 20048 | |
| 20040 | 20049 | const backing_int_ty_uncoerced = try sema.resolveInst(extra.backing_ty); |
| 20041 | 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 }); | |
| 20043 | 20052 | |
| 20044 | 20053 | const field_names_uncoerced = try sema.resolveInst(extra.field_names); |
| 20045 | 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 | 20088 | return sema.failWithUseOfUndef(block, backing_ty_src, null); |
| 20080 | 20089 | } |
| 20081 | 20090 | |
| 20082 | // The validation work here is non-trivial, and it's possible the type already exists. | |
| 20083 | // So in this first pass, let's just construct a hash to optimize for this case. If the | |
| 20084 | // inputs turn out to be invalid, we can cancel the WIP type later. | |
| 20091 | // Most validation of this type happens during type resolution. We basically need to do the work | |
| 20092 | // which AstGen would normally do. An exception is checking for duplicate field names, which is | |
| 20093 | // handled by type resolution---it just simplifies some logic a little. | |
| 20094 | ||
| 20095 | // As well as validation, we're going to gather some information about the fields, and construct | |
| 20096 | // a hash representing the inputs for deduplication purposes. | |
| 20085 | 20097 | |
| 20086 | 20098 | var any_comptime_fields = false; |
| 20087 | var any_default_inits = false; | |
| 20088 | var any_aligned_fields = false; | |
| 20099 | var any_field_defaults = false; | |
| 20100 | var any_field_aligns = false; | |
| 20089 | 20101 | |
| 20090 | // For deduplication purposes, we must create a hash including all details of this type. | |
| 20091 | 20102 | // TODO: use a longer hash! |
| 20092 | 20103 | var hasher = std.hash.Wyhash.init(0); |
| 20093 | 20104 | std.hash.autoHash(&hasher, layout); |
| 20094 | 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 | 20115 | // The field *type* array has already been deduplicated for us thanks to the InternPool! |
| 20096 | 20116 | std.hash.autoHash(&hasher, field_types_arr); |
| 20097 | 20117 | // However, for field names and attributes, we need to actually iterate the individual fields, |
| ... | ... | @@ -20126,201 +20146,126 @@ fn zirReifyStruct( |
| 20126 | 20146 | field_attrs_src, |
| 20127 | 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 | 20153 | break :d deref_val.toIntern(); |
| 20130 | 20154 | }; |
| 20131 | 20155 | |
| 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 | 20175 | std.hash.autoHash(&hasher, .{ |
| 20133 | 20176 | field_name, |
| 20134 | 20177 | field_attr_comptime, |
| 20135 | 20178 | field_attr_align, |
| 20136 | 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 | } |
| 20158 | 20182 | |
| 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 | 20186 | .fields_len = @intCast(fields_len), |
| 20161 | 20187 | .layout = layout, |
| 20162 | .explicit_packed_backing_type = if (backing_int_ty) |t| t.toIntern() else .none, | |
| 20163 | 20188 | .any_comptime_fields = any_comptime_fields, |
| 20164 | .any_field_defaults = any_default_inits, | |
| 20165 | .any_field_aligns = any_aligned_fields, | |
| 20166 | .key = .{ .reified = .{ | |
| 20167 | .zir_index = tracked_inst, | |
| 20168 | .type_hash = hasher.final(), | |
| 20169 | } }, | |
| 20189 | .any_field_defaults = any_field_defaults, | |
| 20190 | .any_field_aligns = any_field_aligns, | |
| 20191 | .packed_backing_int_type = if (backing_int_ty) |ty| ty.toIntern() else .none, | |
| 20170 | 20192 | })) { |
| 20171 | .wip => |wip| wip, | |
| 20172 | 20193 | .existing => |ty| { |
| 20173 | 20194 | try sema.addTypeReferenceEntry(src, .fromInterned(ty)); |
| 20174 | 20195 | return .fromIntern(ty); |
| 20175 | 20196 | }, |
| 20176 | }; | |
| 20177 | errdefer wip_ty.cancel(ip, pt.tid); | |
| 20178 | ||
| 20179 | _ = try (try sema.createTypeName( | |
| 20180 | block, | |
| 20181 | name_strategy, | |
| 20182 | "struct", | |
| 20183 | inst, | |
| 20184 | )).apply(&wip_ty, pt); | |
| 20185 | ||
| 20186 | const wip_struct_type = ip.loadStructType(wip_ty.index); | |
| 20187 | ||
| 20188 | for (0..fields_len) |field_idx| { | |
| 20189 | const field_name_val = try field_names_arr.elemValue(pt, field_idx); | |
| 20190 | const field_attrs_val = try field_attrs_arr.elemValue(pt, field_idx); | |
| 20191 | ||
| 20192 | // Don't pass a reason; first loop acts as a check that this is valid. | |
| 20193 | const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined); | |
| 20194 | const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType(); | |
| 20195 | const field_attr_comptime = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex( | |
| 20196 | std.builtin.Type.StructField.Attributes, | |
| 20197 | "comptime", | |
| 20198 | ).?); | |
| 20199 | const field_attr_align = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex( | |
| 20200 | std.builtin.Type.StructField.Attributes, | |
| 20201 | "align", | |
| 20202 | ).?); | |
| 20203 | const field_attr_default_value_ptr = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex( | |
| 20204 | std.builtin.Type.StructField.Attributes, | |
| 20205 | "default_value_ptr", | |
| 20206 | ).?); | |
| 20197 | .wip => |wip| { | |
| 20198 | errdefer wip.cancel(ip, pt.tid); | |
| 20199 | try sema.setTypeName(block, &wip, name_strategy, "struct", inst); | |
| 20200 | for (0..fields_len) |field_idx| { | |
| 20201 | const field_name_val = try field_names_arr.elemValue(pt, field_idx); | |
| 20202 | const field_attrs_val = try field_attrs_arr.elemValue(pt, field_idx); | |
| 20203 | ||
| 20204 | // No source location or reason; first loop checked this is valid. | |
| 20205 | const field_name = try sema.sliceToIpString(block, .unneeded, field_name_val, undefined); | |
| 20206 | wip.field_names.get(ip)[field_idx] = field_name; | |
| 20207 | ||
| 20208 | const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType(); | |
| 20209 | wip.field_types.get(ip)[field_idx] = field_ty.toIntern(); | |
| 20210 | ||
| 20211 | const field_attr_comptime = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex( | |
| 20212 | std.builtin.Type.StructField.Attributes, | |
| 20213 | "comptime", | |
| 20214 | ).?); | |
| 20215 | const field_attr_align = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex( | |
| 20216 | std.builtin.Type.StructField.Attributes, | |
| 20217 | "align", | |
| 20218 | ).?); | |
| 20219 | const field_attr_default_value_ptr = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex( | |
| 20220 | std.builtin.Type.StructField.Attributes, | |
| 20221 | "default_value_ptr", | |
| 20222 | ).?); | |
| 20223 | ||
| 20224 | if (field_attr_comptime.toBool()) { | |
| 20225 | const bit_bag_index = field_idx / 32; | |
| 20226 | const mask = @as(u32, 1) << @intCast(field_idx % 32); | |
| 20227 | wip.field_is_comptime_bits.getAll(ip)[bit_bag_index] |= mask; | |
| 20228 | } | |
| 20207 | 20229 | |
| 20208 | if (wip_ty.nextField(ip, field_name, field_attr_comptime.toBool())) |prev_index| { | |
| 20209 | _ = prev_index; // TODO: better source location | |
| 20210 | return sema.fail(block, field_names_src, "duplicate struct field name {f}", .{field_name.fmt(ip)}); | |
| 20211 | } | |
| 20230 | if (field_attr_default_value_ptr.optionalValue(zcu)) |ptr_val| { | |
| 20231 | const ptr_ty = try pt.singleConstPtrType(field_ty); | |
| 20232 | // No source location; first loop checked this is valid. | |
| 20233 | const deref_val = (try sema.pointerDeref(block, .unneeded, ptr_val, ptr_ty)).?; | |
| 20234 | wip.field_values.get(ip)[field_idx] = deref_val.toIntern(); | |
| 20235 | } else if (any_field_defaults) { | |
| 20236 | wip.field_values.get(ip)[field_idx] = .none; | |
| 20237 | } | |
| 20212 | 20238 | |
| 20213 | const field_default: InternPool.Index = d: { | |
| 20214 | const ptr_val = field_attr_default_value_ptr.optionalValue(zcu) orelse break :d .none; | |
| 20215 | assert(any_default_inits); | |
| 20216 | const ptr_ty = try pt.singleConstPtrType(field_ty); | |
| 20217 | // The first loop checked that this is comptime-dereferencable. | |
| 20218 | const deref_val = (try sema.pointerDeref(block, field_attrs_src, ptr_val, ptr_ty)).?; | |
| 20219 | // ...but we've not checked this yet! | |
| 20220 | if (deref_val.canMutateComptimeVarState(zcu)) { | |
| 20221 | return sema.failWithContainsReferenceToComptimeVar(block, field_attrs_src, field_name, "field default value", deref_val); | |
| 20239 | if (field_attr_align.optionalValue(zcu)) |field_align_val| { | |
| 20240 | const bytes = field_align_val.toUnsignedInt(zcu); | |
| 20241 | // No source location; first loop checked this is valid. | |
| 20242 | const a = try sema.validateAlign(block, .unneeded, bytes); | |
| 20243 | wip.field_aligns.get(ip)[field_idx] = a; | |
| 20244 | } else if (any_field_aligns) { | |
| 20245 | wip.field_aligns.get(ip)[field_idx] = .none; | |
| 20246 | } | |
| 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 | } | |
| 20283 | 20248 | |
| 20284 | if (layout == .@"packed") { | |
| 20285 | var field_bits: u64 = 0; | |
| 20286 | for (0..fields_len) |field_idx| { | |
| 20287 | const field_ty: Type = .fromInterned(wip_struct_type.field_types.get(ip)[field_idx]); | |
| 20288 | try sema.ensureLayoutResolved(field_ty); | |
| 20289 | field_bits += field_ty.bitSize(zcu); | |
| 20290 | } | |
| 20291 | try type_resolution.resolvePackedStructBackingInt( | |
| 20292 | sema, | |
| 20293 | block, | |
| 20294 | field_bits, | |
| 20295 | .fromInterned(wip_ty.index), | |
| 20296 | &wip_struct_type, | |
| 20297 | ); | |
| 20298 | } else { | |
| 20299 | try type_resolution.finishStructLayout( | |
| 20300 | sema, | |
| 20301 | block, | |
| 20302 | src, | |
| 20303 | wip_ty.index, | |
| 20304 | &wip_struct_type, | |
| 20305 | ); | |
| 20306 | } | |
| 20249 | const new_namespace_index = try pt.createNamespace(.{ | |
| 20250 | .parent = block.namespace.toOptional(), | |
| 20251 | .owner_type = wip.index, | |
| 20252 | .file_scope = block.getFileScopeIndex(zcu), | |
| 20253 | .generation = zcu.generation, | |
| 20254 | }); | |
| 20255 | try sema.addTypeReferenceEntry(src, .fromInterned(wip.index)); | |
| 20256 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); | |
| 20257 | // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind | |
| 20258 | try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) }); | |
| 20307 | 20259 | |
| 20308 | const new_namespace_index = try pt.createNamespace(.{ | |
| 20309 | .parent = block.namespace.toOptional(), | |
| 20310 | .owner_type = wip_ty.index, | |
| 20311 | .file_scope = block.getFileScopeIndex(zcu), | |
| 20312 | .generation = zcu.generation, | |
| 20313 | }); | |
| 20260 | try zcu.outdated.ensureUnusedCapacity(gpa, 1); | |
| 20261 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); | |
| 20262 | errdefer comptime unreachable; // because we don't remove the `outdated` entries | |
| 20263 | zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); | |
| 20264 | zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); | |
| 20314 | 20265 | |
| 20315 | codegen_type: { | |
| 20316 | if (zcu.comp.config.use_llvm) break :codegen_type; | |
| 20317 | if (block.ownerModule().strip) break :codegen_type; | |
| 20318 | zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); | |
| 20319 | try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); | |
| 20266 | return .fromIntern(wip.finish(ip, new_namespace_index)); | |
| 20267 | }, | |
| 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 | } |
| 20325 | 20270 | |
| 20326 | 20271 | fn zirReifyUnion( |
| ... | ... | @@ -20390,7 +20335,10 @@ fn zirReifyUnion( |
| 20390 | 20335 | |
| 20391 | 20336 | const arg_ty_uncoerced = try sema.resolveInst(extra.arg_ty); |
| 20392 | 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 | }); | |
| 20394 | 20342 | |
| 20395 | 20343 | const field_names_uncoerced = try sema.resolveInst(extra.field_names); |
| 20396 | 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 | 20378 | return sema.failWithUseOfUndef(block, arg_ty_src, null); |
| 20431 | 20379 | } |
| 20432 | 20380 | |
| 20433 | // The validation work here is non-trivial, and it's possible the type already exists. | |
| 20434 | // So in this first pass, let's just construct a hash to optimize for this case. If the | |
| 20435 | // inputs turn out to be invalid, we can cancel the WIP type later. | |
| 20381 | // Most validation of this type happens during type resolution. We basically need to do the work | |
| 20382 | // which AstGen would normally do. An exception is checking for duplicate field names, which is | |
| 20383 | // handled by type resolution---it just simplifies some logic a little. | |
| 20384 | ||
| 20385 | // As well as validation, we're going to gather some information about the fields, and construct | |
| 20386 | // a hash representing the inputs for deduplication purposes. | |
| 20436 | 20387 | |
| 20437 | var any_aligned_fields = false; | |
| 20388 | var any_field_aligns = false; | |
| 20438 | 20389 | |
| 20439 | // For deduplication purposes, we must create a hash including all details of this type. | |
| 20440 | 20390 | // TODO: use a longer hash! |
| 20441 | 20391 | var hasher = std.hash.Wyhash.init(0); |
| 20442 | 20392 | std.hash.autoHash(&hasher, layout); |
| 20443 | 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 | 20404 | // `field_types_arr` and `field_attrs_arr` are already deduplicated by the InternPool! |
| 20445 | 20405 | std.hash.autoHash(&hasher, field_types_arr); |
| 20446 | 20406 | std.hash.autoHash(&hasher, field_attrs_arr); |
| ... | ... | @@ -20457,249 +20417,84 @@ fn zirReifyUnion( |
| 20457 | 20417 | try field_attrs_arr.elemValue(pt, field_idx), |
| 20458 | 20418 | std.builtin.Type.UnionField.Attributes, |
| 20459 | 20419 | ); |
| 20460 | if (field_attrs.@"align" != null) { | |
| 20461 | any_aligned_fields = true; | |
| 20462 | } | |
| 20463 | } | |
| 20464 | ||
| 20465 | // Some basic validation to avoid a bogus `getUnionType` call... | |
| 20466 | const explicit_tag_ty: ?Type, const explicit_packed_backing_type: ?Type = ty: { | |
| 20467 | const arg_ty = arg_ty_val.optionalValue(zcu) orelse break :ty .{ null, null }; | |
| 20468 | switch (layout) { | |
| 20469 | .@"extern" => return sema.fail(block, arg_ty_src, "extern union does not support enum tag type", .{}), | |
| 20470 | .@"packed" => break :ty .{ null, arg_ty.toType() }, | |
| 20471 | .auto => break :ty .{ arg_ty.toType(), null }, | |
| 20420 | if (field_attrs.@"align") |bytes| { | |
| 20421 | if (layout == .@"packed") { | |
| 20422 | return sema.fail(block, field_attrs_src, "packed union fields cannot be aligned", .{}); | |
| 20423 | } | |
| 20424 | // Trigger a compile error if the alignment is invalid. | |
| 20425 | _ = try sema.validateAlign(block, field_attrs_src, bytes); | |
| 20426 | any_field_aligns = true; | |
| 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 | } |
| 20477 | 20429 | |
| 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 | 20433 | .fields_len = @intCast(fields_len), |
| 20480 | 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 | 20436 | .runtime_tag = rt: { |
| 20483 | 20437 | if (explicit_tag_ty != null) break :rt .tagged; |
| 20484 | 20438 | if (layout == .auto and block.wantSafeTypes()) break :rt .safety; |
| 20485 | 20439 | break :rt .none; |
| 20486 | 20440 | }, |
| 20487 | .have_explicit_enum_tag = explicit_tag_ty != null, | |
| 20488 | .any_field_aligns = any_aligned_fields, | |
| 20489 | .key = .{ .reified = .{ | |
| 20490 | .zir_index = tracked_inst, | |
| 20491 | .type_hash = hasher.final(), | |
| 20492 | } }, | |
| 20441 | .enum_tag_type = if (explicit_tag_ty) |ty| ty.toIntern() else .none, | |
| 20442 | .packed_backing_int_type = if (explicit_packed_backing_type) |ty| ty.toIntern() else .none, | |
| 20493 | 20443 | })) { |
| 20494 | .wip => |wip| wip, | |
| 20495 | 20444 | .existing => |ty| { |
| 20496 | 20445 | try sema.addTypeReferenceEntry(src, .fromInterned(ty)); |
| 20497 | 20446 | return .fromIntern(ty); |
| 20498 | 20447 | }, |
| 20499 | }; | |
| 20500 | errdefer wip_ty.cancel(ip, pt.tid); | |
| 20501 | ||
| 20502 | const type_name = try (try sema.createTypeName( | |
| 20503 | block, | |
| 20504 | name_strategy, | |
| 20505 | "union", | |
| 20506 | inst, | |
| 20507 | )).apply(&wip_ty, pt); | |
| 20508 | ||
| 20509 | const loaded_union = ip.loadUnionType(wip_ty.index); | |
| 20510 | ||
| 20511 | const generated_tag_ty: InternPool.Index = if (explicit_tag_ty) |enum_tag_ty| generated_tag: { | |
| 20512 | if (enum_tag_ty.zigTypeTag(zcu) != .@"enum") { | |
| 20513 | return sema.fail(block, arg_ty_src, "tag type must be an enum type", .{}); | |
| 20514 | } | |
| 20515 | ||
| 20516 | const tag_ty_fields_len = enum_tag_ty.enumFieldCount(zcu); | |
| 20448 | .wip => |wip| { | |
| 20449 | errdefer wip.cancel(ip, pt.tid); | |
| 20450 | try sema.setTypeName(block, &wip, name_strategy, "union", inst); | |
| 20517 | 20451 | |
| 20518 | for (0..fields_len) |field_idx| { | |
| 20519 | const field_name_val = try field_names_arr.elemValue(pt, field_idx); | |
| 20520 | // Don't pass a reason; first loop acts as a check that this is valid. | |
| 20521 | const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined); | |
| 20452 | for (0..fields_len) |field_idx| { | |
| 20453 | const field_name_val = try field_names_arr.elemValue(pt, field_idx); | |
| 20454 | // No source location or reason; first loop checked this is valid. | |
| 20455 | const field_name = try sema.sliceToIpString(block, .unneeded, field_name_val, undefined); | |
| 20456 | wip.field_names.get(ip)[field_idx] = field_name; | |
| 20522 | 20457 | |
| 20523 | if (field_idx >= tag_ty_fields_len) { | |
| 20524 | return sema.fail(block, field_names_src, "no field named '{f}' in enum '{f}'", .{ | |
| 20525 | field_name.fmt(ip), enum_tag_ty.fmt(pt), | |
| 20526 | }); | |
| 20527 | } | |
| 20458 | const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType(); | |
| 20459 | wip.field_types.get(ip)[field_idx] = field_ty.toIntern(); | |
| 20528 | 20460 | |
| 20529 | const enum_field_name = enum_tag_ty.enumFieldName(field_idx, zcu); | |
| 20530 | if (enum_field_name != field_name) { | |
| 20531 | return sema.fail(block, field_names_src, "union field name '{f}' does not match enum field name '{f}'", .{ | |
| 20532 | field_name.fmt(ip), enum_field_name.fmt(ip), | |
| 20533 | }); | |
| 20534 | } | |
| 20535 | } | |
| 20536 | if (tag_ty_fields_len > fields_len) return sema.failWithOwnedErrorMsg(block, msg: { | |
| 20537 | const msg = try sema.errMsg(field_names_src, "{d} enum fields missing in union", .{ | |
| 20538 | tag_ty_fields_len - fields_len, | |
| 20539 | }); | |
| 20540 | errdefer msg.destroy(gpa); | |
| 20541 | for (fields_len..tag_ty_fields_len) |enum_field_idx| { | |
| 20542 | try sema.addFieldErrNote(enum_tag_ty, enum_field_idx, msg, "field '{f}' missing, declared here", .{ | |
| 20543 | enum_tag_ty.enumFieldName(enum_field_idx, zcu).fmt(ip), | |
| 20544 | }); | |
| 20461 | // No source location; first loop checked this is valid. | |
| 20462 | const field_attrs = try sema.interpretBuiltinType( | |
| 20463 | block, | |
| 20464 | .unneeded, | |
| 20465 | try field_attrs_arr.elemValue(pt, field_idx), | |
| 20466 | std.builtin.Type.UnionField.Attributes, | |
| 20467 | ); | |
| 20468 | if (field_attrs.@"align") |bytes| { | |
| 20469 | // No source location; first loop checked this is valid. | |
| 20470 | const a = try sema.validateAlign(block, .unneeded, bytes); | |
| 20471 | wip.field_aligns.get(ip)[field_idx] = a; | |
| 20472 | } else if (any_field_aligns) { | |
| 20473 | wip.field_aligns.get(ip)[field_idx] = .none; | |
| 20474 | } | |
| 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 | ); | |
| 20619 | 20476 | |
| 20620 | if (field_ty.zigTypeTag(zcu) == .@"opaque") { | |
| 20621 | return sema.failWithOwnedErrorMsg(block, msg: { | |
| 20622 | const msg = try sema.errMsg(field_types_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{}); | |
| 20623 | errdefer msg.destroy(gpa); | |
| 20624 | try sema.addDeclaredHereNote(msg, field_ty); | |
| 20625 | break :msg msg; | |
| 20477 | const new_namespace_index = try pt.createNamespace(.{ | |
| 20478 | .parent = block.namespace.toOptional(), | |
| 20479 | .owner_type = wip.index, | |
| 20480 | .file_scope = block.getFileScopeIndex(zcu), | |
| 20481 | .generation = zcu.generation, | |
| 20626 | 20482 | }); |
| 20627 | } | |
| 20628 | ||
| 20629 | switch (layout) { | |
| 20630 | .auto => {}, | |
| 20631 | .@"extern" => if (!try sema.validateExternType(field_ty, .union_field)) { | |
| 20632 | return sema.failWithOwnedErrorMsg(block, msg: { | |
| 20633 | const msg = try sema.errMsg(field_types_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | |
| 20634 | errdefer msg.destroy(gpa); | |
| 20635 | ||
| 20636 | try sema.explainWhyTypeIsNotExtern(msg, field_types_src, field_ty, .union_field); | |
| 20637 | ||
| 20638 | try sema.addDeclaredHereNote(msg, field_ty); | |
| 20639 | break :msg msg; | |
| 20640 | }); | |
| 20641 | }, | |
| 20642 | .@"packed" => if (!field_ty.packable(zcu)) { | |
| 20643 | return sema.failWithOwnedErrorMsg(block, msg: { | |
| 20644 | const msg = try sema.errMsg(field_types_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | |
| 20645 | errdefer msg.destroy(gpa); | |
| 20646 | ||
| 20647 | try sema.explainWhyTypeIsNotPackable(msg, field_types_src, field_ty); | |
| 20648 | ||
| 20649 | try sema.addDeclaredHereNote(msg, field_ty); | |
| 20650 | break :msg msg; | |
| 20651 | }); | |
| 20652 | }, | |
| 20653 | } | |
| 20654 | ||
| 20655 | loaded_union.field_types.get(ip)[field_idx] = field_ty.toIntern(); | |
| 20656 | if (field_attrs.@"align") |bytes| { | |
| 20657 | assert(layout != .@"packed"); | |
| 20658 | const a = try sema.validateAlign(block, field_attrs_src, bytes); | |
| 20659 | loaded_union.field_aligns.get(ip)[field_idx] = a; | |
| 20660 | } else if (any_aligned_fields) { | |
| 20661 | assert(layout != .@"packed"); | |
| 20662 | loaded_union.field_aligns.get(ip)[field_idx] = .none; | |
| 20663 | } | |
| 20664 | } | |
| 20483 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); | |
| 20484 | try sema.addTypeReferenceEntry(src, .fromInterned(wip.index)); | |
| 20665 | 20485 | |
| 20666 | if (layout == .@"packed") { | |
| 20667 | try type_resolution.resolvePackedUnionBackingInt( | |
| 20668 | sema, | |
| 20669 | block, | |
| 20670 | .fromInterned(wip_ty.index), | |
| 20671 | &loaded_union, | |
| 20672 | true, | |
| 20673 | ); | |
| 20674 | } else { | |
| 20675 | try type_resolution.finishUnionLayout( | |
| 20676 | sema, | |
| 20677 | block, | |
| 20678 | src, | |
| 20679 | wip_ty.index, | |
| 20680 | &loaded_union, | |
| 20681 | explicit_tag_ty orelse .fromInterned(generated_tag_ty), | |
| 20682 | ); | |
| 20683 | } | |
| 20486 | // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind | |
| 20487 | try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) }); | |
| 20684 | 20488 | |
| 20685 | const new_namespace_index = try pt.createNamespace(.{ | |
| 20686 | .parent = block.namespace.toOptional(), | |
| 20687 | .owner_type = wip_ty.index, | |
| 20688 | .file_scope = block.getFileScopeIndex(zcu), | |
| 20689 | .generation = zcu.generation, | |
| 20690 | }); | |
| 20489 | try zcu.outdated.ensureUnusedCapacity(gpa, 1); | |
| 20490 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); | |
| 20491 | errdefer comptime unreachable; // because we don't remove the `outdated` entry | |
| 20492 | zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); | |
| 20493 | zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); | |
| 20691 | 20494 | |
| 20692 | codegen_type: { | |
| 20693 | if (zcu.comp.config.use_llvm) break :codegen_type; | |
| 20694 | if (block.ownerModule().strip) break :codegen_type; | |
| 20695 | zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); | |
| 20696 | try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); | |
| 20697 | } | |
| 20698 | try sema.addTypeReferenceEntry(src, .fromInterned(wip_ty.index)); | |
| 20699 | if (zcu.comp.debugIncremental()) { | |
| 20700 | try zcu.incremental_debug_state.newType(zcu, wip_ty.index); | |
| 20495 | return .fromIntern(wip.finish(ip, new_namespace_index)); | |
| 20496 | }, | |
| 20701 | 20497 | } |
| 20702 | return .fromIntern(wip_ty.finish(ip, new_namespace_index)); | |
| 20703 | 20498 | } |
| 20704 | 20499 | |
| 20705 | 20500 | fn zirReifyEnum( |
| ... | ... | @@ -20754,10 +20549,10 @@ fn zirReifyEnum( |
| 20754 | 20549 | |
| 20755 | 20550 | const enum_mode_ty = try sema.getBuiltinType(mode_src, .@"Type.Enum.Mode"); |
| 20756 | 20551 | |
| 20757 | const tag_ty = try sema.resolveType(block, tag_ty_src, extra.tag_ty); | |
| 20758 | if (tag_ty.zigTypeTag(zcu) != .int) { | |
| 20759 | return sema.fail(block, tag_ty_src, "tag type must be an integer type", .{}); | |
| 20760 | } | |
| 20552 | const tag_ty_uncoerced = try sema.resolveInst(extra.tag_ty); | |
| 20553 | const tag_ty_coerced = try sema.coerce(block, .type, tag_ty_uncoerced, tag_ty_src); | |
| 20554 | const tag_ty_val = try sema.resolveConstDefinedValue(block, tag_ty_src, tag_ty_coerced, .{ .simple = .enum_int_tag_type }); | |
| 20555 | const tag_ty = tag_ty_val.toType(); | |
| 20761 | 20556 | |
| 20762 | 20557 | const mode_uncoerced = try sema.resolveInst(extra.mode); |
| 20763 | 20558 | const mode_coerced = try sema.coerce(block, enum_mode_ty, mode_uncoerced, mode_src); |
| ... | ... | @@ -20790,11 +20585,13 @@ fn zirReifyEnum( |
| 20790 | 20585 | } |
| 20791 | 20586 | // We don't need to check `field_names_arr`, because `sliceToIpString` will check that for us. |
| 20792 | 20587 | |
| 20793 | // The validation work here is non-trivial, and it's possible the type already exists. | |
| 20794 | // So in this first pass, let's just construct a hash to optimize for this case. If the | |
| 20795 | // inputs turn out to be invalid, we can cancel the WIP type later. | |
| 20588 | // Most validation of this type happens during type resolution. We basically need to do the work | |
| 20589 | // which AstGen would normally do. An exception is checking for duplicate field names, which is | |
| 20590 | // handled by type resolution---it just simplifies some logic a little. | |
| 20591 | ||
| 20592 | // As well as validation, we're going to gather some information about the fields, and construct | |
| 20593 | // a hash representing the inputs for deduplication purposes. | |
| 20796 | 20594 | |
| 20797 | // For deduplication purposes, we must create a hash including all details of this type. | |
| 20798 | 20595 | // TODO: use a longer hash! |
| 20799 | 20596 | var hasher = std.hash.Wyhash.init(0); |
| 20800 | 20597 | std.hash.autoHash(&hasher, tag_ty.toIntern()); |
| ... | ... | @@ -20810,85 +20607,55 @@ fn zirReifyEnum( |
| 20810 | 20607 | std.hash.autoHash(&hasher, field_name); |
| 20811 | 20608 | } |
| 20812 | 20609 | |
| 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 | 20613 | .fields_len = @intCast(fields_len), |
| 20815 | .explicit_int_tag_type = tag_ty.toIntern(), | |
| 20816 | 20614 | .nonexhaustive = nonexhaustive, |
| 20817 | .key = .{ .reified = .{ | |
| 20818 | .zir_index = tracked_inst, | |
| 20819 | .type_hash = hasher.final(), | |
| 20820 | } }, | |
| 20615 | .int_tag_type = tag_ty.toIntern(), | |
| 20821 | 20616 | })) { |
| 20822 | .wip => |wip| wip, | |
| 20823 | 20617 | .existing => |ty| { |
| 20824 | 20618 | try sema.addTypeReferenceEntry(src, .fromInterned(ty)); |
| 20825 | 20619 | return .fromIntern(ty); |
| 20826 | 20620 | }, |
| 20827 | }; | |
| 20828 | errdefer wip_ty.cancel(ip, pt.tid); | |
| 20621 | .wip => |wip| { | |
| 20622 | errdefer wip.cancel(ip, pt.tid); | |
| 20829 | 20623 | |
| 20830 | _ = try (try sema.createTypeName( | |
| 20831 | block, | |
| 20832 | name_strategy, | |
| 20833 | "enum", | |
| 20834 | inst, | |
| 20835 | )).apply(&wip_ty, pt); | |
| 20624 | try sema.setTypeName(block, &wip, name_strategy, "enum", inst); | |
| 20836 | 20625 | |
| 20837 | for (0..fields_len) |field_idx| { | |
| 20838 | const field_name_val = try field_names_arr.elemValue(pt, field_idx); | |
| 20839 | // Don't pass a reason; first loop acts as a check that this is valid. | |
| 20840 | const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined); | |
| 20841 | if (wip_ty.nextField(ip, field_name, false)) |prev_field_idx| return sema.failWithOwnedErrorMsg(block, msg: { | |
| 20842 | const msg = try sema.errMsg(field_names_src, "duplicate enum field '{f}' at index '{d}'", .{ field_name.fmt(ip), field_idx }); | |
| 20843 | errdefer msg.destroy(gpa); | |
| 20844 | try sema.errNote(field_names_src, msg, "previous field at index '{d}'", .{prev_field_idx}); | |
| 20845 | break :msg msg; | |
| 20846 | }); | |
| 20847 | } | |
| 20626 | // Populate field names and values. Duplicate checking will be handled by type resolution. | |
| 20627 | for (0..fields_len) |field_index| { | |
| 20628 | const field_name_val = try field_names_arr.elemValue(pt, field_index); | |
| 20629 | // No source location or reason; first loop checked this is valid. | |
| 20630 | const field_name = try sema.sliceToIpString(block, .unneeded, field_name_val, undefined); | |
| 20631 | wip.field_names.get(ip)[field_index] = field_name; | |
| 20848 | 20632 | |
| 20849 | const enum_obj = ip.loadEnumType(wip_ty.index); | |
| 20850 | const field_value_map = enum_obj.field_value_map.unwrap().?; | |
| 20851 | for (0..fields_len) |field_idx| { | |
| 20852 | const field_val = try field_values_arr.elemValue(pt, field_idx); | |
| 20853 | const field_values = enum_obj.field_values.get(ip); | |
| 20854 | field_values[field_idx] = field_val.toIntern(); | |
| 20855 | const adapter: InternPool.Index.Adapter = .{ .indexes = field_values[0..field_idx] }; | |
| 20856 | const gop = field_value_map.get(ip).getOrPutAssumeCapacityAdapted(field_val.toIntern(), adapter); | |
| 20857 | if (gop.found_existing) return sema.failWithOwnedErrorMsg(block, msg: { | |
| 20858 | const field_names = enum_obj.field_names.get(ip); | |
| 20859 | const this_field_name = field_names[field_idx]; | |
| 20860 | const prev_field_name = field_names[gop.index]; | |
| 20861 | const msg = try sema.errMsg(field_names_src, "duplicate enum tag value '{f}' in field '{f}'", .{ | |
| 20862 | field_val.fmtValueSema(pt, sema), | |
| 20863 | this_field_name.fmt(ip), | |
| 20633 | const field_val = try field_values_arr.elemValue(pt, field_index); | |
| 20634 | wip.field_values.get(ip)[field_index] = field_val.toIntern(); | |
| 20635 | } | |
| 20636 | ||
| 20637 | const new_namespace_index = try pt.createNamespace(.{ | |
| 20638 | .parent = block.namespace.toOptional(), | |
| 20639 | .owner_type = wip.index, | |
| 20640 | .file_scope = block.getFileScopeIndex(zcu), | |
| 20641 | .generation = zcu.generation, | |
| 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 | } | |
| 20870 | 20643 | |
| 20871 | if (nonexhaustive and fields_len > 1 and std.math.log2_int(u64, fields_len) == tag_ty.bitSize(zcu)) { | |
| 20872 | return sema.fail(block, src, "non-exhaustive enum specified every value", .{}); | |
| 20873 | } | |
| 20644 | try sema.addTypeReferenceEntry(src, .fromInterned(wip.index)); | |
| 20645 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); | |
| 20874 | 20646 | |
| 20875 | const new_namespace_index = try pt.createNamespace(.{ | |
| 20876 | .parent = block.namespace.toOptional(), | |
| 20877 | .owner_type = wip_ty.index, | |
| 20878 | .file_scope = block.getFileScopeIndex(zcu), | |
| 20879 | .generation = zcu.generation, | |
| 20880 | }); | |
| 20647 | // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind | |
| 20648 | try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) }); | |
| 20881 | 20649 | |
| 20882 | codegen_type: { | |
| 20883 | if (zcu.comp.config.use_llvm) break :codegen_type; | |
| 20884 | if (block.ownerModule().strip) break :codegen_type; | |
| 20885 | zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); | |
| 20886 | try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); | |
| 20887 | } | |
| 20650 | try zcu.outdated.ensureUnusedCapacity(gpa, 1); | |
| 20651 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); | |
| 20652 | errdefer comptime unreachable; // because we don't remove the `outdated` entry | |
| 20653 | zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); | |
| 20654 | zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); | |
| 20888 | 20655 | |
| 20889 | try sema.addTypeReferenceEntry(src, .fromInterned(wip_ty.index)); | |
| 20890 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index); | |
| 20891 | return .fromIntern(wip_ty.finish(ip, new_namespace_index)); | |
| 20656 | return .fromIntern(wip.finish(ip, new_namespace_index)); | |
| 20657 | }, | |
| 20658 | } | |
| 20892 | 20659 | } |
| 20893 | 20660 | |
| 20894 | 20661 | fn 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 | 20676 | const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.lhs); |
| 20910 | 20677 | const arg_ty = try sema.resolveType(block, ty_src, extra.rhs); |
| 20911 | 20678 | |
| 20912 | if (!try sema.validateExternType(arg_ty, .param_ty)) { | |
| 20679 | if (!arg_ty.validateExtern(.param_ty, sema.pt.zcu)) { | |
| 20913 | 20680 | const msg = msg: { |
| 20914 | 20681 | const msg = try sema.errMsg(ty_src, "cannot get '{f}' from variadic argument", .{arg_ty.fmt(sema.pt)}); |
| 20915 | 20682 | errdefer msg.destroy(sema.gpa); |
| ... | ... | @@ -24205,8 +23972,8 @@ fn zirMemcpy( |
| 24205 | 23972 | return sema.failWithOwnedErrorMsg(block, msg); |
| 24206 | 23973 | } |
| 24207 | 23974 | |
| 24208 | const dest_elem_ty = dest_ty.indexablePtrElem(zcu); | |
| 24209 | const src_elem_ty = src_ty.indexablePtrElem(zcu); | |
| 23975 | const dest_elem_ty = dest_ty.indexableElem(zcu); | |
| 23976 | const src_elem_ty = src_ty.indexableElem(zcu); | |
| 24210 | 23977 | |
| 24211 | 23978 | try sema.ensureLayoutResolved(dest_elem_ty); |
| 24212 | 23979 | try sema.ensureLayoutResolved(src_elem_ty); |
| ... | ... | @@ -24906,7 +24673,7 @@ fn zirBuiltinExtern( |
| 24906 | 24673 | if (!ty.isPtrAtRuntime(zcu)) { |
| 24907 | 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 | 24677 | const msg = msg: { |
| 24911 | 24678 | const msg = try sema.errMsg(ty_src, "extern symbol cannot have type '{f}'", .{ty.fmt(pt)}); |
| 24912 | 24679 | errdefer msg.destroy(sema.gpa); |
| ... | ... | @@ -24954,7 +24721,7 @@ fn zirBuiltinExtern( |
| 24954 | 24721 | // So, for now, just use our containing `declaration`. |
| 24955 | 24722 | .zir_index = switch (sema.owner.unwrap()) { |
| 24956 | 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 | 24725 | .memoized_state => unreachable, |
| 24959 | 24726 | .nav_ty, .nav_val => |nav| ip.getNav(nav).analysis.?.zir_index, |
| 24960 | 24727 | .func => |func| zir_index: { |
| ... | ... | @@ -25060,6 +24827,7 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD |
| 25060 | 24827 | // Values are handled here. |
| 25061 | 24828 | .calling_convention_c => { |
| 25062 | 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 | 24831 | return try sema.namespaceLookupVal( |
| 25064 | 24832 | block, |
| 25065 | 24833 | src, |
| ... | ... | @@ -25068,17 +24836,15 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD |
| 25068 | 24836 | ) orelse @panic("std.builtin is corrupt"); |
| 25069 | 24837 | }, |
| 25070 | 24838 | .calling_convention_inline => { |
| 25071 | comptime assert(@typeInfo(std.builtin.CallingConvention.Tag).@"enum".tag_type == u8); | |
| 25072 | 24839 | const callconv_ty = try sema.getBuiltinType(src, .CallingConvention); |
| 25073 | const callconv_tag_ty = callconv_ty.unionTagType(zcu) orelse @panic("std.builtin is corrupt"); | |
| 25074 | const inline_tag_val = try pt.enumValue( | |
| 25075 | callconv_tag_ty, | |
| 25076 | (try pt.intValue( | |
| 25077 | .u8, | |
| 25078 | @intFromEnum(std.builtin.CallingConvention.@"inline"), | |
| 25079 | )).toIntern(), | |
| 25080 | ); | |
| 25081 | return sema.coerce(block, callconv_ty, Air.internedToRef(inline_tag_val.toIntern()), src); | |
| 24840 | return .fromValue(Value.uninterpret( | |
| 24841 | @as(std.builtin.CallingConvention, .@"inline"), | |
| 24842 | callconv_ty, | |
| 24843 | pt, | |
| 24844 | ) catch |err| switch (err) { | |
| 24845 | error.TypeMismatch => @panic("std.builtin is corrupt"), | |
| 24846 | error.OutOfMemory => |e| return e, | |
| 24847 | }); | |
| 25082 | 24848 | }, |
| 25083 | 24849 | }; |
| 25084 | 24850 | return .fromType(try sema.getBuiltinType(src, builtin_type)); |
| ... | ... | @@ -25180,7 +24946,7 @@ pub fn validateVarType( |
| 25180 | 24946 | const zcu = pt.zcu; |
| 25181 | 24947 | var_ty.assertHasLayout(zcu); |
| 25182 | 24948 | if (is_extern) { |
| 25183 | if (!try sema.validateExternType(var_ty, .other)) { | |
| 24949 | if (!var_ty.validateExtern(.other, zcu)) { | |
| 25184 | 24950 | const msg = msg: { |
| 25185 | 24951 | const msg = try sema.errMsg(src, "extern variable cannot have type '{f}'", .{var_ty.fmt(pt)}); |
| 25186 | 24952 | errdefer msg.destroy(sema.gpa); |
| ... | ... | @@ -25296,124 +25062,17 @@ fn explainWhyTypeIsComptime( |
| 25296 | 25062 | } |
| 25297 | 25063 | } |
| 25298 | 25064 | |
| 25299 | const ExternPosition = enum { | |
| 25300 | ret_ty, | |
| 25301 | param_ty, | |
| 25302 | union_field, | |
| 25303 | struct_field, | |
| 25304 | element, | |
| 25305 | other, | |
| 25306 | }; | |
| 25307 | ||
| 25308 | /// Returns true if `ty` is allowed in extern types. | |
| 25309 | /// Does not require `ty` to be resolved in any way. | |
| 25310 | pub fn validateExternType( | |
| 25311 | sema: *Sema, | |
| 25312 | ty: Type, | |
| 25313 | position: ExternPosition, | |
| 25314 | ) !bool { | |
| 25315 | const pt = sema.pt; | |
| 25316 | const zcu = pt.zcu; | |
| 25317 | switch (ty.zigTypeTag(zcu)) { | |
| 25318 | .type, | |
| 25319 | .comptime_float, | |
| 25320 | .comptime_int, | |
| 25321 | .enum_literal, | |
| 25322 | .undefined, | |
| 25323 | .null, | |
| 25324 | .error_union, | |
| 25325 | .error_set, | |
| 25326 | .frame, | |
| 25327 | => return false, | |
| 25328 | .void => return switch (position) { | |
| 25329 | .ret_ty, | |
| 25330 | .union_field, | |
| 25331 | .struct_field, | |
| 25332 | .element, | |
| 25333 | => true, | |
| 25334 | .param_ty, | |
| 25335 | .other, | |
| 25336 | => false, | |
| 25337 | }, | |
| 25338 | .noreturn => return position == .ret_ty, | |
| 25339 | .@"opaque", | |
| 25340 | .bool, | |
| 25341 | .float, | |
| 25342 | .@"anyframe", | |
| 25343 | => return true, | |
| 25344 | .pointer => { | |
| 25345 | if (ty.isSlice(zcu)) return false; | |
| 25346 | const child_ty = ty.childType(zcu); | |
| 25347 | if (child_ty.zigTypeTag(zcu) == .@"fn") { | |
| 25348 | return ty.isConstPtr(zcu) and try sema.validateExternType(child_ty, .other); | |
| 25349 | } | |
| 25350 | return true; | |
| 25351 | }, | |
| 25352 | .int => switch (ty.intInfo(zcu).bits) { | |
| 25353 | 0, 8, 16, 32, 64, 128 => return true, | |
| 25354 | else => return false, | |
| 25355 | }, | |
| 25356 | .@"fn" => { | |
| 25357 | if (position != .other) return false; | |
| 25358 | // For now we want to authorize PTX kernel to use zig objects, even if we end up exposing the ABI. | |
| 25359 | // The goal is to experiment with more integrated CPU/GPU code. | |
| 25360 | if (ty.fnCallingConvention(zcu) == .nvptx_kernel) { | |
| 25361 | return true; | |
| 25362 | } | |
| 25363 | return !target_util.fnCallConvAllowsZigTypes(ty.fnCallingConvention(zcu)); | |
| 25364 | }, | |
| 25365 | .@"enum" => { | |
| 25366 | const enum_obj = zcu.intern_pool.loadEnumType(ty.toIntern()); | |
| 25367 | if (!enum_obj.int_tag_is_explicit) return false; | |
| 25368 | return sema.validateExternType(.fromInterned(enum_obj.int_tag_type), position); | |
| 25369 | }, | |
| 25370 | .@"struct" => { | |
| 25371 | const struct_obj = zcu.intern_pool.loadStructType(ty.toIntern()); | |
| 25372 | return switch (struct_obj.layout) { | |
| 25373 | .auto => false, | |
| 25374 | .@"extern" => true, | |
| 25375 | .@"packed" => switch (struct_obj.packed_backing_mode) { | |
| 25376 | .auto => false, | |
| 25377 | .explicit => try sema.validateExternType(.fromInterned(struct_obj.packed_backing_int_type), position), | |
| 25378 | }, | |
| 25379 | }; | |
| 25380 | }, | |
| 25381 | .@"union" => { | |
| 25382 | const union_obj = zcu.intern_pool.loadUnionType(ty.toIntern()); | |
| 25383 | return switch (union_obj.layout) { | |
| 25384 | .auto => false, | |
| 25385 | .@"extern" => true, | |
| 25386 | .@"packed" => switch (union_obj.packed_backing_mode) { | |
| 25387 | .auto => false, | |
| 25388 | .explicit => try sema.validateExternType(.fromInterned(union_obj.packed_backing_int_type), position), | |
| 25389 | }, | |
| 25390 | }; | |
| 25391 | }, | |
| 25392 | .array => { | |
| 25393 | if (position == .ret_ty or position == .param_ty) return false; | |
| 25394 | return sema.validateExternType(ty.childType(zcu), .element); | |
| 25395 | }, | |
| 25396 | .vector => return sema.validateExternType(ty.childType(zcu), .element), | |
| 25397 | .optional => return ty.isPtrLikeOptional(zcu), | |
| 25398 | } | |
| 25399 | } | |
| 25400 | ||
| 25065 | /// Keep in sync with `Type.validateExtern`. | |
| 25401 | 25066 | pub fn explainWhyTypeIsNotExtern( |
| 25402 | 25067 | sema: *Sema, |
| 25403 | 25068 | msg: *Zcu.ErrorMsg, |
| 25404 | 25069 | src_loc: LazySrcLoc, |
| 25405 | 25070 | ty: Type, |
| 25406 | position: ExternPosition, | |
| 25071 | position: Type.ExternPosition, | |
| 25407 | 25072 | ) CompileError!void { |
| 25408 | 25073 | const pt = sema.pt; |
| 25409 | 25074 | const zcu = pt.zcu; |
| 25410 | 25075 | switch (ty.zigTypeTag(zcu)) { |
| 25411 | .@"opaque", | |
| 25412 | .bool, | |
| 25413 | .float, | |
| 25414 | .@"anyframe", | |
| 25415 | => return, | |
| 25416 | ||
| 25417 | 25076 | .type, |
| 25418 | 25077 | .comptime_float, |
| 25419 | 25078 | .comptime_int, |
| ... | ... | @@ -25425,101 +25084,110 @@ pub fn explainWhyTypeIsNotExtern( |
| 25425 | 25084 | .frame, |
| 25426 | 25085 | => return, |
| 25427 | 25086 | |
| 25428 | .pointer => { | |
| 25429 | if (ty.isSlice(zcu)) { | |
| 25430 | try sema.errNote(src_loc, msg, "slices have no guaranteed in-memory representation", .{}); | |
| 25087 | .void => try sema.errNote(src_loc, msg, "'void' is a zero bit type", .{}), | |
| 25088 | .noreturn => try sema.errNote(src_loc, msg, "'noreturn' is only allowed as a return type", .{}), | |
| 25089 | ||
| 25090 | .@"opaque", | |
| 25091 | .bool, | |
| 25092 | .float, | |
| 25093 | .@"anyframe", | |
| 25094 | => unreachable, // these *are* allowed | |
| 25095 | ||
| 25096 | .pointer => if (ty.isSlice(zcu)) { | |
| 25097 | try sema.errNote(src_loc, msg, "slices have no guaranteed in-memory representation", .{}); | |
| 25098 | } else { | |
| 25099 | assert(ty.childType(zcu).zigTypeTag(zcu) == .@"fn"); | |
| 25100 | if (!ty.isConstPtr(zcu)) { | |
| 25101 | try sema.errNote(src_loc, msg, "pointer to extern function must be 'const'", .{}); | |
| 25431 | 25102 | } else { |
| 25432 | const pointee_ty = ty.childType(zcu); | |
| 25433 | if (!ty.isConstPtr(zcu) and pointee_ty.zigTypeTag(zcu) == .@"fn") { | |
| 25434 | try sema.errNote(src_loc, msg, "pointer to extern function must be 'const'", .{}); | |
| 25435 | } | |
| 25436 | try sema.explainWhyTypeIsNotExtern(msg, src_loc, pointee_ty, .other); | |
| 25103 | try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.childType(zcu), .other); | |
| 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 | 25106 | .int => if (!std.math.isPowerOfTwo(ty.intInfo(zcu).bits)) { |
| 25442 | 25107 | try sema.errNote(src_loc, msg, "only integers with 0 or power of two bits are extern compatible", .{}); |
| 25443 | 25108 | } else { |
| 25444 | 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" => { | |
| 25447 | if (position != .other) { | |
| 25448 | try sema.errNote(src_loc, msg, "type has no guaranteed in-memory representation", .{}); | |
| 25449 | try sema.errNote(src_loc, msg, "use '*const ' to make a function pointer type", .{}); | |
| 25450 | return; | |
| 25451 | } | |
| 25452 | switch (ty.fnCallingConvention(zcu)) { | |
| 25453 | .auto => try sema.errNote(src_loc, msg, "extern function must specify calling convention", .{}), | |
| 25454 | .async => try sema.errNote(src_loc, msg, "async function cannot be extern", .{}), | |
| 25455 | .@"inline" => try sema.errNote(src_loc, msg, "inline function cannot be extern", .{}), | |
| 25456 | else => return, | |
| 25457 | } | |
| 25111 | .@"fn" => if (position != .other) { | |
| 25112 | try sema.errNote(src_loc, msg, "type has no guaranteed in-memory representation", .{}); | |
| 25113 | try sema.errNote(src_loc, msg, "use '*const ' to make a function pointer type", .{}); | |
| 25114 | } else switch (ty.fnCallingConvention(zcu)) { | |
| 25115 | .auto => try sema.errNote(src_loc, msg, "extern function must specify calling convention", .{}), | |
| 25116 | else => |cc| try sema.errNote(src_loc, msg, "{t} function cannot be extern", .{cc}), | |
| 25458 | 25117 | }, |
| 25459 | 25118 | .@"enum" => { |
| 25460 | 25119 | const tag_ty = ty.intTagType(zcu); |
| 25461 | 25120 | try sema.errNote(src_loc, msg, "enum tag type '{f}' is not extern compatible", .{tag_ty.fmt(pt)}); |
| 25462 | 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) | |
| 25465 | .@"struct" => try sema.errNote(src_loc, msg, "only extern structs and ABI sized packed structs are extern compatible", .{}), | |
| 25466 | .@"union" => try sema.errNote(src_loc, msg, "only extern unions and ABI sized packed unions are extern compatible", .{}), | |
| 25467 | .array => { | |
| 25468 | if (position == .ret_ty) { | |
| 25469 | return sema.errNote(src_loc, msg, "arrays are not allowed as a return type", .{}); | |
| 25470 | } else if (position == .param_ty) { | |
| 25471 | return sema.errNote(src_loc, msg, "arrays are not allowed as a parameter type", .{}); | |
| 25123 | .@"struct" => { | |
| 25124 | const struct_obj = zcu.intern_pool.loadStructType(ty.toIntern()); | |
| 25125 | switch (struct_obj.layout) { | |
| 25126 | .auto => try sema.errNote(src_loc, msg, "struct with automatic layout has no guaranteed in-memory representation", .{}), | |
| 25127 | .@"extern" => unreachable, | |
| 25128 | .@"packed" => switch (struct_obj.packed_backing_mode) { | |
| 25129 | .auto => try sema.errNote(src_loc, msg, "inferred backing integer of packed struct has unspecified signedness", .{}), | |
| 25130 | .explicit => { | |
| 25131 | const backing_int_ty: Type = .fromInterned(struct_obj.packed_backing_int_type); | |
| 25132 | try sema.errNote(src_loc, msg, "packed struct backing integer type '{f}' is not extern compatible", .{backing_int_ty.fmt(pt)}); | |
| 25133 | try sema.explainWhyTypeIsNotExtern(msg, src_loc, backing_int_ty, position); | |
| 25134 | }, | |
| 25135 | }, | |
| 25136 | } | |
| 25137 | }, | |
| 25138 | .@"union" => { | |
| 25139 | const union_obj = zcu.intern_pool.loadStructType(ty.toIntern()); | |
| 25140 | switch (union_obj.layout) { | |
| 25141 | .auto => try sema.errNote(src_loc, msg, "union with automatic layout has no guaranteed in-memory representation", .{}), | |
| 25142 | .@"extern" => unreachable, | |
| 25143 | .@"packed" => switch (union_obj.packed_backing_mode) { | |
| 25144 | .auto => try sema.errNote(src_loc, msg, "inferred backing integer of packed union has unspecified signedness", .{}), | |
| 25145 | .explicit => { | |
| 25146 | const backing_int_ty: Type = .fromInterned(union_obj.packed_backing_int_type); | |
| 25147 | try sema.errNote(src_loc, msg, "packed union backing integer type '{f}' is not extern compatible", .{backing_int_ty.fmt(pt)}); | |
| 25148 | try sema.explainWhyTypeIsNotExtern(msg, src_loc, backing_int_ty, position); | |
| 25149 | }, | |
| 25150 | }, | |
| 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 | 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 | } |
| 25479 | 25162 | |
| 25480 | pub fn explainWhyTypeIsNotPackable( | |
| 25163 | pub fn explainWhyTypeIsUnpackable( | |
| 25481 | 25164 | sema: *Sema, |
| 25482 | 25165 | msg: *Zcu.ErrorMsg, |
| 25483 | src_loc: LazySrcLoc, | |
| 25484 | ty: Type, | |
| 25166 | src: LazySrcLoc, | |
| 25167 | reason: Type.UnpackableReason, | |
| 25485 | 25168 | ) CompileError!void { |
| 25486 | 25169 | const pt = sema.pt; |
| 25487 | 25170 | const zcu = pt.zcu; |
| 25488 | switch (ty.zigTypeTag(zcu)) { | |
| 25489 | .void, | |
| 25490 | .bool, | |
| 25491 | .float, | |
| 25492 | .int, | |
| 25493 | .vector, | |
| 25494 | .@"enum", | |
| 25495 | => return, | |
| 25496 | .type, | |
| 25497 | .comptime_float, | |
| 25498 | .comptime_int, | |
| 25499 | .enum_literal, | |
| 25500 | .undefined, | |
| 25501 | .null, | |
| 25502 | .frame, | |
| 25503 | .noreturn, | |
| 25504 | .@"opaque", | |
| 25505 | .error_union, | |
| 25506 | .error_set, | |
| 25507 | .@"anyframe", | |
| 25508 | .optional, | |
| 25509 | .array, | |
| 25510 | => try sema.errNote(src_loc, msg, "type has no guaranteed in-memory representation", .{}), | |
| 25511 | .pointer => if (ty.isSlice(zcu)) { | |
| 25512 | try sema.errNote(src_loc, msg, "slices have no guaranteed in-memory representation", .{}); | |
| 25513 | } else { | |
| 25514 | try sema.errNote(src_loc, msg, "comptime-only pointer has no guaranteed in-memory representation", .{}); | |
| 25515 | try sema.explainWhyTypeIsComptime(msg, src_loc, ty); | |
| 25171 | switch (reason) { | |
| 25172 | .comptime_only => try sema.errNote(src, msg, "comptime-only types have no bit-packed representation", .{}), | |
| 25173 | .pointer => { | |
| 25174 | try sema.errNote(src, msg, "pointers cannot be directly bitpacked", .{}); | |
| 25175 | try sema.errNote(src, msg, "consider using 'usize' and '@intFromPtr'", .{}); | |
| 25516 | 25176 | }, |
| 25517 | .@"fn" => { | |
| 25518 | try sema.errNote(src_loc, msg, "type has no guaranteed in-memory representation", .{}); | |
| 25519 | try sema.errNote(src_loc, msg, "use '*const ' to make a function pointer type", .{}); | |
| 25177 | .enum_inferred_int_tag => |enum_ty| { | |
| 25178 | const enum_src = enum_ty.srcLoc(zcu); | |
| 25179 | try sema.errNote(enum_src, msg, "integer tag type of enum is inferred", .{}); | |
| 25180 | try sema.errNote(enum_src, msg, "consider explicitly specifying the integer tag type", .{}); | |
| 25181 | }, | |
| 25182 | .non_packed_struct => |struct_ty| { | |
| 25183 | try sema.errNote(src, msg, "non-packed structs do not have a bit-packed representation", .{}); | |
| 25184 | try sema.addDeclaredHereNote(msg, struct_ty); | |
| 25185 | }, | |
| 25186 | .non_packed_union => |union_ty| { | |
| 25187 | try sema.errNote(src, msg, "non-packed unions do not have a bit-packed representation", .{}); | |
| 25188 | try sema.addDeclaredHereNote(msg, union_ty); | |
| 25520 | 25189 | }, |
| 25521 | .@"struct" => try sema.errNote(src_loc, msg, "struct in packed type must have packed layout", .{}), | |
| 25522 | .@"union" => try sema.errNote(src_loc, msg, "union in packed type must have packed layout", .{}), | |
| 25190 | .other => try sema.errNote(src, msg, "type does not have a bit-packed representation", .{}), | |
| 25523 | 25191 | } |
| 25524 | 25192 | } |
| 25525 | 25193 | |
| ... | ... | @@ -25545,7 +25213,7 @@ fn getPanicIdFunc(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.SimplePanicId) !In |
| 25545 | 25213 | try sema.ensureMemoizedStateResolved(src, .panic); |
| 25546 | 25214 | const panic_fn_index = zcu.builtin_decl_values.get(panic_id.toBuiltin()); |
| 25547 | 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 | 25217 | .func => |owner_func| zcu.intern_pool.funcSetHasErrorTrace(io, owner_func, true), |
| 25550 | 25218 | } |
| 25551 | 25219 | return panic_fn_index; |
| ... | ... | @@ -25962,6 +25630,7 @@ fn fieldVal( |
| 25962 | 25630 | if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| { |
| 25963 | 25631 | return inst; |
| 25964 | 25632 | } |
| 25633 | try sema.ensureLayoutResolved(child_type); | |
| 25965 | 25634 | if (child_type.unionTagType(zcu)) |enum_ty| { |
| 25966 | 25635 | if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index_usize| { |
| 25967 | 25636 | const field_index: u32 = @intCast(field_index_usize); |
| ... | ... | @@ -25974,6 +25643,7 @@ fn fieldVal( |
| 25974 | 25643 | if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| { |
| 25975 | 25644 | return inst; |
| 25976 | 25645 | } |
| 25646 | try sema.ensureLayoutResolved(child_type); | |
| 25977 | 25647 | const field_index_usize = child_type.enumFieldIndex(field_name, zcu) orelse |
| 25978 | 25648 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); |
| 25979 | 25649 | const field_index: u32 = @intCast(field_index_usize); |
| ... | ... | @@ -26195,6 +25865,7 @@ fn fieldPtr( |
| 26195 | 25865 | if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| { |
| 26196 | 25866 | return inst; |
| 26197 | 25867 | } |
| 25868 | try sema.ensureLayoutResolved(child_type); | |
| 26198 | 25869 | if (child_type.unionTagType(zcu)) |enum_ty| { |
| 26199 | 25870 | if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index| { |
| 26200 | 25871 | const field_index_u32: u32 = @intCast(field_index); |
| ... | ... | @@ -26208,6 +25879,7 @@ fn fieldPtr( |
| 26208 | 25879 | if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| { |
| 26209 | 25880 | return inst; |
| 26210 | 25881 | } |
| 25882 | try sema.ensureLayoutResolved(child_type); | |
| 26211 | 25883 | const field_index = child_type.enumFieldIndex(field_name, zcu) orelse { |
| 26212 | 25884 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); |
| 26213 | 25885 | }; |
| ... | ... | @@ -26444,9 +26116,6 @@ fn finishFieldCallBind( |
| 26444 | 26116 | const container_ty = ptr_ty.childType(zcu); |
| 26445 | 26117 | if (container_ty.zigTypeTag(zcu) == .@"struct") { |
| 26446 | 26118 | if (container_ty.structFieldIsComptime(field_index, zcu)) { |
| 26447 | if (!container_ty.isTuple(zcu)) { | |
| 26448 | try sema.ensureFieldInitsResolved(container_ty); | |
| 26449 | } | |
| 26450 | 26119 | const default_val = (try container_ty.structFieldValueComptime(pt, field_index)).?; |
| 26451 | 26120 | return .{ .direct = Air.internedToRef(default_val.toIntern()) }; |
| 26452 | 26121 | } |
| ... | ... | @@ -26623,7 +26292,7 @@ fn structFieldPtrByIndex( |
| 26623 | 26292 | const ptr_field_ty = try pt.ptrType(ptr_ty_data); |
| 26624 | 26293 | |
| 26625 | 26294 | if (field_is_comptime) { |
| 26626 | try sema.ensureFieldInitsResolved(struct_ty); | |
| 26295 | assert(struct_type.field_defaults.get(ip)[field_index] != .none); | |
| 26627 | 26296 | const val = try pt.intern(.{ .ptr = .{ |
| 26628 | 26297 | .ty = ptr_field_ty.toIntern(), |
| 26629 | 26298 | .base_addr = .{ .comptime_field = struct_type.field_defaults.get(ip)[field_index] }, |
| ... | ... | @@ -26647,6 +26316,8 @@ fn structFieldVal( |
| 26647 | 26316 | const zcu = pt.zcu; |
| 26648 | 26317 | const ip = &zcu.intern_pool; |
| 26649 | 26318 | assert(struct_ty.zigTypeTag(zcu) == .@"struct"); |
| 26319 | assert(sema.typeOf(struct_byval).toIntern() == struct_ty.toIntern()); | |
| 26320 | struct_ty.assertHasLayout(zcu); | |
| 26650 | 26321 | |
| 26651 | 26322 | switch (ip.indexToKey(struct_ty.toIntern())) { |
| 26652 | 26323 | .struct_type => { |
| ... | ... | @@ -26655,7 +26326,6 @@ fn structFieldVal( |
| 26655 | 26326 | const field_index = struct_type.nameIndex(ip, field_name) orelse |
| 26656 | 26327 | return sema.failWithBadStructFieldAccess(block, struct_ty, struct_type, field_name_src, field_name); |
| 26657 | 26328 | if (struct_type.field_is_comptime_bits.get(ip, field_index)) { |
| 26658 | try sema.ensureFieldInitsResolved(struct_ty); | |
| 26659 | 26329 | return .fromIntern(struct_type.field_defaults.get(ip)[field_index]); |
| 26660 | 26330 | } |
| 26661 | 26331 | |
| ... | ... | @@ -26886,6 +26556,8 @@ fn unionFieldVal( |
| 26886 | 26556 | const zcu = pt.zcu; |
| 26887 | 26557 | const ip = &zcu.intern_pool; |
| 26888 | 26558 | assert(union_ty.zigTypeTag(zcu) == .@"union"); |
| 26559 | assert(sema.typeOf(union_byval).toIntern() == union_ty.toIntern()); | |
| 26560 | union_ty.assertHasLayout(zcu); | |
| 26889 | 26561 | |
| 26890 | 26562 | const union_obj = zcu.typeToUnion(union_ty).?; |
| 26891 | 26563 | const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); |
| ... | ... | @@ -27149,11 +26821,11 @@ fn validateRuntimeElemAccess( |
| 27149 | 26821 | const msg = try sema.errMsg( |
| 27150 | 26822 | elem_index_src, |
| 27151 | 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 | 26826 | errdefer msg.destroy(sema.gpa); |
| 27155 | 26827 | |
| 27156 | try sema.explainWhyTypeIsComptime(msg, parent_src, parent_ty); | |
| 26828 | try sema.explainWhyTypeIsComptime(msg, parent_src, elem_ty); | |
| 27157 | 26829 | |
| 27158 | 26830 | break :msg msg; |
| 27159 | 26831 | }; |
| ... | ... | @@ -27885,18 +27557,14 @@ fn coerceExtra( |
| 27885 | 27557 | // empty tuple to zero-length slice |
| 27886 | 27558 | // note that this allows coercing to a mutable slice. |
| 27887 | 27559 | if (inst_child_ty.structFieldCount(zcu) == 0) { |
| 27888 | // TODO MLUGG: this is *unacceptably* stupid. we're resolving the child for the alignment value | |
| 27889 | try sema.ensureLayoutResolved(dest_ty.childType(zcu)); | |
| 27890 | const align_val = dest_ty.ptrAlignment(zcu); | |
| 27891 | return Air.internedToRef(try pt.intern(.{ .slice = .{ | |
| 27892 | .ty = dest_ty.toIntern(), | |
| 27893 | .ptr = try pt.intern(.{ .ptr = .{ | |
| 27894 | .ty = dest_ty.slicePtrFieldType(zcu).toIntern(), | |
| 27895 | .base_addr = .int, | |
| 27896 | .byte_offset = align_val.toByteUnits().?, | |
| 27897 | } }), | |
| 27898 | .len = .zero_usize, | |
| 27899 | } })); | |
| 27560 | const empty_array_ty = try pt.arrayType(.{ | |
| 27561 | .len = 0, | |
| 27562 | .child = dest_info.child, | |
| 27563 | .sentinel = dest_info.sentinel, | |
| 27564 | }); | |
| 27565 | const empty_array_val = try pt.aggregateValue(empty_array_ty, &.{}); | |
| 27566 | const empty_array_ptr = try sema.uavRef(empty_array_val.toIntern()); | |
| 27567 | return sema.coerceArrayPtrToSlice(block, dest_ty, empty_array_ptr, inst_src); | |
| 27900 | 27568 | } |
| 27901 | 27569 | |
| 27902 | 27570 | // pointer to tuple to slice |
| ... | ... | @@ -27955,7 +27623,7 @@ fn coerceExtra( |
| 27955 | 27623 | .int, .comptime_int => { |
| 27956 | 27624 | if (maybe_inst_val) |val| { |
| 27957 | 27625 | // comptime-known integer to other number |
| 27958 | if (!(try sema.intFitsInType(val, dest_ty, null))) { | |
| 27626 | if (!val.intFitsInType(dest_ty, null, zcu)) { | |
| 27959 | 27627 | if (!opts.report_err) return error.NotCoercible; |
| 27960 | 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 | 27707 | } |
| 28040 | 27708 | break :int; |
| 28041 | 27709 | }; |
| 27710 | if (val.isUndef(zcu)) { | |
| 27711 | return .fromValue(try pt.undefValue(dest_ty)); | |
| 27712 | } | |
| 28042 | 27713 | const result_val = try pt.floatValue(dest_ty, val.toFloat(f128, zcu)); |
| 28043 | const fits: bool = switch (ip.indexToKey(result_val.toIntern())) { | |
| 28044 | else => unreachable, | |
| 28045 | .undef => true, | |
| 28046 | .float => |float| fits: { | |
| 28047 | var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined; | |
| 28048 | const operand_big_int = val.toBigInt(&buffer, zcu); | |
| 28049 | switch (float.storage) { | |
| 28050 | inline else => |x| { | |
| 28051 | if (!std.math.isFinite(x)) break :fits false; | |
| 28052 | var result_big_int: std.math.big.int.Mutable = .{ | |
| 28053 | .limbs = try sema.arena.alloc(std.math.big.Limb, std.math.big.int.calcLimbLen(x)), | |
| 28054 | .len = undefined, | |
| 28055 | .positive = undefined, | |
| 28056 | }; | |
| 28057 | switch (result_big_int.setFloat(x, .nearest_even)) { | |
| 28058 | .inexact => break :fits false, | |
| 28059 | .exact => {}, | |
| 28060 | } | |
| 28061 | break :fits result_big_int.toConst().eql(operand_big_int); | |
| 28062 | }, | |
| 27714 | const float = ip.indexToKey(result_val.toIntern()).float; | |
| 27715 | var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined; | |
| 27716 | const operand_big_int = val.toBigInt(&buffer, zcu); | |
| 27717 | const fits = switch (float.storage) { | |
| 27718 | inline else => |x| fits: { | |
| 27719 | if (!std.math.isFinite(x)) break :fits false; | |
| 27720 | var result_big_int: std.math.big.int.Mutable = .{ | |
| 27721 | .limbs = try sema.arena.alloc(std.math.big.Limb, std.math.big.int.calcLimbLen(x)), | |
| 27722 | .len = undefined, | |
| 27723 | .positive = undefined, | |
| 27724 | }; | |
| 27725 | switch (result_big_int.setFloat(x, .nearest_even)) { | |
| 27726 | .inexact => break :fits false, | |
| 27727 | .exact => {}, | |
| 28063 | 27728 | } |
| 27729 | break :fits result_big_int.toConst().eql(operand_big_int); | |
| 28064 | 27730 | }, |
| 28065 | 27731 | }; |
| 28066 | 27732 | if (!fits) return sema.fail( |
| ... | ... | @@ -28699,7 +28365,7 @@ pub fn coerceInMemoryAllowed( |
| 28699 | 28365 | // Comptime int to regular int. |
| 28700 | 28366 | if (dest_tag == .int and src_tag == .comptime_int) { |
| 28701 | 28367 | if (src_val) |val| { |
| 28702 | if (!(try sema.intFitsInType(val, dest_ty, null))) { | |
| 28368 | if (!val.intFitsInType(dest_ty, null, zcu)) { | |
| 28703 | 28369 | return .{ .comptime_int_not_coercible = .{ .wanted = dest_ty, .actual = val } }; |
| 28704 | 28370 | } |
| 28705 | 28371 | } |
| ... | ... | @@ -29333,7 +28999,7 @@ fn coerceVarArgParam( |
| 29333 | 28999 | } |
| 29334 | 29000 | }, |
| 29335 | 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 | 29003 | const target = zcu.getTarget(); |
| 29338 | 29004 | const uncasted_info = uncasted_ty.intInfo(zcu); |
| 29339 | 29005 | if (uncasted_info.bits <= target.cTypeBitSize(switch (uncasted_info.signedness) { |
| ... | ... | @@ -29362,7 +29028,7 @@ fn coerceVarArgParam( |
| 29362 | 29028 | }; |
| 29363 | 29029 | |
| 29364 | 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 | 29032 | const msg = msg: { |
| 29367 | 29033 | const msg = try sema.errMsg(inst_src, "cannot pass '{f}' to variadic function", .{coerced_ty.fmt(pt)}); |
| 29368 | 29034 | errdefer msg.destroy(sema.gpa); |
| ... | ... | @@ -33283,12 +32949,12 @@ fn typeIsArrayLike(sema: *Sema, ty: Type) ?ArrayLike { |
| 33283 | 32949 | .elem_ty = ty.childType(zcu), |
| 33284 | 32950 | }, |
| 33285 | 32951 | .@"struct" => { |
| 32952 | if (!ty.isTuple(zcu)) return null; | |
| 33286 | 32953 | const field_count = ty.structFieldCount(zcu); |
| 33287 | 32954 | if (field_count == 0) return .{ |
| 33288 | 32955 | .len = 0, |
| 33289 | 32956 | .elem_ty = .noreturn, |
| 33290 | 32957 | }; |
| 33291 | if (!ty.isTuple(zcu)) return null; | |
| 33292 | 32958 | const elem_ty = ty.fieldType(0, zcu); |
| 33293 | 32959 | for (1..field_count) |i| { |
| 33294 | 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 | 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 | } |
| 33702 | 33368 | |
| 33369 | /// Asserts that the layout of `union_ty` is already resolved. | |
| 33703 | 33370 | fn unionFieldIndex( |
| 33704 | 33371 | sema: *Sema, |
| 33705 | 33372 | block: *Block, |
| ... | ... | @@ -33717,6 +33384,7 @@ fn unionFieldIndex( |
| 33717 | 33384 | return @intCast(field_index); |
| 33718 | 33385 | } |
| 33719 | 33386 | |
| 33387 | /// Asserts that the layout of `struct_ty` is already resolved. | |
| 33720 | 33388 | fn structFieldIndex( |
| 33721 | 33389 | sema: *Sema, |
| 33722 | 33390 | block: *Block, |
| ... | ... | @@ -33811,64 +33479,6 @@ fn intFromFloatScalar( |
| 33811 | 33479 | return pt.getCoerced(cti_result, int_ty); |
| 33812 | 33480 | } |
| 33813 | 33481 | |
| 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`? | |
| 33819 | fn 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 | ||
| 33872 | 33482 | fn intInRange(sema: *Sema, tag_ty: Type, int_val: Value, end: usize) !bool { |
| 33873 | 33483 | const pt = sema.pt; |
| 33874 | 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 | 33496 | // The `tagValueIndex` function call below relies on the type being the integer tag type. |
| 33887 | 33497 | // `getCoerced` assumes the value will fit the new type. |
| 33888 | 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 | 33500 | const int_coerced = try pt.getCoerced(int, int_tag_ty); |
| 33891 | 33501 | return enum_type.tagValueIndex(&zcu.intern_pool, int_coerced.toIntern()) != null; |
| 33892 | 33502 | } |
| ... | ... | @@ -33919,7 +33529,6 @@ fn compareAll( |
| 33919 | 33529 | } |
| 33920 | 33530 | |
| 33921 | 33531 | /// Asserts the values are comparable. Both operands have type `ty`. |
| 33922 | /// MLUGG TODO: move to `Value`? | |
| 33923 | 33532 | fn compareScalar( |
| 33924 | 33533 | sema: *Sema, |
| 33925 | 33534 | lhs: Value, |
| ... | ... | @@ -34422,7 +34031,7 @@ const ComptimeStoreResult = @import("Sema/comptime_ptr_access.zig").ComptimeStor |
| 34422 | 34031 | // MLUGG TODO: decide how to do the namespacing here |
| 34423 | 34032 | pub const type_resolution = @import("Sema/type_resolution.zig"); |
| 34424 | 34033 | pub const ensureLayoutResolved = type_resolution.ensureLayoutResolved; |
| 34425 | pub const ensureFieldInitsResolved = type_resolution.ensureFieldInitsResolved; | |
| 34034 | pub const ensureStructDefaultsResolved = type_resolution.ensureStructDefaultsResolved; | |
| 34426 | 34035 | |
| 34427 | 34036 | pub fn getBuiltinType(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl) SemaError!Type { |
| 34428 | 34037 | assert(decl.kind() == .type); |
| ... | ... | @@ -34644,48 +34253,14 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ |
| 34644 | 34253 | }; |
| 34645 | 34254 | } |
| 34646 | 34255 | |
| 34647 | /// TODO MLUGG: this is a gnarly hack | |
| 34648 | const 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 | }; | |
| 34682 | pub fn createTypeName( | |
| 34256 | fn setTypeName( | |
| 34683 | 34257 | sema: *Sema, |
| 34684 | 34258 | block: *Block, |
| 34259 | wip: *const InternPool.WipContainerType, | |
| 34685 | 34260 | name_strategy: Zir.Inst.NameStrategy, |
| 34686 | 34261 | anon_prefix: []const u8, |
| 34687 | 34262 | inst: Zir.Inst.Index, |
| 34688 | ) CompileError!PartialTypeName { | |
| 34263 | ) CompileError!void { | |
| 34689 | 34264 | const pt = sema.pt; |
| 34690 | 34265 | const zcu = pt.zcu; |
| 34691 | 34266 | const comp = zcu.comp; |
| ... | ... | @@ -34693,13 +34268,26 @@ pub fn createTypeName( |
| 34693 | 34268 | const io = comp.io; |
| 34694 | 34269 | const ip = &zcu.intern_pool; |
| 34695 | 34270 | |
| 34696 | switch (name_strategy) { | |
| 34697 | .anon => {}, // handled after switch | |
| 34698 | .parent => return .{ .exact = .{ | |
| 34699 | .name = block.type_name_ctx, | |
| 34700 | .nav = sema.owner.unwrap().nav_val.toOptional(), | |
| 34701 | } }, | |
| 34702 | .func => func_strat: { | |
| 34271 | strat: switch (name_strategy) { | |
| 34272 | .anon => { | |
| 34273 | // It would be neat to have "struct:line:column" but this name has | |
| 34274 | // to survive incremental updates, where it may have been shifted down | |
| 34275 | // or up to a different line, but unchanged, and thus not unnecessarily | |
| 34276 | // semantically analyzed. | |
| 34277 | // TODO: that would be possible, by detecting line number changes and renaming | |
| 34278 | // types appropriately. However, `@typeName` becomes a problem then. If we remove | |
| 34279 | // that builtin from the language, we can consider this. | |
| 34280 | wip.setName(ip, try ip.getOrPutStringFmt( | |
| 34281 | gpa, | |
| 34282 | io, | |
| 34283 | pt.tid, | |
| 34284 | "{f}__{s}_{d}", | |
| 34285 | .{ block.type_name_ctx.fmt(ip), anon_prefix, @intFromEnum(wip.index) }, | |
| 34286 | .no_embedded_nulls, | |
| 34287 | ), .none); | |
| 34288 | }, | |
| 34289 | .parent => wip.setName(ip, block.type_name_ctx, sema.owner.unwrap().nav_val.toOptional()), | |
| 34290 | .func => { | |
| 34703 | 34291 | const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse return error.AnalysisFail); |
| 34704 | 34292 | const zir_tags = sema.code.instructions.items(.tag); |
| 34705 | 34293 | |
| ... | ... | @@ -34717,7 +34305,9 @@ pub fn createTypeName( |
| 34717 | 34305 | // If not then this is a struct type being returned from a non-generic |
| 34718 | 34306 | // function and the name doesn't matter since it will later |
| 34719 | 34307 | // result in a compile error. |
| 34720 | const arg_val = try sema.resolveValue(arg) orelse break :func_strat; // fall through to anon strat | |
| 34308 | const arg_val = try sema.resolveValue(arg) orelse { | |
| 34309 | continue :strat .anon; | |
| 34310 | }; | |
| 34721 | 34311 | |
| 34722 | 34312 | if (arg_i != 0) w.writeByte(',') catch return error.OutOfMemory; |
| 34723 | 34313 | |
| ... | ... | @@ -34739,431 +34329,28 @@ pub fn createTypeName( |
| 34739 | 34329 | }; |
| 34740 | 34330 | |
| 34741 | 34331 | w.writeByte(')') catch return error.OutOfMemory; |
| 34742 | return .{ .exact = .{ | |
| 34743 | .name = try ip.getOrPutString(gpa, io, pt.tid, aw.written(), .no_embedded_nulls), | |
| 34744 | .nav = .none, | |
| 34745 | } }; | |
| 34332 | const name = try ip.getOrPutString(gpa, io, pt.tid, aw.written(), .no_embedded_nulls); | |
| 34333 | wip.setName(ip, name, .none); | |
| 34746 | 34334 | }, |
| 34747 | 34335 | .dbg_var => { |
| 34748 | 34336 | // TODO: this logic is questionable. We ideally should be traversing the `Block` rather than relying on the order of AstGen instructions. |
| 34749 | 34337 | const ref = inst.toRef(); |
| 34750 | 34338 | const zir_tags = sema.code.instructions.items(.tag); |
| 34751 | 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 | 34341 | .dbg_var_ptr, .dbg_var_val => if (zir_data[i].str_op.operand == ref) { |
| 34754 | return .{ .exact = .{ | |
| 34755 | .name = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}.{s}", .{ | |
| 34756 | block.type_name_ctx.fmt(ip), zir_data[i].str_op.getStr(sema.code), | |
| 34757 | }, .no_embedded_nulls), | |
| 34758 | .nav = .none, | |
| 34759 | } }; | |
| 34342 | break zir_data[i].str_op.getStr(sema.code); | |
| 34760 | 34343 | }, |
| 34761 | 34344 | else => {}, |
| 34345 | } else { | |
| 34346 | continue :strat .anon; | |
| 34762 | 34347 | }; |
| 34763 | // fall through to anon strat | |
| 34348 | const name = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}.{s}", .{ | |
| 34349 | block.type_name_ctx.fmt(ip), var_name, | |
| 34350 | }, .no_embedded_nulls); | |
| 34351 | wip.setName(ip, name, .none); | |
| 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 | ||
| 34784 | pub 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 | } | |
| 34853 | const 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 | }; | |
| 34866 | fn 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 | } | |
| 35044 | const AnalyzeEnumDeclError = error{ | |
| 35045 | OutOfMemory, | |
| 35046 | Canceled, | |
| 35047 | /// `enum(T)` syntax was used, but `T` was not an integer type. | |
| 35048 | ExplicitTagNotInt, | |
| 35049 | }; | |
| 35050 | fn 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 | } | |
| 35129 | fn 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 | } |
| 35168 | 34355 | |
| 35169 | 34356 | fn zirStructDecl( |
| ... | ... | @@ -35173,6 +34360,10 @@ fn zirStructDecl( |
| 35173 | 34360 | ) CompileError!Air.Inst.Ref { |
| 35174 | 34361 | const pt = sema.pt; |
| 35175 | 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; | |
| 35176 | 34367 | |
| 35177 | 34368 | const tracked_inst = try block.trackZir(inst); |
| 35178 | 34369 | |
| ... | ... | @@ -35180,32 +34371,50 @@ fn zirStructDecl( |
| 35180 | 34371 | .base_node_inst = tracked_inst, |
| 35181 | 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 | }; | |
| 35187 | 34374 | |
| 35188 | 34375 | const struct_decl = sema.code.getStructDecl(inst); |
| 35189 | 34376 | |
| 35190 | 34377 | const captures = try sema.getCaptures(block, src, struct_decl.captures, struct_decl.capture_names); |
| 35191 | 34378 | |
| 35192 | const backing_int_type: ?Type = ty: { | |
| 35193 | if (struct_decl.backing_int_type == .none) break :ty null; | |
| 35194 | break :ty try sema.resolveType(block, backing_ty_src, struct_decl.backing_int_type); | |
| 35195 | // MLUGG TODO validate it's an int! | |
| 35196 | }; | |
| 34379 | const ty: Type = switch (try ip.getDeclaredStructType(gpa, io, pt.tid, .{ | |
| 34380 | .zir_index = tracked_inst, | |
| 34381 | .captures = captures, | |
| 34382 | .fields_len = @intCast(struct_decl.field_names.len), | |
| 34383 | .layout = struct_decl.layout, | |
| 34384 | .any_comptime_fields = struct_decl.field_comptime_bits != null, | |
| 34385 | .any_field_defaults = struct_decl.field_default_body_lens != null, | |
| 34386 | .any_field_aligns = struct_decl.field_align_body_lens != null, | |
| 34387 | .packed_backing_mode = if (struct_decl.backing_int_type_body != null) .explicit else .auto, | |
| 34388 | })) { | |
| 34389 | .existing => |ty| .fromInterned(ty), | |
| 34390 | .wip => |wip| ty: { | |
| 34391 | errdefer wip.cancel(ip, pt.tid); | |
| 34392 | try sema.setTypeName(block, &wip, struct_decl.name_strategy, "struct", inst); | |
| 34393 | const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ | |
| 34394 | .parent = block.namespace.toOptional(), | |
| 34395 | .owner_type = wip.index, | |
| 34396 | .file_scope = block.getFileScopeIndex(zcu), | |
| 34397 | .generation = zcu.generation, | |
| 34398 | }); | |
| 34399 | errdefer pt.destroyNamespace(new_namespace_index); | |
| 34400 | try pt.scanNamespace(new_namespace_index, struct_decl.decls); | |
| 34401 | // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind | |
| 34402 | try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) }); | |
| 34403 | try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .struct_defaults = wip.index }) }); | |
| 35197 | 34404 | |
| 35198 | const ty = try analyzeStructDecl( | |
| 35199 | pt, | |
| 35200 | block.getFileScopeIndex(zcu), | |
| 35201 | &sema.code, | |
| 35202 | block.namespace.toOptional(), | |
| 35203 | tracked_inst, | |
| 35204 | &struct_decl, | |
| 35205 | backing_int_type, | |
| 35206 | captures, | |
| 35207 | try sema.createTypeName(block, struct_decl.name_strategy, "struct", inst), | |
| 35208 | ); | |
| 34405 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); | |
| 34406 | ||
| 34407 | try zcu.outdated.ensureUnusedCapacity(gpa, 2); | |
| 34408 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 2); | |
| 34409 | errdefer comptime unreachable; // because we don't remove the `outdated` entries | |
| 34410 | zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); | |
| 34411 | zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .struct_defaults = wip.index }), 0); | |
| 34412 | zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); | |
| 34413 | zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .struct_defaults = wip.index }), {}); | |
| 34414 | ||
| 34415 | break :ty .fromInterned(wip.finish(ip, new_namespace_index)); | |
| 34416 | }, | |
| 34417 | }; | |
| 35209 | 34418 | |
| 35210 | 34419 | try sema.addTypeReferenceEntry(src, ty); |
| 35211 | 34420 | |
| ... | ... | @@ -35234,124 +34443,68 @@ fn zirUnionDecl( |
| 35234 | 34443 | .base_node_inst = tracked_inst, |
| 35235 | 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 | }; | |
| 35241 | 34446 | |
| 35242 | 34447 | const union_decl = sema.code.getUnionDecl(inst); |
| 35243 | 34448 | |
| 35244 | 34449 | const captures = try sema.getCaptures(block, src, union_decl.captures, union_decl.capture_names); |
| 35245 | 34450 | |
| 35246 | const arg_type: ?Type = ty: { | |
| 35247 | if (union_decl.arg_type == .none) break :ty null; | |
| 35248 | break :ty try sema.resolveType(block, arg_ty_src, union_decl.arg_type); | |
| 35249 | }; | |
| 34451 | const ty: Type = switch (try ip.getDeclaredUnionType(gpa, io, pt.tid, .{ | |
| 34452 | .zir_index = tracked_inst, | |
| 34453 | .captures = captures, | |
| 34454 | .fields_len = @intCast(union_decl.field_names.len), | |
| 34455 | .layout = union_decl.kind.layout(), | |
| 34456 | .any_field_aligns = union_decl.field_align_body_lens != null, | |
| 34457 | .runtime_tag = switch (union_decl.kind) { | |
| 34458 | .auto => if (block.wantSafeTypes()) .safety else .none, | |
| 35250 | 34459 | |
| 35251 | const ty = analyzeUnionDecl( | |
| 35252 | pt, | |
| 35253 | block.getFileScopeIndex(zcu), | |
| 35254 | &sema.code, | |
| 35255 | block.namespace.toOptional(), | |
| 35256 | block.wantSafeTypes(), | |
| 35257 | tracked_inst, | |
| 35258 | &union_decl, | |
| 35259 | arg_type, | |
| 35260 | captures, | |
| 35261 | try sema.createTypeName(block, union_decl.name_strategy, "union", inst), | |
| 35262 | ) catch |err| switch (err) { | |
| 35263 | error.OutOfMemory, | |
| 35264 | error.Canceled, | |
| 35265 | => |e| return e, | |
| 35266 | ||
| 35267 | error.ExplicitBackingNotInt => return sema.fail( | |
| 35268 | block, | |
| 35269 | arg_ty_src, | |
| 35270 | "expected integer backing type, found '{f}'", | |
| 35271 | .{arg_type.?.fmt(pt)}, | |
| 35272 | ), | |
| 35273 | error.ExplicitTagNotInt => return sema.fail( | |
| 35274 | block, | |
| 35275 | arg_ty_src, | |
| 35276 | "expected integer tag type, found '{f}'", | |
| 35277 | .{arg_type.?.fmt(pt)}, | |
| 35278 | ), | |
| 35279 | error.ExplicitTagNotEnum => return sema.fail( | |
| 35280 | block, | |
| 35281 | arg_ty_src, | |
| 35282 | "expected enum tag type, found '{f}'", | |
| 35283 | .{arg_type.?.fmt(pt)}, | |
| 35284 | ), | |
| 35285 | error.ExplicitTagFieldMismatch => { | |
| 35286 | const enum_obj = ip.loadEnumType(arg_type.?.toIntern()); | |
| 35287 | const enum_to_union_map = try sema.arena.alloc(?u32, enum_obj.field_names.len); | |
| 35288 | @memset(enum_to_union_map, null); | |
| 35289 | for (union_decl.field_names, 0..) |field_name_zir, union_field_idx| { | |
| 35290 | const field_name_ip = try ip.getOrPutString(gpa, io, pt.tid, sema.code.nullTerminatedString(field_name_zir), .no_embedded_nulls); | |
| 35291 | if (enum_obj.nameIndex(ip, field_name_ip)) |enum_field_idx| { | |
| 35292 | enum_to_union_map[enum_field_idx] = @intCast(union_field_idx); | |
| 35293 | continue; | |
| 35294 | } | |
| 35295 | const union_field_src: LazySrcLoc = .{ | |
| 35296 | .base_node_inst = tracked_inst, | |
| 35297 | .offset = .{ .container_field_name = @intCast(union_field_idx) }, | |
| 35298 | }; | |
| 35299 | return sema.failWithOwnedErrorMsg(block, msg: { | |
| 35300 | const msg = try sema.errMsg(union_field_src, "no field named '{f}' in enum '{f}'", .{ field_name_ip.fmt(ip), arg_type.?.fmt(pt) }); | |
| 35301 | errdefer msg.destroy(gpa); | |
| 35302 | try sema.addDeclaredHereNote(msg, arg_type.?); | |
| 35303 | break :msg msg; | |
| 35304 | }); | |
| 35305 | } | |
| 35306 | for (enum_to_union_map, 0..) |union_field_idx, enum_field_idx| { | |
| 35307 | if (union_field_idx != null) continue; | |
| 35308 | const field_name_ip = enum_obj.field_names.get(ip)[enum_field_idx]; | |
| 35309 | const enum_field_src: LazySrcLoc = .{ | |
| 35310 | .base_node_inst = arg_type.?.typeDeclInstAllowGeneratedTag(zcu).?, | |
| 35311 | .offset = .{ .container_field_name = @intCast(enum_field_idx) }, | |
| 35312 | }; | |
| 35313 | return sema.failWithOwnedErrorMsg(block, msg: { | |
| 35314 | const msg = try sema.errMsg(src, "enum field '{f}' missing from union", .{field_name_ip.fmt(ip)}); | |
| 35315 | errdefer msg.destroy(gpa); | |
| 35316 | try sema.errNote(enum_field_src, msg, "enum field here", .{}); | |
| 35317 | break :msg msg; | |
| 35318 | }); | |
| 35319 | } | |
| 35320 | for (enum_to_union_map, 0..) |union_field_idx, enum_field_idx| { | |
| 35321 | if (union_field_idx.? == enum_field_idx) continue; | |
| 35322 | const field_name = sema.code.nullTerminatedString( | |
| 35323 | union_decl.field_names[union_field_idx.?], | |
| 35324 | ); | |
| 35325 | const union_field_src: LazySrcLoc = .{ | |
| 35326 | .base_node_inst = tracked_inst, | |
| 35327 | .offset = .{ .container_field_name = union_field_idx.? }, | |
| 35328 | }; | |
| 35329 | const enum_field_src: LazySrcLoc = .{ | |
| 35330 | .base_node_inst = arg_type.?.typeDeclInstAllowGeneratedTag(zcu).?, | |
| 35331 | .offset = .{ .container_field_name = @intCast(enum_field_idx) }, | |
| 35332 | }; | |
| 35333 | return sema.failWithOwnedErrorMsg(block, msg: { | |
| 35334 | const msg = try sema.errMsg(src, "union field order does not match tag enum field order", .{}); | |
| 35335 | errdefer msg.destroy(gpa); | |
| 35336 | try sema.errNote(union_field_src, msg, "union field '{s}' is index {d}", .{ field_name, union_field_idx.? }); | |
| 35337 | try sema.errNote(enum_field_src, msg, "enum field '{s}' is index {d}", .{ field_name, enum_field_idx }); | |
| 35338 | break :msg msg; | |
| 35339 | }); | |
| 35340 | } | |
| 35341 | unreachable; | |
| 34460 | .tagged_explicit, | |
| 34461 | .tagged_enum, | |
| 34462 | .tagged_enum_explicit, | |
| 34463 | => .tagged, | |
| 34464 | ||
| 34465 | .@"extern", | |
| 34466 | .@"packed", | |
| 34467 | .packed_explicit, | |
| 34468 | => .none, | |
| 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); | |
| 35344 | 34483 | |
| 35345 | const enum_tag_ty = ty.unionTagTypeHypothetical(zcu); | |
| 35346 | switch (ip.indexToKey(enum_tag_ty.toIntern()).enum_type) { | |
| 35347 | .declared, .reified => {}, | |
| 35348 | .generated_union_tag => |owner_union_ty| { | |
| 35349 | assert(owner_union_ty == ty.toIntern()); | |
| 35350 | // generated tag type [MLUGG] | |
| 35351 | // Enum inits are resolved eagerly. TODO MLUGG: honestly i don't think they SHOULD be lol | |
| 35352 | try sema.ensureFieldInitsResolved(.fromInterned(ip.loadUnionType(ty.toIntern()).enum_tag_type)); | |
| 34484 | const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ | |
| 34485 | .parent = block.namespace.toOptional(), | |
| 34486 | .owner_type = wip.index, | |
| 34487 | .file_scope = block.getFileScopeIndex(zcu), | |
| 34488 | .generation = zcu.generation, | |
| 34489 | }); | |
| 34490 | errdefer pt.destroyNamespace(new_namespace_index); | |
| 34491 | ||
| 34492 | try pt.scanNamespace(new_namespace_index, union_decl.decls); | |
| 34493 | ||
| 34494 | // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind | |
| 34495 | try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) }); | |
| 34496 | ||
| 34497 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); | |
| 34498 | ||
| 34499 | try zcu.outdated.ensureUnusedCapacity(gpa, 1); | |
| 34500 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); | |
| 34501 | errdefer comptime unreachable; // because we don't remove the `outdated` entry | |
| 34502 | zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); | |
| 34503 | zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); | |
| 34504 | ||
| 34505 | break :ty .fromInterned(wip.finish(ip, new_namespace_index)); | |
| 35353 | 34506 | }, |
| 35354 | } | |
| 34507 | }; | |
| 35355 | 34508 | |
| 35356 | 34509 | try sema.addTypeReferenceEntry(src, ty); |
| 35357 | 34510 | |
| ... | ... | @@ -35369,6 +34522,10 @@ fn zirEnumDecl( |
| 35369 | 34522 | ) CompileError!Air.Inst.Ref { |
| 35370 | 34523 | const pt = sema.pt; |
| 35371 | 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; | |
| 35372 | 34529 | |
| 35373 | 34530 | const tracked_inst = try block.trackZir(inst); |
| 35374 | 34531 | |
| ... | ... | @@ -35376,45 +34533,48 @@ fn zirEnumDecl( |
| 35376 | 34533 | .base_node_inst = tracked_inst, |
| 35377 | 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 | }; | |
| 35383 | 34536 | |
| 35384 | 34537 | const enum_decl = sema.code.getEnumDecl(inst); |
| 35385 | 34538 | |
| 35386 | 34539 | const captures = try sema.getCaptures(block, src, enum_decl.captures, enum_decl.capture_names); |
| 35387 | 34540 | |
| 35388 | const tag_type: ?Type = ty: { | |
| 35389 | if (enum_decl.tag_type == .none) break :ty null; | |
| 35390 | break :ty try sema.resolveType(block, tag_ty_src, enum_decl.tag_type); | |
| 35391 | }; | |
| 34541 | const ty: Type = switch (try ip.getDeclaredEnumType(gpa, io, pt.tid, .{ | |
| 34542 | .zir_index = tracked_inst, | |
| 34543 | .captures = captures, | |
| 34544 | .fields_len = @intCast(enum_decl.field_names.len), | |
| 34545 | .nonexhaustive = enum_decl.nonexhaustive, | |
| 34546 | .int_tag_mode = if (enum_decl.tag_type_body != null) .explicit else .auto, | |
| 34547 | })) { | |
| 34548 | .existing => |ty| .fromInterned(ty), | |
| 34549 | .wip => |wip| ty: { | |
| 34550 | errdefer wip.cancel(ip, pt.tid); | |
| 35392 | 34551 | |
| 35393 | const ty = analyzeEnumDecl( | |
| 35394 | pt, | |
| 35395 | block.getFileScopeIndex(zcu), | |
| 35396 | &sema.code, | |
| 35397 | block.namespace.toOptional(), | |
| 35398 | tracked_inst, | |
| 35399 | &enum_decl, | |
| 35400 | tag_type, | |
| 35401 | captures, | |
| 35402 | try sema.createTypeName(block, enum_decl.name_strategy, "enum", inst), | |
| 35403 | ) catch |err| switch (err) { | |
| 35404 | error.OutOfMemory, | |
| 35405 | error.Canceled, | |
| 35406 | => |e| return e, | |
| 35407 | ||
| 35408 | error.ExplicitTagNotInt => return sema.fail( | |
| 35409 | block, | |
| 35410 | tag_ty_src, | |
| 35411 | "expected integer tag type, found '{f}'", | |
| 35412 | .{tag_type.?.fmt(pt)}, | |
| 35413 | ), | |
| 35414 | }; | |
| 34552 | try sema.setTypeName(block, &wip, enum_decl.name_strategy, "enum", inst); | |
| 34553 | ||
| 34554 | const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ | |
| 34555 | .parent = block.namespace.toOptional(), | |
| 34556 | .owner_type = wip.index, | |
| 34557 | .file_scope = block.getFileScopeIndex(zcu), | |
| 34558 | .generation = zcu.generation, | |
| 34559 | }); | |
| 34560 | errdefer pt.destroyNamespace(new_namespace_index); | |
| 35415 | 34561 | |
| 35416 | // Enum inits are resolved eagerly. TODO MLUGG: honestly i don't think they SHOULD be lol | |
| 35417 | try sema.ensureFieldInitsResolved(ty); | |
| 34562 | try pt.scanNamespace(new_namespace_index, enum_decl.decls); | |
| 34563 | ||
| 34564 | // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind | |
| 34565 | try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) }); | |
| 34566 | ||
| 34567 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); | |
| 34568 | ||
| 34569 | try zcu.outdated.ensureUnusedCapacity(gpa, 1); | |
| 34570 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); | |
| 34571 | errdefer comptime unreachable; // because we don't remove the `outdated` entry | |
| 34572 | zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); | |
| 34573 | zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); | |
| 34574 | ||
| 34575 | break :ty .fromInterned(wip.finish(ip, new_namespace_index)); | |
| 34576 | }, | |
| 34577 | }; | |
| 35418 | 34578 | |
| 35419 | 34579 | try sema.addTypeReferenceEntry(src, ty); |
| 35420 | 34580 | |
| ... | ... | @@ -35432,6 +34592,10 @@ fn zirOpaqueDecl( |
| 35432 | 34592 | ) CompileError!Air.Inst.Ref { |
| 35433 | 34593 | const pt = sema.pt; |
| 35434 | 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; | |
| 35435 | 34599 | |
| 35436 | 34600 | const tracked_inst = try block.trackZir(inst); |
| 35437 | 34601 | |
| ... | ... | @@ -35444,15 +34608,26 @@ fn zirOpaqueDecl( |
| 35444 | 34608 | |
| 35445 | 34609 | const captures = try sema.getCaptures(block, src, opaque_decl.captures, opaque_decl.capture_names); |
| 35446 | 34610 | |
| 35447 | const ty = try analyzeOpaqueDecl( | |
| 35448 | pt, | |
| 35449 | block.getFileScopeIndex(zcu), | |
| 35450 | block.namespace.toOptional(), | |
| 35451 | tracked_inst, | |
| 35452 | &opaque_decl, | |
| 35453 | captures, | |
| 35454 | try sema.createTypeName(block, opaque_decl.name_strategy, "opaque", inst), | |
| 35455 | ); | |
| 34611 | const ty: Type = switch (try ip.getDeclaredOpaqueType(gpa, io, pt.tid, .{ | |
| 34612 | .zir_index = tracked_inst, | |
| 34613 | .captures = captures, | |
| 34614 | })) { | |
| 34615 | .existing => |ty| .fromInterned(ty), | |
| 34616 | .wip => |wip| ty: { | |
| 34617 | errdefer wip.cancel(ip, pt.tid); | |
| 34618 | try sema.setTypeName(block, &wip, opaque_decl.name_strategy, "opaque", inst); | |
| 34619 | const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ | |
| 34620 | .parent = block.namespace.toOptional(), | |
| 34621 | .owner_type = wip.index, | |
| 34622 | .file_scope = block.getFileScopeIndex(zcu), | |
| 34623 | .generation = zcu.generation, | |
| 34624 | }); | |
| 34625 | errdefer pt.destroyNamespace(new_namespace_index); | |
| 34626 | try pt.scanNamespace(new_namespace_index, opaque_decl.decls); | |
| 34627 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); | |
| 34628 | break :ty .fromInterned(wip.finish(ip, new_namespace_index)); | |
| 34629 | }, | |
| 34630 | }; | |
| 35456 | 34631 | |
| 35457 | 34632 | try sema.addTypeReferenceEntry(src, ty); |
| 35458 | 34633 |
src/Sema/LowerZon.zig+1-1| ... | ... | @@ -769,7 +769,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool |
| 769 | 769 | const ip = &pt.zcu.intern_pool; |
| 770 | 770 | |
| 771 | 771 | try self.sema.ensureLayoutResolved(res_ty); |
| 772 | try self.sema.ensureFieldInitsResolved(res_ty); | |
| 772 | try self.sema.ensureStructDefaultsResolved(res_ty); | |
| 773 | 773 | const struct_info = self.sema.pt.zcu.typeToStruct(res_ty).?; |
| 774 | 774 | |
| 775 | 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 | 18 | /// `ty` may be any type; its layout is resolved *recursively* if necessary. |
| 19 | 19 | /// Adds incremental dependencies tracking any required type resolution. |
| 20 | 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 | 21 | /// MLUGG TODO: to be clear, i should audit EVERY use of this before PRing |
| 26 | 22 | pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void { |
| 27 | 23 | const pt = sema.pt; |
| ... | ... | @@ -33,7 +29,6 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void { |
| 33 | 29 | .anyframe_type, |
| 34 | 30 | .simple_type, |
| 35 | 31 | .opaque_type, |
| 36 | .enum_type, | |
| 37 | 32 | .error_set_type, |
| 38 | 33 | .inferred_error_set_type, |
| 39 | 34 | => {}, |
| ... | ... | @@ -52,7 +47,7 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void { |
| 52 | 47 | .tuple_type => |tuple| for (tuple.types.get(ip)) |field_ty| { |
| 53 | 48 | try ensureLayoutResolved(sema, .fromInterned(field_ty)); |
| 54 | 49 | }, |
| 55 | .struct_type, .union_type => { | |
| 50 | .struct_type, .union_type, .enum_type => { | |
| 56 | 51 | try sema.declareDependency(.{ .type_layout = ty.toIntern() }); |
| 57 | 52 | if (zcu.analysis_in_progress.contains(.wrap(.{ .type_layout = ty.toIntern() }))) { |
| 58 | 53 | // TODO: better error message |
| ... | ... | @@ -89,36 +84,36 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void { |
| 89 | 84 | } |
| 90 | 85 | } |
| 91 | 86 | |
| 92 | /// Asserts that `ty` is either a `struct` type, or an `enum` type. | |
| 93 | /// If `ty` is a struct, ensures that fields' default values are resolved. | |
| 94 | /// If `ty` is an enum, ensures that fields' integer tag valus are resolved. | |
| 95 | /// Adds incremental dependencies tracking the required type resolution. | |
| 96 | pub fn ensureFieldInitsResolved(sema: *Sema, ty: Type) SemaError!void { | |
| 87 | /// Asserts that `ty` is a non-tuple `struct` type, and ensures that its fields' default values | |
| 88 | /// are resolved. Adds incremental dependencies tracking the required type resolution. | |
| 89 | /// | |
| 90 | /// It is not necessary to call this function to query the values of comptime fields: those values | |
| 91 | /// are available from type *layout* resolution, see `ensureLayoutResolved`. | |
| 92 | pub fn ensureStructDefaultsResolved(sema: *Sema, ty: Type) SemaError!void { | |
| 97 | 93 | const pt = sema.pt; |
| 98 | 94 | const zcu = pt.zcu; |
| 99 | 95 | const ip = &zcu.intern_pool; |
| 100 | switch (ip.indexToKey(ty.toIntern())) { | |
| 101 | .struct_type, .enum_type => {}, | |
| 102 | else => unreachable, // assertion failure | |
| 103 | } | |
| 96 | assert(ip.indexToKey(ty.toIntern()) == .struct_type); | |
| 104 | 97 | |
| 105 | try sema.declareDependency(.{ .type_inits = ty.toIntern() }); | |
| 106 | if (zcu.analysis_in_progress.contains(.wrap(.{ .type_inits = ty.toIntern() }))) { | |
| 98 | try sema.declareDependency(.{ .struct_defaults = ty.toIntern() }); | |
| 99 | if (zcu.analysis_in_progress.contains(.wrap(.{ .struct_defaults = ty.toIntern() }))) { | |
| 107 | 100 | // TODO: better error message |
| 108 | 101 | return sema.failWithOwnedErrorMsg(null, try sema.errMsg( |
| 109 | 102 | ty.srcLoc(zcu), |
| 110 | "{s} '{f}' depends on itself", | |
| 111 | .{ @tagName(ty.zigTypeTag(zcu)), ty.fmt(pt) }, | |
| 103 | "struct '{f}' depends on itself", | |
| 104 | .{ty.fmt(pt)}, | |
| 112 | 105 | )); |
| 113 | 106 | } |
| 114 | try pt.ensureTypeInitsUpToDate(ty); | |
| 107 | try pt.ensureStructDefaultsUpToDate(ty); | |
| 115 | 108 | } |
| 109 | ||
| 116 | 110 | /// Asserts that `struct_ty` is a non-packed non-tuple struct, and that `sema.owner` is that type. |
| 117 | 111 | /// This function *does* register the `src_hash` dependency on the struct. |
| 118 | 112 | pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { |
| 119 | 113 | const pt = sema.pt; |
| 120 | 114 | const zcu = pt.zcu; |
| 121 | 115 | const comp = zcu.comp; |
| 116 | const io = comp.io; | |
| 122 | 117 | const gpa = comp.gpa; |
| 123 | 118 | const ip = &zcu.intern_pool; |
| 124 | 119 | |
| ... | ... | @@ -127,10 +122,6 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { |
| 127 | 122 | const struct_obj = ip.loadStructType(struct_ty.toIntern()); |
| 128 | 123 | const zir_index = struct_obj.zir_index.resolve(ip).?; |
| 129 | 124 | |
| 130 | assert(struct_obj.layout != .@"packed"); | |
| 131 | ||
| 132 | try sema.declareDependency(.{ .src_hash = struct_obj.zir_index }); | |
| 133 | ||
| 134 | 125 | var block: Block = .{ |
| 135 | 126 | .parent = null, |
| 136 | 127 | .sema = sema, |
| ... | ... | @@ -143,39 +134,92 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { |
| 143 | 134 | }; |
| 144 | 135 | defer assert(block.instructions.items.len == 0); |
| 145 | 136 | |
| 146 | const zir_struct = sema.code.getStructDecl(zir_index); | |
| 147 | var field_it = zir_struct.iterateFields(); | |
| 148 | while (field_it.next()) |zir_field| { | |
| 149 | const field_ty_src: LazySrcLoc = .{ | |
| 150 | .base_node_inst = struct_obj.zir_index, | |
| 151 | .offset = .{ .container_field_type = zir_field.idx }, | |
| 152 | }; | |
| 153 | const field_align_src: LazySrcLoc = .{ | |
| 154 | .base_node_inst = struct_obj.zir_index, | |
| 155 | .offset = .{ .container_field_align = zir_field.idx }, | |
| 156 | }; | |
| 137 | // There may be old field names in here from a previous update. | |
| 138 | struct_obj.field_name_map.get(ip).clearRetainingCapacity(); | |
| 139 | ||
| 140 | if (struct_obj.is_reified) { | |
| 141 | // The field names are populated, but we haven't checked for duplicates (nor populated the map) yet. | |
| 142 | for (0..struct_obj.field_names.len) |field_index| { | |
| 143 | const name = struct_obj.field_names.get(ip)[field_index]; | |
| 144 | if (ip.addFieldName(struct_obj.field_names, struct_obj.field_name_map, name)) |prev_field_index| { | |
| 145 | return sema.failWithOwnedErrorMsg(&block, msg: { | |
| 146 | const src = block.nodeOffset(.zero); | |
| 147 | const msg = try sema.errMsg(src, "duplicate struct field '{f}' at index '{d}", .{ name.fmt(ip), field_index }); | |
| 148 | errdefer msg.destroy(gpa); | |
| 149 | try sema.errNote(src, msg, "previous field at index '{d}'", .{prev_field_index}); | |
| 150 | break :msg msg; | |
| 151 | }); | |
| 152 | } | |
| 153 | } | |
| 154 | } else { | |
| 155 | // Declared structs do not yet have field information populated: | |
| 156 | // * field names | |
| 157 | // * field comptime-ness | |
| 158 | // * field types | |
| 159 | // * field aligns | |
| 160 | // It's our job to populate these now. | |
| 161 | try sema.declareDependency(.{ .src_hash = struct_obj.zir_index }); | |
| 162 | ||
| 163 | // Likewise, comptime bits may be set. We clear them all first because it avoids needing | |
| 164 | // "unset bit with AND" logic below (instead we only need the "set bit with OR" case). | |
| 165 | @memset(struct_obj.field_is_comptime_bits.getAll(ip), 0); | |
| 166 | ||
| 167 | const zir_struct = sema.code.getStructDecl(zir_index); | |
| 168 | var field_it = zir_struct.iterateFields(); | |
| 169 | while (field_it.next()) |zir_field| { | |
| 170 | { | |
| 171 | const name_slice = sema.code.nullTerminatedString(zir_field.name); | |
| 172 | const name = try ip.getOrPutString(gpa, io, pt.tid, name_slice, .no_embedded_nulls); | |
| 173 | assert(ip.addFieldName(struct_obj.field_names, struct_obj.field_name_map, name) == null); // AstGen validated this for us | |
| 174 | } | |
| 157 | 175 | |
| 158 | const field_ty: Type = field_ty: { | |
| 159 | block.comptime_reason = .{ .reason = .{ | |
| 160 | .src = field_ty_src, | |
| 161 | .r = .{ .simple = .struct_field_types }, | |
| 162 | } }; | |
| 163 | const type_ref = try sema.resolveInlineBody(&block, zir_field.type_body, zir_index); | |
| 164 | break :field_ty try sema.analyzeAsType(&block, field_ty_src, type_ref); | |
| 165 | }; | |
| 166 | assert(!field_ty.isGenericPoison()); | |
| 176 | if (zir_field.is_comptime) { | |
| 177 | const bit_bag_index = zir_field.idx / 32; | |
| 178 | const mask = @as(u32, 1) << @intCast(zir_field.idx % 32); | |
| 179 | struct_obj.field_is_comptime_bits.getAll(ip)[bit_bag_index] |= mask; | |
| 180 | } | |
| 167 | 181 | |
| 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 | } | |
| 169 | 194 | |
| 170 | const explicit_field_align: Alignment = a: { | |
| 171 | block.comptime_reason = .{ .reason = .{ | |
| 172 | .src = field_align_src, | |
| 173 | .r = .{ .simple = .struct_field_attrs }, | |
| 174 | } }; | |
| 175 | const align_body = zir_field.align_body orelse break :a .none; | |
| 176 | const align_ref = try sema.resolveInlineBody(&block, align_body, zir_index); | |
| 177 | break :a try sema.analyzeAsAlign(&block, field_align_src, align_ref); | |
| 178 | }; | |
| 195 | if (struct_obj.field_aligns.len == 0) { | |
| 196 | assert(zir_field.align_body == null); | |
| 197 | } else { | |
| 198 | const field_align_src = block.src(.{ .container_field_align = zir_field.idx }); | |
| 199 | const field_align: Alignment = a: { | |
| 200 | block.comptime_reason = .{ .reason = .{ | |
| 201 | .src = field_align_src, | |
| 202 | .r = .{ .simple = .struct_field_attrs }, | |
| 203 | } }; | |
| 204 | const align_body = zir_field.align_body orelse break :a .none; | |
| 205 | const align_ref = try sema.resolveInlineBody(&block, align_body, zir_index); | |
| 206 | break :a try sema.analyzeAsAlign(&block, field_align_src, align_ref); | |
| 207 | }; | |
| 208 | struct_obj.field_aligns.get(ip)[zir_field.idx] = field_align; | |
| 209 | } | |
| 210 | } | |
| 211 | } | |
| 212 | ||
| 213 | if (struct_obj.layout == .@"packed") { | |
| 214 | return resolvePackedStructLayout(sema, &block, struct_ty, &struct_obj); | |
| 215 | } | |
| 216 | ||
| 217 | // Resolve the layout of all fields, and check their types are allowed. | |
| 218 | for (struct_obj.field_types.get(ip), 0..) |field_ty_ip, field_index| { | |
| 219 | const field_ty: Type = .fromInterned(field_ty_ip); | |
| 220 | assert(!field_ty.isGenericPoison()); | |
| 221 | const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) }); | |
| 222 | try sema.ensureLayoutResolved(field_ty); | |
| 179 | 223 | |
| 180 | 224 | if (field_ty.zigTypeTag(zcu) == .@"opaque") { |
| 181 | 225 | return sema.failWithOwnedErrorMsg(&block, msg: { |
| ... | ... | @@ -186,7 +230,8 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { |
| 186 | 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 | 235 | return sema.failWithOwnedErrorMsg(&block, msg: { |
| 191 | 236 | const msg = try sema.errMsg(field_ty_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); |
| 192 | 237 | errdefer msg.destroy(gpa); |
| ... | ... | @@ -195,35 +240,14 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { |
| 195 | 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 | } |
| 206 | 244 | |
| 207 | try finishStructLayout(sema, &block, struct_ty.srcLoc(zcu), struct_ty.toIntern(), &struct_obj); | |
| 208 | } | |
| 245 | // Fields are okay. Now we need to resolve the struct's overall layout (size, field offsets, etc). | |
| 209 | 246 | |
| 210 | /// Called after populating field types and alignments; populates field offsets, runtime order, and | |
| 211 | /// overall struct layout information (size, alignment, comptime-only state, etc). | |
| 212 | pub fn finishStructLayout( | |
| 213 | sema: *Sema, | |
| 214 | /// Only used to report compile errors. | |
| 215 | block: *Block, | |
| 216 | struct_src: LazySrcLoc, | |
| 217 | struct_ty: InternPool.Index, | |
| 218 | struct_obj: *const InternPool.LoadedStructType, | |
| 219 | ) SemaError!void { | |
| 220 | const pt = sema.pt; | |
| 221 | const zcu = pt.zcu; | |
| 222 | const comp = zcu.comp; | |
| 223 | const io = comp.io; | |
| 224 | const ip = &zcu.intern_pool; | |
| 247 | var any_comptime_fields = false; | |
| 225 | 248 | var comptime_only = false; |
| 226 | 249 | var one_possible_value = true; |
| 250 | var has_runtime_bits = false; | |
| 227 | 251 | var struct_align: Alignment = .@"1"; |
| 228 | 252 | // Unlike `struct_obj.field_aligns`, these are not `.none`. |
| 229 | 253 | const resolved_field_aligns = try sema.arena.alloc(Alignment, struct_obj.field_names.len); |
| ... | ... | @@ -240,12 +264,15 @@ pub fn finishStructLayout( |
| 240 | 264 | // Non-`comptime` fields contribute to the struct's layout. |
| 241 | 265 | struct_align = struct_align.maxStrict(field_align); |
| 242 | 266 | if (field_ty.comptimeOnly(zcu)) comptime_only = true; |
| 267 | if (field_ty.hasRuntimeBits(zcu)) has_runtime_bits = true; | |
| 243 | 268 | if (try field_ty.onePossibleValue(pt) == null) one_possible_value = false; |
| 244 | 269 | if (struct_obj.layout == .auto) { |
| 245 | 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 | 274 | 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 | 277 | align_out.* = field_align; |
| 251 | 278 | } |
| ... | ... | @@ -297,75 +324,53 @@ pub fn finishStructLayout( |
| 297 | 324 | cur_offset = offset + field_ty.abiSize(zcu); |
| 298 | 325 | } |
| 299 | 326 | const struct_size = std.math.cast(u32, struct_align.forward(cur_offset)) orelse return sema.fail( |
| 300 | block, | |
| 301 | struct_src, | |
| 327 | &block, | |
| 328 | struct_ty.srcLoc(zcu), | |
| 302 | 329 | "struct layout requires size {d}, this compiler implementation supports up to {d}", |
| 303 | 330 | .{ struct_align.forward(cur_offset), std.math.maxInt(u32) }, |
| 304 | 331 | ); |
| 305 | 332 | ip.resolveStructLayout( |
| 306 | 333 | io, |
| 307 | struct_ty, | |
| 334 | struct_ty.toIntern(), | |
| 308 | 335 | struct_size, |
| 309 | 336 | struct_align, |
| 310 | 337 | false, // MLUGG TODO XXX NPV |
| 311 | 338 | one_possible_value, |
| 312 | 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 | } |
| 315 | 348 | |
| 316 | 349 | /// Asserts that `struct_ty` is a packed struct, and that `sema.owner` is that type. |
| 317 | 350 | /// This function *does* register the `src_hash` dependency on the struct. |
| 318 | pub fn resolvePackedStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { | |
| 351 | fn resolvePackedStructLayout( | |
| 352 | sema: *Sema, | |
| 353 | block: *Block, | |
| 354 | struct_ty: Type, | |
| 355 | struct_obj: *const InternPool.LoadedStructType, | |
| 356 | ) CompileError!void { | |
| 319 | 357 | const pt = sema.pt; |
| 320 | 358 | const zcu = pt.zcu; |
| 321 | 359 | const comp = zcu.comp; |
| 360 | const io = comp.io; | |
| 322 | 361 | const gpa = comp.gpa; |
| 323 | 362 | const ip = &zcu.intern_pool; |
| 324 | 363 | |
| 325 | assert(sema.owner.unwrap().type_layout == struct_ty.toIntern()); | |
| 326 | ||
| 327 | const struct_obj = ip.loadStructType(struct_ty.toIntern()); | |
| 328 | const zir_index = struct_obj.zir_index.resolve(ip).?; | |
| 329 | ||
| 330 | assert(struct_obj.layout == .@"packed"); | |
| 331 | ||
| 332 | try sema.declareDependency(.{ .src_hash = struct_obj.zir_index }); | |
| 333 | ||
| 334 | var block: Block = .{ | |
| 335 | .parent = null, | |
| 336 | .sema = sema, | |
| 337 | .namespace = struct_obj.namespace, | |
| 338 | .instructions = .{}, | |
| 339 | .inlining = null, | |
| 340 | .comptime_reason = undefined, // always set before using `block` | |
| 341 | .src_base_inst = struct_obj.zir_index, | |
| 342 | .type_name_ctx = struct_obj.name, | |
| 343 | }; | |
| 344 | defer assert(block.instructions.items.len == 0); | |
| 345 | ||
| 364 | // Resolve the layout of all fields, and check their types are allowed. | |
| 365 | // Also count the number of bits while we're at it. | |
| 346 | 366 | var field_bits: u64 = 0; |
| 347 | const zir_struct = sema.code.getStructDecl(zir_index); | |
| 348 | var field_it = zir_struct.iterateFields(); | |
| 349 | while (field_it.next()) |zir_field| { | |
| 350 | const field_ty_src: LazySrcLoc = .{ | |
| 351 | .base_node_inst = struct_obj.zir_index, | |
| 352 | .offset = .{ .container_field_type = zir_field.idx }, | |
| 353 | }; | |
| 354 | const field_ty: Type = field_ty: { | |
| 355 | block.comptime_reason = .{ .reason = .{ | |
| 356 | .src = field_ty_src, | |
| 357 | .r = .{ .simple = .struct_field_types }, | |
| 358 | } }; | |
| 359 | const type_ref = try sema.resolveInlineBody(&block, zir_field.type_body, zir_index); | |
| 360 | break :field_ty try sema.analyzeAsType(&block, field_ty_src, type_ref); | |
| 361 | }; | |
| 367 | for (struct_obj.field_types.get(ip), 0..) |field_ty_ip, field_index| { | |
| 368 | const field_ty: Type = .fromInterned(field_ty_ip); | |
| 362 | 369 | assert(!field_ty.isGenericPoison()); |
| 363 | struct_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern(); | |
| 364 | ||
| 370 | const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) }); | |
| 365 | 371 | try sema.ensureLayoutResolved(field_ty); |
| 366 | ||
| 367 | 372 | if (field_ty.zigTypeTag(zcu) == .@"opaque") { |
| 368 | return sema.failWithOwnedErrorMsg(&block, msg: { | |
| 373 | return sema.failWithOwnedErrorMsg(block, msg: { | |
| 369 | 374 | const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in struct", .{field_ty.fmt(pt)}); |
| 370 | 375 | errdefer msg.destroy(gpa); |
| 371 | 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 | 378 | break :msg msg; |
| 374 | 379 | }); |
| 375 | 380 | } |
| 376 | if (!field_ty.packable(zcu)) { | |
| 377 | return sema.failWithOwnedErrorMsg(&block, msg: { | |
| 378 | const msg = try sema.errMsg(field_ty_src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | |
| 379 | errdefer msg.destroy(gpa); | |
| 380 | try sema.explainWhyTypeIsNotPackable(msg, field_ty_src, field_ty); | |
| 381 | try sema.addDeclaredHereNote(msg, field_ty); | |
| 382 | break :msg msg; | |
| 383 | }); | |
| 384 | } | |
| 381 | if (field_ty.unpackable(zcu)) |reason| return sema.failWithOwnedErrorMsg(block, msg: { | |
| 382 | const msg = try sema.errMsg(field_ty_src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | |
| 383 | errdefer msg.destroy(gpa); | |
| 384 | try sema.explainWhyTypeIsUnpackable(msg, field_ty_src, reason); | |
| 385 | try sema.addDeclaredHereNote(msg, field_ty); | |
| 386 | break :msg msg; | |
| 387 | }); | |
| 385 | 388 | assert(!field_ty.comptimeOnly(zcu)); // packable types are not comptime-only |
| 386 | 389 | field_bits += field_ty.bitSize(zcu); |
| 387 | 390 | } |
| 388 | 391 | |
| 389 | try resolvePackedStructBackingInt(sema, &block, field_bits, struct_ty, &struct_obj); | |
| 390 | } | |
| 391 | ||
| 392 | pub fn resolvePackedStructBackingInt( | |
| 393 | sema: *Sema, | |
| 394 | block: *Block, | |
| 395 | field_bits: u64, | |
| 396 | struct_ty: Type, | |
| 397 | struct_obj: *const InternPool.LoadedStructType, | |
| 398 | ) SemaError!void { | |
| 399 | const pt = sema.pt; | |
| 400 | const zcu = pt.zcu; | |
| 401 | const comp = zcu.comp; | |
| 402 | const gpa = comp.gpa; | |
| 403 | const io = comp.io; | |
| 404 | const ip = &zcu.intern_pool; | |
| 392 | const explicit_backing_int_ty: ?Type = if (struct_obj.is_reified) ty: { | |
| 393 | break :ty switch (struct_obj.packed_backing_mode) { | |
| 394 | .explicit => .fromInterned(struct_obj.packed_backing_int_type), | |
| 395 | .auto => null, | |
| 396 | }; | |
| 397 | } else ty: { | |
| 398 | const zir_index = struct_obj.zir_index.resolve(ip).?; | |
| 399 | const zir_struct = sema.code.getStructDecl(zir_index); | |
| 400 | const backing_int_type_body = zir_struct.backing_int_type_body orelse { | |
| 401 | break :ty null; // inferred backing type | |
| 402 | }; | |
| 403 | // Explicitly specified, so evaluate the backing int type expression. | |
| 404 | const backing_int_type_src = block.src(.container_arg); | |
| 405 | block.comptime_reason = .{ .reason = .{ | |
| 406 | .src = backing_int_type_src, | |
| 407 | .r = .{ .simple = .packed_struct_backing_int_type }, | |
| 408 | } }; | |
| 409 | const type_ref = try sema.resolveInlineBody(block, backing_int_type_body, zir_index); | |
| 410 | break :ty try sema.analyzeAsType(block, backing_int_type_src, .packed_struct_backing_int_type, type_ref); | |
| 411 | }; | |
| 405 | 412 | |
| 406 | switch (struct_obj.packed_backing_mode) { | |
| 407 | .explicit => { | |
| 408 | // We only need to validate the type. | |
| 409 | const backing_ty: Type = .fromInterned(struct_obj.packed_backing_int_type); | |
| 410 | assert(backing_ty.zigTypeTag(zcu) == .int); | |
| 411 | if (field_bits != backing_ty.intInfo(zcu).bits) return sema.failWithOwnedErrorMsg(block, msg: { | |
| 412 | const src = struct_ty.srcLoc(zcu); | |
| 413 | const msg = try sema.errMsg(src, "backing integer bit width does not match total bit width of fields", .{}); | |
| 414 | errdefer msg.destroy(gpa); | |
| 415 | try sema.errNote(src, msg, "backing integer '{f}' has bit width '{d}'", .{ backing_ty.fmt(pt), backing_ty.bitSize(zcu) }); | |
| 416 | try sema.errNote(src, msg, "struct fields have total bit width '{d}'", .{field_bits}); | |
| 417 | break :msg msg; | |
| 418 | }); | |
| 419 | }, | |
| 420 | .auto => { | |
| 421 | // We need to generate the inferred tag. | |
| 422 | const want_bits = std.math.cast(u16, field_bits) orelse return sema.fail( | |
| 423 | block, | |
| 424 | struct_ty.srcLoc(zcu), | |
| 425 | "packed struct bit width '{d}' exceeds maximum bit width of 65535", | |
| 426 | .{field_bits}, | |
| 427 | ); | |
| 428 | const backing_int = try pt.intType(.unsigned, want_bits); | |
| 429 | ip.resolvePackedStructBackingInt(io, struct_ty.toIntern(), backing_int.toIntern()); | |
| 430 | }, | |
| 431 | } | |
| 413 | // Finally, either validate or infer the backing int type. | |
| 414 | const backing_int_ty: Type = if (explicit_backing_int_ty) |backing_ty| ty: { | |
| 415 | // We only need to validate the type. | |
| 416 | if (backing_ty.zigTypeTag(zcu) != .int) return sema.failWithOwnedErrorMsg(block, msg: { | |
| 417 | const src = struct_ty.srcLoc(zcu); | |
| 418 | const msg = try sema.errMsg(src, "expected backing integer type, found '{f}'", .{backing_ty.fmt(pt)}); | |
| 419 | errdefer msg.destroy(gpa); | |
| 420 | try sema.errNote(src, msg, "backing integer '{f}' has bit width '{d}'", .{ backing_ty.fmt(pt), backing_ty.bitSize(zcu) }); | |
| 421 | try sema.errNote(src, msg, "struct fields have total bit width '{d}'", .{field_bits}); | |
| 422 | break :msg msg; | |
| 423 | }); | |
| 424 | if (field_bits != backing_ty.intInfo(zcu).bits) return sema.failWithOwnedErrorMsg(block, msg: { | |
| 425 | const src = struct_ty.srcLoc(zcu); | |
| 426 | const msg = try sema.errMsg(src, "backing integer bit width does not match total bit width of fields", .{}); | |
| 427 | errdefer msg.destroy(gpa); | |
| 428 | try sema.errNote(src, msg, "backing integer '{f}' has bit width '{d}'", .{ backing_ty.fmt(pt), backing_ty.bitSize(zcu) }); | |
| 429 | try sema.errNote(src, msg, "struct fields have total bit width '{d}'", .{field_bits}); | |
| 430 | break :msg msg; | |
| 431 | }); | |
| 432 | break :ty backing_ty; | |
| 433 | } else ty: { | |
| 434 | // We need to generate the inferred tag. | |
| 435 | const backing_int_bits = std.math.cast(u16, field_bits) orelse return sema.fail( | |
| 436 | block, | |
| 437 | struct_ty.srcLoc(zcu), | |
| 438 | "packed struct bit width '{d}' exceeds maximum bit width of 65535", | |
| 439 | .{field_bits}, | |
| 440 | ); | |
| 441 | break :ty try pt.intType(.unsigned, backing_int_bits); | |
| 442 | }; | |
| 443 | ip.resolvePackedStructLayout( | |
| 444 | io, | |
| 445 | struct_ty.toIntern(), | |
| 446 | backing_int_ty.toIntern(), | |
| 447 | ); | |
| 432 | 448 | } |
| 433 | 449 | |
| 434 | 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 | 452 | pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void { |
| 437 | 453 | const pt = sema.pt; |
| 438 | 454 | const zcu = pt.zcu; |
| 439 | const comp = zcu.comp; | |
| 440 | const gpa = comp.gpa; | |
| 441 | 455 | const ip = &zcu.intern_pool; |
| 442 | 456 | |
| 443 | assert(sema.owner.unwrap().type_inits == struct_ty.toIntern()); | |
| 457 | assert(sema.owner.unwrap().struct_defaults == struct_ty.toIntern()); | |
| 444 | 458 | |
| 445 | 459 | try sema.ensureLayoutResolved(struct_ty); |
| 446 | 460 | |
| 447 | 461 | const struct_obj = ip.loadStructType(struct_ty.toIntern()); |
| 448 | const zir_index = struct_obj.zir_index.resolve(ip).?; | |
| 449 | 462 | |
| 450 | 463 | try sema.declareDependency(.{ .src_hash = struct_obj.zir_index }); |
| 451 | 464 | |
| 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 | 470 | if (struct_obj.field_defaults.len == 0) { |
| 453 | 471 | // The struct has no default field values, so the slice has been omitted. |
| 454 | 472 | return; |
| 455 | 473 | } |
| 456 | 474 | |
| 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 | } | |
| 458 | 482 | |
| 459 | 483 | var block: Block = .{ |
| 460 | 484 | .parent = null, |
| ... | ... | @@ -468,16 +492,30 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void { |
| 468 | 492 | }; |
| 469 | 493 | defer assert(block.instructions.items.len == 0); |
| 470 | 494 | |
| 495 | return resolveStructDefaultsInner(sema, &block, &struct_obj); | |
| 496 | } | |
| 497 | /// MLUGG TODO: i dislike this, see the 'TODO' in the prev func | |
| 498 | fn 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 | 509 | // We'll need to map the struct decl instruction to provide result types |
| 510 | const zir_index = struct_obj.zir_index.resolve(ip).?; | |
| 472 | 511 | try sema.inst_map.ensureSpaceForInstructions(gpa, &.{zir_index}); |
| 473 | 512 | |
| 513 | const field_types = struct_obj.field_types.get(ip); | |
| 514 | ||
| 474 | 515 | const zir_struct = sema.code.getStructDecl(zir_index); |
| 475 | 516 | var field_it = zir_struct.iterateFields(); |
| 476 | 517 | while (field_it.next()) |zir_field| { |
| 477 | const default_val_src: LazySrcLoc = .{ | |
| 478 | .base_node_inst = struct_obj.zir_index, | |
| 479 | .offset = .{ .container_field_value = zir_field.idx }, | |
| 480 | }; | |
| 518 | const default_val_src = block.src(.{ .container_field_value = zir_field.idx }); | |
| 481 | 519 | block.comptime_reason = .{ .reason = .{ |
| 482 | 520 | .src = default_val_src, |
| 483 | 521 | .r = .{ .simple = .struct_field_default_value }, |
| ... | ... | @@ -491,13 +529,13 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void { |
| 491 | 529 | // Provide the result type |
| 492 | 530 | sema.inst_map.putAssumeCapacity(zir_index, .fromIntern(field_ty.toIntern())); |
| 493 | 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); | |
| 497 | const default_val = try sema.resolveConstValue(&block, default_val_src, coerced, null); | |
| 534 | const coerced = try sema.coerce(block, field_ty, uncoerced, default_val_src); | |
| 535 | const default_val = try sema.resolveConstValue(block, default_val_src, coerced, null); | |
| 498 | 536 | if (default_val.canMutateComptimeVarState(zcu)) { |
| 499 | 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 | 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 | 546 | const pt = sema.pt; |
| 509 | 547 | const zcu = pt.zcu; |
| 510 | 548 | const comp = zcu.comp; |
| 549 | const io = comp.io; | |
| 511 | 550 | const gpa = comp.gpa; |
| 512 | 551 | const ip = &zcu.intern_pool; |
| 513 | 552 | |
| ... | ... | @@ -516,10 +555,6 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { |
| 516 | 555 | const union_obj = ip.loadUnionType(union_ty.toIntern()); |
| 517 | 556 | const zir_index = union_obj.zir_index.resolve(ip).?; |
| 518 | 557 | |
| 519 | assert(union_obj.layout != .@"packed"); | |
| 520 | ||
| 521 | try sema.declareDependency(.{ .src_hash = union_obj.zir_index }); | |
| 522 | ||
| 523 | 558 | var block: Block = .{ |
| 524 | 559 | .parent = null, |
| 525 | 560 | .sema = sema, |
| ... | ... | @@ -532,48 +567,169 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { |
| 532 | 567 | }; |
| 533 | 568 | defer assert(block.instructions.items.len == 0); |
| 534 | 569 | |
| 535 | const zir_union = sema.code.getUnionDecl(zir_index); | |
| 536 | var field_it = zir_union.iterateFields(); | |
| 537 | while (field_it.next()) |zir_field| { | |
| 538 | const field_ty_src: LazySrcLoc = .{ | |
| 539 | .base_node_inst = union_obj.zir_index, | |
| 540 | .offset = .{ .container_field_type = zir_field.idx }, | |
| 541 | }; | |
| 542 | const field_align_src: LazySrcLoc = .{ | |
| 543 | .base_node_inst = union_obj.zir_index, | |
| 544 | .offset = .{ .container_field_align = zir_field.idx }, | |
| 570 | // MLUGG TODO: this is fucking ugly bro | |
| 571 | const explicit_enum_tag_ty: ?Type = if (union_obj.is_reified) ty: { | |
| 572 | break :ty switch (union_obj.enum_tag_mode) { | |
| 573 | .explicit => .fromInterned(union_obj.enum_tag_type), | |
| 574 | .auto => null, | |
| 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 | }; | |
| 546 | 636 | |
| 547 | const field_ty: Type = field_ty: { | |
| 548 | block.comptime_reason = .{ .reason = .{ | |
| 549 | .src = field_ty_src, | |
| 550 | .r = .{ .simple = .union_field_types }, | |
| 551 | } }; | |
| 552 | const type_body = zir_field.type_body orelse break :field_ty .void; | |
| 553 | const type_ref = try sema.resolveInlineBody(&block, type_body, zir_index); | |
| 554 | break :field_ty try sema.analyzeAsType(&block, field_ty_src, type_ref); | |
| 555 | }; | |
| 556 | assert(!field_ty.isGenericPoison()); | |
| 557 | union_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern(); | |
| 558 | ||
| 559 | try sema.ensureLayoutResolved(field_ty); | |
| 637 | try sema.ensureLayoutResolved(enum_tag_ty); | |
| 638 | const enum_obj = ip.loadEnumType(enum_tag_ty.toIntern()); | |
| 639 | ||
| 640 | if (union_obj.is_reified) { | |
| 641 | // We have field names in `union_obj.reified_field_names`, but we haven't | |
| 642 | // checked them against the backing type yet. | |
| 643 | const union_field_names = union_obj.reified_field_names.get(ip); | |
| 644 | match_fields: { | |
| 645 | // We can efficiently *check* if the fields match... | |
| 646 | if (union_field_names.len == enum_obj.field_names.len) { | |
| 647 | for (union_field_names, enum_obj.field_names.get(ip)) |union_field_name, enum_field_name| { | |
| 648 | if (!std.mem.eql(u8, union_field_name.toSlice(ip), enum_field_name.toSlice(ip))) break; | |
| 649 | } else { | |
| 650 | break :match_fields; | |
| 651 | } | |
| 652 | } | |
| 653 | // ...but if they don't, reporting a nice error is a little more involved. If some field | |
| 654 | // is present in the enum but not the union, or vice versa, we will report that instead | |
| 655 | // of a generic "field order mismatch" error. Of course, this error is impossible for a | |
| 656 | // generated tag type, because we populated that from the union ZIR! | |
| 657 | assert(enum_obj.owner_union != union_ty.toIntern()); | |
| 658 | return failUnionFieldMismatch(sema, &block, union_field_names, enum_tag_ty, &enum_obj); | |
| 659 | } | |
| 660 | } else { | |
| 661 | // Declared unions do not have field types or aligns populated yet. | |
| 662 | // We also need to check the field names match the backing enum. | |
| 663 | try sema.declareDependency(.{ .src_hash = union_obj.zir_index }); | |
| 664 | const zir_union = sema.code.getUnionDecl(zir_index); | |
| 560 | 665 | |
| 561 | const explicit_field_align: Alignment = a: { | |
| 562 | block.comptime_reason = .{ .reason = .{ | |
| 563 | .src = field_align_src, | |
| 564 | .r = .{ .simple = .union_field_attrs }, | |
| 565 | } }; | |
| 566 | const align_body = zir_field.align_body orelse break :a .none; | |
| 567 | const align_ref = try sema.resolveInlineBody(&block, align_body, zir_index); | |
| 568 | break :a try sema.analyzeAsAlign(&block, field_align_src, align_ref); | |
| 569 | }; | |
| 666 | // We'll first check the field names against the backing enum, and only analyze the types | |
| 667 | // once we know the fields match one-to-one. | |
| 668 | match_fields: { | |
| 669 | // We can efficiently *check* if the fields match... | |
| 670 | if (zir_union.field_names.len == enum_obj.field_names.len) { | |
| 671 | for (zir_union.field_names, enum_obj.field_names.get(ip)) |union_field_name_zir, enum_field_name| { | |
| 672 | const union_field_name_slice = sema.code.nullTerminatedString(union_field_name_zir); | |
| 673 | if (!std.mem.eql(u8, union_field_name_slice, enum_field_name.toSlice(ip))) break; | |
| 674 | } else { | |
| 675 | break :match_fields; | |
| 676 | } | |
| 677 | } | |
| 678 | // ...but if they don't, reporting a nice error is a little more involved. If some field | |
| 679 | // is present in the enum but not the union, or vice versa, we will report that instead | |
| 680 | // of a generic "field order mismatch" error. Of course, this error is impossible for a | |
| 681 | // generated tag type, because we populated that from the union ZIR! | |
| 682 | assert(enum_obj.owner_union != union_ty.toIntern()); | |
| 683 | const union_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, zir_union.field_names.len); | |
| 684 | for (zir_union.field_names, union_field_names) |name_zir, *name| { | |
| 685 | name.* = try ip.getOrPutString(gpa, io, pt.tid, sema.code.nullTerminatedString(name_zir), .no_embedded_nulls); | |
| 686 | } | |
| 687 | return failUnionFieldMismatch(sema, &block, union_field_names, enum_tag_ty, &enum_obj); | |
| 688 | } | |
| 570 | 689 | |
| 571 | if (union_obj.field_aligns.len != 0) { | |
| 572 | union_obj.field_aligns.get(ip)[zir_field.idx] = explicit_field_align; | |
| 573 | } else { | |
| 574 | assert(explicit_field_align == .none); | |
| 690 | // Field names okay; populate types and aligns. | |
| 691 | var field_it = zir_union.iterateFields(); | |
| 692 | while (field_it.next()) |zir_field| { | |
| 693 | const field_ty_src = block.src(.{ .container_field_type = zir_field.idx }); | |
| 694 | const field_ty: Type = field_ty: { | |
| 695 | block.comptime_reason = .{ .reason = .{ | |
| 696 | .src = field_ty_src, | |
| 697 | .r = .{ .simple = .union_field_types }, | |
| 698 | } }; | |
| 699 | const type_body = zir_field.type_body orelse break :field_ty .void; | |
| 700 | const type_ref = try sema.resolveInlineBody(&block, type_body, zir_index); | |
| 701 | break :field_ty try sema.analyzeAsType(&block, field_ty_src, .union_field_types, type_ref); | |
| 702 | }; | |
| 703 | union_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern(); | |
| 704 | ||
| 705 | const field_align_src = block.src(.{ .container_field_align = zir_field.idx }); | |
| 706 | const explicit_field_align: Alignment = a: { | |
| 707 | block.comptime_reason = .{ .reason = .{ | |
| 708 | .src = field_align_src, | |
| 709 | .r = .{ .simple = .union_field_attrs }, | |
| 710 | } }; | |
| 711 | const align_body = zir_field.align_body orelse break :a .none; | |
| 712 | const align_ref = try sema.resolveInlineBody(&block, align_body, zir_index); | |
| 713 | break :a try sema.analyzeAsAlign(&block, field_align_src, align_ref); | |
| 714 | }; | |
| 715 | if (union_obj.field_aligns.len != 0) { | |
| 716 | union_obj.field_aligns.get(ip)[zir_field.idx] = explicit_field_align; | |
| 717 | } else { | |
| 718 | assert(explicit_field_align == .none); | |
| 719 | } | |
| 575 | 720 | } |
| 721 | } | |
| 576 | 722 | |
| 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 | 733 | if (field_ty.zigTypeTag(zcu) == .@"opaque") { |
| 578 | 734 | return sema.failWithOwnedErrorMsg(&block, msg: { |
| 579 | 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 | 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 | 743 | return sema.failWithOwnedErrorMsg(&block, msg: { |
| 588 | 744 | const msg = try sema.errMsg(field_ty_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); |
| 589 | 745 | errdefer msg.destroy(gpa); |
| ... | ... | @@ -594,36 +750,11 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { |
| 594 | 750 | } |
| 595 | 751 | } |
| 596 | 752 | |
| 597 | try finishUnionLayout( | |
| 598 | sema, | |
| 599 | &block, | |
| 600 | union_ty.srcLoc(zcu), | |
| 601 | union_ty.toIntern(), | |
| 602 | &union_obj, | |
| 603 | .fromInterned(union_obj.enum_tag_type), | |
| 604 | ); | |
| 605 | } | |
| 606 | ||
| 607 | /// Called after populating field types and alignments; populates overall union layout | |
| 608 | /// information (size, alignment, comptime-only state, etc). | |
| 609 | pub fn finishUnionLayout( | |
| 610 | sema: *Sema, | |
| 611 | /// Only used to report compile errors. | |
| 612 | block: *Block, | |
| 613 | union_src: LazySrcLoc, | |
| 614 | union_ty: InternPool.Index, | |
| 615 | union_obj: *const InternPool.LoadedUnionType, | |
| 616 | enum_tag_ty: Type, | |
| 617 | ) SemaError!void { | |
| 618 | const pt = sema.pt; | |
| 619 | const zcu = pt.zcu; | |
| 620 | const comp = zcu.comp; | |
| 621 | const io = comp.io; | |
| 622 | const ip = &zcu.intern_pool; | |
| 623 | ||
| 753 | // Fields are okay. Now we need to resolve the union's overall layout (size, alignment, etc). | |
| 624 | 754 | var payload_align: Alignment = .@"1"; |
| 625 | 755 | var payload_size: u64 = 0; |
| 626 | 756 | var comptime_only = false; |
| 757 | var has_runtime_bits = union_obj.runtime_tag != .none and enum_tag_ty.hasRuntimeBits(zcu); | |
| 627 | 758 | var possible_values: enum { none, one, many } = .none; |
| 628 | 759 | for (0..union_obj.field_types.len) |field_idx| { |
| 629 | 760 | const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_idx]); |
| ... | ... | @@ -637,6 +768,7 @@ pub fn finishUnionLayout( |
| 637 | 768 | payload_align = payload_align.maxStrict(field_align); |
| 638 | 769 | payload_size = @max(payload_size, field_ty.abiSize(zcu)); |
| 639 | 770 | if (field_ty.comptimeOnly(zcu)) comptime_only = true; |
| 771 | if (field_ty.hasRuntimeBits(zcu)) has_runtime_bits = true; | |
| 640 | 772 | if (!field_ty.isNoReturn(zcu)) { |
| 641 | 773 | if (try field_ty.onePossibleValue(pt) != null) { |
| 642 | 774 | possible_values = .many; // this field alone has many possible values |
| ... | ... | @@ -664,78 +796,100 @@ pub fn finishUnionLayout( |
| 664 | 796 | }; |
| 665 | 797 | |
| 666 | 798 | const casted_size = std.math.cast(u32, size) orelse return sema.fail( |
| 667 | block, | |
| 668 | union_src, | |
| 799 | &block, | |
| 800 | union_ty.srcLoc(zcu), | |
| 669 | 801 | "union layout requires size {d}, this compiler implementation supports up to {d}", |
| 670 | 802 | .{ size, std.math.maxInt(u32) }, |
| 671 | 803 | ); |
| 672 | 804 | ip.resolveUnionLayout( |
| 673 | 805 | io, |
| 674 | union_ty, | |
| 806 | union_ty.toIntern(), | |
| 807 | enum_tag_ty.toIntern(), | |
| 675 | 808 | casted_size, |
| 676 | 809 | @intCast(padding), // okay because padding is no greater than size |
| 677 | 810 | alignment, |
| 678 | 811 | possible_values == .none, // MLUGG TODO: make sure queries use `LoadedUnionType.has_no_possible_value`! |
| 679 | 812 | possible_values == .one, |
| 680 | 813 | comptime_only, |
| 814 | has_runtime_bits, | |
| 681 | 815 | ); |
| 682 | 816 | } |
| 683 | ||
| 684 | pub fn resolvePackedUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { | |
| 817 | fn failUnionFieldMismatch(sema: *Sema, block: *Block, union_field_names: []const InternPool.NullTerminatedString, enum_tag_ty: Type, enum_obj: *const InternPool.LoadedEnumType) CompileError { | |
| 685 | 818 | const pt = sema.pt; |
| 686 | 819 | const zcu = pt.zcu; |
| 687 | 820 | const comp = zcu.comp; |
| 688 | 821 | const gpa = comp.gpa; |
| 689 | 822 | const ip = &zcu.intern_pool; |
| 690 | ||
| 691 | assert(sema.owner.unwrap().type_layout == union_ty.toIntern()); | |
| 692 | ||
| 693 | const union_obj = ip.loadUnionType(union_ty.toIntern()); | |
| 694 | const zir_index = union_obj.zir_index.resolve(ip).?; | |
| 695 | ||
| 696 | assert(union_obj.layout == .@"packed"); | |
| 697 | ||
| 698 | try sema.declareDependency(.{ .src_hash = union_obj.zir_index }); | |
| 699 | ||
| 700 | var block: Block = .{ | |
| 701 | .parent = null, | |
| 702 | .sema = sema, | |
| 703 | .namespace = union_obj.namespace, | |
| 704 | .instructions = .{}, | |
| 705 | .inlining = null, | |
| 706 | .comptime_reason = undefined, // always set before using `block` | |
| 707 | .src_base_inst = union_obj.zir_index, | |
| 708 | .type_name_ctx = union_obj.name, | |
| 709 | }; | |
| 710 | defer assert(block.instructions.items.len == 0); | |
| 711 | ||
| 712 | const zir_union = sema.code.getUnionDecl(zir_index); | |
| 713 | var field_it = zir_union.iterateFields(); | |
| 714 | while (field_it.next()) |zir_field| { | |
| 715 | const field_ty_src: LazySrcLoc = .{ | |
| 716 | .base_node_inst = union_obj.zir_index, | |
| 717 | .offset = .{ .container_field_type = zir_field.idx }, | |
| 823 | const enum_to_union_map = try sema.arena.alloc(?u32, enum_obj.field_names.len); | |
| 824 | @memset(enum_to_union_map, null); | |
| 825 | for (union_field_names, 0..) |field_name, union_field_index| { | |
| 826 | if (enum_obj.nameIndex(ip, field_name)) |enum_field_index| { | |
| 827 | enum_to_union_map[enum_field_index] = @intCast(union_field_index); | |
| 828 | continue; | |
| 829 | } | |
| 830 | const union_field_src = block.src(.{ .container_field_name = @intCast(union_field_index) }); | |
| 831 | return sema.failWithOwnedErrorMsg(block, msg: { | |
| 832 | const msg = try sema.errMsg(union_field_src, "no field named '{f}' in enum '{f}'", .{ field_name.fmt(ip), enum_tag_ty.fmt(pt) }); | |
| 833 | errdefer msg.destroy(gpa); | |
| 834 | try sema.addDeclaredHereNote(msg, enum_tag_ty); | |
| 835 | break :msg msg; | |
| 836 | }); | |
| 837 | } | |
| 838 | for (enum_to_union_map, 0..) |union_field_index, enum_field_index| { | |
| 839 | if (union_field_index != null) continue; | |
| 840 | const field_name_ip = enum_obj.field_names.get(ip)[enum_field_index]; | |
| 841 | const enum_field_src: LazySrcLoc = .{ | |
| 842 | .base_node_inst = enum_tag_ty.typeDeclInstAllowGeneratedTag(zcu).?, | |
| 843 | .offset = .{ .container_field_name = @intCast(enum_field_index) }, | |
| 718 | 844 | }; |
| 719 | const field_ty: Type = field_ty: { | |
| 720 | block.comptime_reason = .{ .reason = .{ | |
| 721 | .src = field_ty_src, | |
| 722 | .r = .{ .simple = .union_field_types }, | |
| 723 | } }; | |
| 724 | // MLUGG TODO: i think this should probably be a compile error? (if so, it's an astgen one, right?) | |
| 725 | const type_body = zir_field.type_body orelse break :field_ty .void; | |
| 726 | const type_ref = try sema.resolveInlineBody(&block, type_body, zir_index); | |
| 727 | break :field_ty try sema.analyzeAsType(&block, field_ty_src, type_ref); | |
| 845 | return sema.failWithOwnedErrorMsg(block, msg: { | |
| 846 | const msg = try sema.errMsg(block.nodeOffset(.zero), "enum field '{f}' missing from union", .{field_name_ip.fmt(ip)}); | |
| 847 | errdefer msg.destroy(gpa); | |
| 848 | try sema.errNote(enum_field_src, msg, "enum field here", .{}); | |
| 849 | break :msg msg; | |
| 850 | }); | |
| 851 | } | |
| 852 | // The only problem is the field ordering. | |
| 853 | for (enum_to_union_map, 0..) |union_field_index, enum_field_index| { | |
| 854 | if (union_field_index.? == enum_field_index) continue; | |
| 855 | const field_name = enum_obj.field_names.get(ip)[enum_field_index]; | |
| 856 | const union_field_src = block.src(.{ .container_field_name = union_field_index.? }); | |
| 857 | const enum_field_src: LazySrcLoc = .{ | |
| 858 | .base_node_inst = enum_tag_ty.typeDeclInstAllowGeneratedTag(zcu).?, | |
| 859 | .offset = .{ .container_field_name = @intCast(enum_field_index) }, | |
| 728 | 860 | }; |
| 729 | assert(!field_ty.isGenericPoison()); | |
| 730 | union_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern(); | |
| 731 | ||
| 732 | assert(zir_field.align_body == null); // packed union fields cannot be aligned | |
| 733 | assert(zir_field.value_body == null); // packed union fields cannot have tag values | |
| 861 | return sema.failWithOwnedErrorMsg(block, msg: { | |
| 862 | const msg = try sema.errMsg(block.nodeOffset(.zero), "union field order does not match tag enum field order", .{}); | |
| 863 | errdefer msg.destroy(gpa); | |
| 864 | try sema.errNote(union_field_src, msg, "union field '{f}' is index {d}", .{ field_name.fmt(ip), union_field_index.? }); | |
| 865 | try sema.errNote(enum_field_src, msg, "enum field '{f}' is index {d}", .{ field_name.fmt(ip), enum_field_index }); | |
| 866 | break :msg msg; | |
| 867 | }); | |
| 868 | } | |
| 869 | unreachable; // we already determined that *something* is wrong | |
| 870 | } | |
| 871 | fn 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; | |
| 734 | 884 | |
| 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 | 890 | try sema.ensureLayoutResolved(field_ty); |
| 736 | ||
| 737 | 891 | if (field_ty.zigTypeTag(zcu) == .@"opaque") { |
| 738 | return sema.failWithOwnedErrorMsg(&block, msg: { | |
| 892 | return sema.failWithOwnedErrorMsg(block, msg: { | |
| 739 | 893 | const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in union", .{field_ty.fmt(pt)}); |
| 740 | 894 | errdefer msg.destroy(gpa); |
| 741 | 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 | 897 | break :msg msg; |
| 744 | 898 | }); |
| 745 | 899 | } |
| 746 | if (!field_ty.packable(zcu)) { | |
| 747 | return sema.failWithOwnedErrorMsg(&block, msg: { | |
| 748 | const msg = try sema.errMsg(field_ty_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | |
| 900 | if (field_ty.unpackable(zcu)) |reason| return sema.failWithOwnedErrorMsg(block, msg: { | |
| 901 | const msg = try sema.errMsg(field_ty_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | |
| 902 | errdefer msg.destroy(gpa); | |
| 903 | try sema.explainWhyTypeIsUnpackable(msg, field_ty_src, reason); | |
| 904 | try sema.addDeclaredHereNote(msg, field_ty); | |
| 905 | break :msg msg; | |
| 906 | }); | |
| 907 | assert(!field_ty.comptimeOnly(zcu)); // packable types are not comptime-only | |
| 908 | } | |
| 909 | ||
| 910 | const explicit_backing_int_ty: ?Type = if (union_obj.is_reified) ty: { | |
| 911 | switch (union_obj.packed_backing_mode) { | |
| 912 | .explicit => break :ty .fromInterned(union_obj.packed_backing_int_type), | |
| 913 | .auto => break :ty null, | |
| 914 | } | |
| 915 | } else ty: { | |
| 916 | const zir_index = union_obj.zir_index.resolve(ip).?; | |
| 917 | const zir_union = sema.code.getUnionDecl(zir_index); | |
| 918 | const backing_int_type_body = zir_union.arg_type_body orelse { | |
| 919 | break :ty null; // inferred backing type | |
| 920 | }; | |
| 921 | // Explicitly specified, so evaluate the backing int type expression. | |
| 922 | const backing_int_type_src = block.src(.container_arg); | |
| 923 | block.comptime_reason = .{ .reason = .{ | |
| 924 | .src = backing_int_type_src, | |
| 925 | .r = .{ .simple = .packed_union_backing_int_type }, | |
| 926 | } }; | |
| 927 | const type_ref = try sema.resolveInlineBody(block, backing_int_type_body, zir_index); | |
| 928 | break :ty try sema.analyzeAsType(block, backing_int_type_src, .packed_union_backing_int_type, type_ref); | |
| 929 | }; | |
| 930 | ||
| 931 | // Finally, either validate or infer the backing int type. | |
| 932 | const backing_int_ty: Type = if (explicit_backing_int_ty) |backing_ty| ty: { | |
| 933 | const backing_int_bits = backing_ty.intInfo(zcu).bits; | |
| 934 | for (union_obj.field_types.get(ip), 0..) |field_type_ip, field_idx| { | |
| 935 | const field_type: Type = .fromInterned(field_type_ip); | |
| 936 | const field_bits = field_type.bitSize(zcu); | |
| 937 | if (field_bits != backing_int_bits) return sema.failWithOwnedErrorMsg(block, msg: { | |
| 938 | const field_ty_src = block.src(.{ .container_field_type = @intCast(field_idx) }); | |
| 939 | const msg = try sema.errMsg(field_ty_src, "field bit width does not match backing integer", .{}); | |
| 749 | 940 | errdefer msg.destroy(gpa); |
| 750 | try sema.explainWhyTypeIsNotPackable(msg, field_ty_src, field_ty); | |
| 751 | try sema.addDeclaredHereNote(msg, field_ty); | |
| 941 | try sema.errNote(field_ty_src, msg, "field type '{f}' has bit width '{d}'", .{ field_type.fmt(pt), field_bits }); | |
| 942 | try sema.errNote(field_ty_src, msg, "backing integer '{f}' has bit width '{d}'", .{ backing_ty.fmt(pt), backing_int_bits }); | |
| 943 | try sema.errNote(field_ty_src, msg, "all fields in a packed union must have the same bit width", .{}); | |
| 752 | 944 | break :msg msg; |
| 753 | 945 | }); |
| 754 | 946 | } |
| 755 | assert(!field_ty.comptimeOnly(zcu)); // packable types are not comptime-only | |
| 756 | } | |
| 757 | ||
| 758 | try resolvePackedUnionBackingInt(sema, &block, union_ty, &union_obj, false); | |
| 947 | break :ty backing_ty; | |
| 948 | } else if (union_obj.field_types.len == 0) ty: { | |
| 949 | // Special case: there is no first field to infer the type from. Treat the union as empty (zero-bit). | |
| 950 | break :ty .u0; | |
| 951 | } else ty: { | |
| 952 | const field_types = union_obj.field_types.get(ip); | |
| 953 | const first_field_type: Type = .fromInterned(field_types[0]); | |
| 954 | const first_field_bits = first_field_type.bitSize(zcu); | |
| 955 | for (field_types[1..], 1..) |field_type_ip, field_idx| { | |
| 956 | const field_type: Type = .fromInterned(field_type_ip); | |
| 957 | const field_bits = field_type.bitSize(zcu); | |
| 958 | if (field_bits != first_field_bits) return sema.failWithOwnedErrorMsg(block, msg: { | |
| 959 | const first_field_ty_src = block.src(.{ .container_field_type = 0 }); | |
| 960 | const field_ty_src = block.src(.{ .container_field_type = @intCast(field_idx) }); | |
| 961 | const msg = try sema.errMsg(field_ty_src, "field bit width does not match earlier field", .{}); | |
| 962 | errdefer msg.destroy(gpa); | |
| 963 | try sema.errNote(field_ty_src, msg, "field type '{f}' has bit width '{d}'", .{ field_type.fmt(pt), field_bits }); | |
| 964 | try sema.errNote(first_field_ty_src, msg, "other field type '{f}' has bit width '{d}'", .{ first_field_type.fmt(pt), first_field_bits }); | |
| 965 | try sema.errNote(field_ty_src, msg, "all fields in a packed union must have the same bit width", .{}); | |
| 966 | break :msg msg; | |
| 967 | }); | |
| 968 | } | |
| 969 | const backing_int_bits = std.math.cast(u16, first_field_bits) orelse return sema.fail( | |
| 970 | block, | |
| 971 | union_ty.srcLoc(zcu), | |
| 972 | "packed union bit width '{d}' exceeds maximum bit width of 65535", | |
| 973 | .{first_field_bits}, | |
| 974 | ); | |
| 975 | break :ty try pt.intType(.unsigned, backing_int_bits); | |
| 976 | }; | |
| 977 | ip.resolvePackedUnionLayout( | |
| 978 | io, | |
| 979 | union_ty.toIntern(), | |
| 980 | enum_tag_ty.toIntern(), | |
| 981 | backing_int_ty.toIntern(), | |
| 982 | ); | |
| 759 | 983 | } |
| 760 | 984 | |
| 761 | /// MLUGG TODO doc comment; asserts all fields are resolved or whatever | |
| 762 | pub 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 { | |
| 985 | pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void { | |
| 769 | 986 | const pt = sema.pt; |
| 770 | 987 | const zcu = pt.zcu; |
| 771 | 988 | const comp = zcu.comp; |
| 772 | const gpa = comp.gpa; | |
| 773 | 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. | |
| 846 | pub 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 | 990 | const gpa = comp.gpa; |
| 851 | 991 | const ip = &zcu.intern_pool; |
| 852 | 992 | |
| 853 | assert(sema.owner.unwrap().type_inits == enum_ty.toIntern()); | |
| 993 | assert(sema.owner.unwrap().type_layout == enum_ty.toIntern()); | |
| 854 | 994 | |
| 855 | 995 | const enum_obj = ip.loadEnumType(enum_ty.toIntern()); |
| 856 | 996 | |
| 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 | 997 | const maybe_parent_union_obj: ?InternPool.LoadedUnionType = un: { |
| 865 | 998 | if (enum_obj.owner_union == .none) break :un null; |
| 866 | 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).?; | |
| 870 | 1001 | |
| 871 | try sema.declareDependency(.{ .src_hash = tracked_inst }); | |
| 1002 | const tracked_inst = enum_obj.zir_index.unwrap() orelse maybe_parent_union_obj.?.zir_index; | |
| 872 | 1003 | |
| 873 | 1004 | var block: Block = .{ |
| 874 | 1005 | .parent = null, |
| ... | ... | @@ -882,7 +1013,139 @@ pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void { |
| 882 | 1013 | }; |
| 883 | 1014 | defer assert(block.instructions.items.len == 0); |
| 884 | 1015 | |
| 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).?; | |
| 886 | 1149 | |
| 887 | 1150 | // Map the enum (or union) decl instruction to provide the tag type as the result type |
| 888 | 1151 | try sema.inst_map.ensureSpaceForInstructions(gpa, &.{zir_index}); |
| ... | ... | @@ -891,36 +1154,38 @@ pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void { |
| 891 | 1154 | |
| 892 | 1155 | // First, populate any explicitly provided values. This is the part that actually depends on |
| 893 | 1156 | // 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 | 1158 | if (maybe_parent_union_obj) |union_obj| { |
| 896 | const zir_union = sema.code.getUnionDecl(zir_index); | |
| 897 | var field_it = zir_union.iterateFields(); | |
| 898 | while (field_it.next()) |zir_field| { | |
| 899 | const field_val_src: LazySrcLoc = .{ | |
| 900 | .base_node_inst = union_obj.zir_index, | |
| 901 | .offset = .{ .container_field_value = zir_field.idx }, | |
| 902 | }; | |
| 903 | block.comptime_reason = .{ .reason = .{ | |
| 904 | .src = field_val_src, | |
| 905 | .r = .{ .simple = .enum_field_values }, | |
| 906 | } }; | |
| 907 | const value_body = zir_field.value_body orelse { | |
| 908 | enum_obj.field_values.get(ip)[zir_field.idx] = .none; | |
| 909 | continue; | |
| 910 | }; | |
| 911 | const uncoerced = try sema.resolveInlineBody(&block, value_body, zir_index); | |
| 912 | const coerced = try sema.coerce(&block, int_tag_ty, uncoerced, field_val_src); | |
| 913 | const val = try sema.resolveConstValue(&block, field_val_src, coerced, null); | |
| 914 | enum_obj.field_values.get(ip)[zir_field.idx] = val.toIntern(); | |
| 1159 | if (union_obj.is_reified) { | |
| 1160 | // Generated tag type for reified union; values already populated. | |
| 1161 | } else { | |
| 1162 | // Generated tag type for declared union; evaluate the expressions given in the union declaration. | |
| 1163 | const zir_union = sema.code.getUnionDecl(zir_index); | |
| 1164 | var field_it = zir_union.iterateFields(); | |
| 1165 | while (field_it.next()) |zir_field| { | |
| 1166 | const field_val_src = block.src(.{ .container_field_value = zir_field.idx }); | |
| 1167 | block.comptime_reason = .{ .reason = .{ | |
| 1168 | .src = field_val_src, | |
| 1169 | .r = .{ .simple = .enum_field_values }, | |
| 1170 | } }; | |
| 1171 | const value_body = zir_field.value_body orelse { | |
| 1172 | enum_obj.field_values.get(ip)[zir_field.idx] = .none; | |
| 1173 | continue; | |
| 1174 | }; | |
| 1175 | const uncoerced = try sema.resolveInlineBody(&block, value_body, zir_index); | |
| 1176 | const coerced = try sema.coerce(&block, int_tag_ty, uncoerced, field_val_src); | |
| 1177 | const val = try sema.resolveConstValue(&block, field_val_src, coerced, null); | |
| 1178 | enum_obj.field_values.get(ip)[zir_field.idx] = val.toIntern(); | |
| 1179 | } | |
| 915 | 1180 | } |
| 1181 | } else if (enum_obj.is_reified) { | |
| 1182 | // Reified enum; values already populated. | |
| 916 | 1183 | } else { |
| 1184 | // Declared enum; evaluate the expressions given in the enum declaration. | |
| 917 | 1185 | const zir_enum = sema.code.getEnumDecl(zir_index); |
| 918 | 1186 | var field_it = zir_enum.iterateFields(); |
| 919 | 1187 | while (field_it.next()) |zir_field| { |
| 920 | const field_val_src: LazySrcLoc = .{ | |
| 921 | .base_node_inst = enum_obj.zir_index.unwrap().?, | |
| 922 | .offset = .{ .container_field_value = zir_field.idx }, | |
| 923 | }; | |
| 1188 | const field_val_src = block.src(.{ .container_field_value = zir_field.idx }); | |
| 924 | 1189 | block.comptime_reason = .{ .reason = .{ |
| 925 | 1190 | .src = field_val_src, |
| 926 | 1191 | .r = .{ .simple = .enum_field_values }, |
| ... | ... | @@ -940,14 +1205,14 @@ pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void { |
| 940 | 1205 | // field values. This is also where we'll detect duplicates. |
| 941 | 1206 | |
| 942 | 1207 | for (0..enum_obj.field_names.len) |field_idx| { |
| 943 | const field_val_src: LazySrcLoc = .{ | |
| 944 | .base_node_inst = tracked_inst, | |
| 945 | .offset = .{ .container_field_value = @intCast(field_idx) }, | |
| 946 | }; | |
| 1208 | const field_val_src = block.src(.{ .container_field_value = @intCast(field_idx) }); | |
| 947 | 1209 | // If the field value was not specified, compute the implicit value. |
| 948 | 1210 | const field_val = val: { |
| 949 | 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 | 1216 | if (field_idx == 0) { |
| 952 | 1217 | // Implicit value is 0, which is valid for every integer type. |
| 953 | 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 | 1232 | enum_obj.field_values.get(ip)[field_idx] = val; |
| 968 | 1233 | break :val val; |
| 969 | 1234 | }; |
| 970 | const adapter: InternPool.Index.Adapter = .{ .indexes = enum_obj.field_values.get(ip)[0..field_idx] }; | |
| 971 | const gop = field_value_map.get(ip).getOrPutAssumeCapacityAdapted(field_val, adapter); | |
| 972 | if (!gop.found_existing) continue; | |
| 973 | const prev_field_val_src: LazySrcLoc = .{ | |
| 974 | .base_node_inst = tracked_inst, | |
| 975 | .offset = .{ .container_field_value = @intCast(gop.index) }, | |
| 976 | }; | |
| 977 | return sema.failWithOwnedErrorMsg(&block, msg: { | |
| 978 | const msg = try sema.errMsg(field_val_src, "enum tag value '{f}' already taken", .{ | |
| 979 | Value.fromInterned(field_val).fmtValueSema(pt, sema), | |
| 1235 | if (ip.addFieldTagValue(enum_obj.field_values, field_value_map, field_val)) |prev_field_index| { | |
| 1236 | return sema.failWithOwnedErrorMsg(&block, msg: { | |
| 1237 | const prev_field_val_src = block.src(.{ .container_field_value = prev_field_index }); | |
| 1238 | const msg = try sema.errMsg(field_val_src, "enum tag value '{f}' for field '{f}' already taken", .{ | |
| 1239 | Value.fromInterned(field_val).fmtValueSema(pt, sema), | |
| 1240 | enum_obj.field_names.get(ip)[field_idx].fmt(ip), | |
| 1241 | }); | |
| 1242 | errdefer msg.destroy(gpa); | |
| 1243 | try sema.errNote(prev_field_val_src, msg, "previous occurrence in field '{f}'", .{ | |
| 1244 | enum_obj.field_names.get(ip)[prev_field_index].fmt(ip), | |
| 1245 | }); | |
| 1246 | break :msg msg; | |
| 980 | 1247 | }); |
| 981 | errdefer msg.destroy(gpa); | |
| 982 | try sema.errNote(prev_field_val_src, msg, "previous occurrence here", .{}); | |
| 983 | break :msg msg; | |
| 984 | }); | |
| 1248 | } | |
| 985 | 1249 | } |
| 986 | 1250 | |
| 1251 | // MLUGG TODO: fate of this line rests on whether comptime_int is a valid int tag type | |
| 987 | 1252 | if (enum_obj.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) { |
| 988 | 1253 | const fields_len = enum_obj.field_names.len; |
| 989 | 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 | 437 | /// - an enum with an explicit tag type has the ABI size of the integer tag type, |
| 438 | 438 | /// making it one-possible-value only if the integer tag type has 0 bits. |
| 439 | 439 | pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool { |
| 440 | ty.assertHasLayout(zcu); | |
| 440 | 441 | const ip = &zcu.intern_pool; |
| 441 | 442 | return switch (ip.indexToKey(ty.toIntern())) { |
| 442 | 443 | .int_type => |int_type| int_type.bits != 0, |
| ... | ... | @@ -499,14 +500,18 @@ pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool { |
| 499 | 500 | .generic_poison => unreachable, |
| 500 | 501 | }, |
| 501 | 502 | .struct_type => { |
| 502 | // TODO MLUGG: memoize this state when resolving struct? | |
| 503 | 503 | const struct_obj = ip.loadStructType(ty.toIntern()); |
| 504 | for (struct_obj.field_types.get(ip), 0..) |field_ty_ip, field_idx| { | |
| 505 | if (struct_obj.field_is_comptime_bits.get(ip, field_idx)) continue; | |
| 506 | const field_ty: Type = .fromInterned(field_ty_ip); | |
| 507 | if (field_ty.hasRuntimeBits(zcu)) return true; | |
| 504 | switch (struct_obj.layout) { | |
| 505 | .auto, .@"extern" => return struct_obj.has_runtime_bits, | |
| 506 | .@"packed" => return Type.fromInterned(struct_obj.packed_backing_int_type).hasRuntimeBits(zcu), | |
| 507 | } | |
| 508 | }, | |
| 509 | .union_type => { | |
| 510 | const union_obj = ip.loadUnionType(ty.toIntern()); | |
| 511 | switch (union_obj.layout) { | |
| 512 | .auto, .@"extern" => return union_obj.has_runtime_bits, | |
| 513 | .@"packed" => return Type.fromInterned(union_obj.packed_backing_int_type).hasRuntimeBits(zcu), | |
| 508 | 514 | } |
| 509 | return false; | |
| 510 | 515 | }, |
| 511 | 516 | .tuple_type => |tuple| { |
| 512 | 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 | 520 | } |
| 516 | 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 | }, | |
| 533 | 523 | |
| 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 | 525 | .opaque_type => true, |
| 536 | 526 | .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).hasRuntimeBits(zcu), |
| 537 | 527 | |
| ... | ... | @@ -618,17 +608,18 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool { |
| 618 | 608 | .generic_poison, |
| 619 | 609 | => false, |
| 620 | 610 | }, |
| 621 | .struct_type => ip.loadStructType(ty.toIntern()).layout != .auto, | |
| 622 | .union_type => { | |
| 623 | const union_obj = ip.loadUnionType(ty.toIntern()); | |
| 624 | if (union_obj.layout == .auto) return false; | |
| 625 | return switch (union_obj.runtime_tag) { | |
| 626 | .none => true, | |
| 627 | .tagged => false, | |
| 628 | .safety => unreachable, // well-defined layout can't have a safety tag | |
| 629 | }; | |
| 611 | .struct_type => switch (ip.loadStructType(ty.toIntern()).layout) { | |
| 612 | .auto => false, | |
| 613 | .@"extern", .@"packed" => true, | |
| 614 | }, | |
| 615 | .union_type => switch (ip.loadUnionType(ty.toIntern()).layout) { | |
| 616 | .auto => false, | |
| 617 | .@"extern", .@"packed" => true, | |
| 618 | }, | |
| 619 | .enum_type => switch (ip.loadEnumType(ty.toIntern()).int_tag_mode) { | |
| 620 | .explicit => true, | |
| 621 | .auto => false, | |
| 630 | 622 | }, |
| 631 | .enum_type => ip.loadEnumType(ty.toIntern()).int_tag_is_explicit, | |
| 632 | 623 | |
| 633 | 624 | // values, not types |
| 634 | 625 | .undef, |
| ... | ... | @@ -664,28 +655,29 @@ pub fn fnHasRuntimeBits(fn_ty: Type, zcu: *Zcu) bool { |
| 664 | 655 | if (param_ty == .generic_poison_type) return false; |
| 665 | 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 | 667 | if (fn_info.return_type == .generic_poison_type) return false; |
| 668 | 668 | if (Type.fromInterned(fn_info.return_type).comptimeOnly(zcu)) return false; |
| 669 | 669 | if (fn_info.cc == .@"inline") return false; |
| 670 | 670 | return true; |
| 671 | 671 | } |
| 672 | 672 | |
| 673 | pub fn isFnOrHasRuntimeBits(ty: Type, zcu: *Zcu) bool { | |
| 673 | /// Like `hasRuntimeBits`, but also returns `true` for runtime functions. | |
| 674 | pub fn isRuntimeFnOrHasRuntimeBits(ty: Type, zcu: *Zcu) bool { | |
| 674 | 675 | switch (ty.zigTypeTag(zcu)) { |
| 675 | 676 | .@"fn" => return ty.fnHasRuntimeBits(zcu), |
| 676 | 677 | else => return ty.hasRuntimeBits(zcu), |
| 677 | 678 | } |
| 678 | 679 | } |
| 679 | 680 | |
| 680 | /// Same as `isFnOrHasRuntimeBits` but comptime-only types may return a false positive. | |
| 681 | /// MLUGG TODO: this function is a bit silly now... | |
| 682 | pub 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 | ||
| 689 | 681 | pub fn isNoReturn(ty: Type, zcu: *const Zcu) bool { |
| 690 | 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 | 703 | } |
| 712 | 704 | |
| 713 | 705 | /// Never returns `none`. Asserts that all necessary type resolution is already done. |
| 714 | /// MLUGG TODO: check that it really does never return `.none` | |
| 715 | 706 | pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment { |
| 716 | 707 | const ip = &zcu.intern_pool; |
| 717 | 708 | const target = zcu.getTarget(); |
| ... | ... | @@ -810,7 +801,7 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment { |
| 810 | 801 | for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| { |
| 811 | 802 | if (val != .none) continue; // comptime field |
| 812 | 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 | 806 | return big_align; |
| 816 | 807 | }, |
| ... | ... | @@ -818,14 +809,20 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment { |
| 818 | 809 | const struct_obj = ip.loadStructType(ty.toIntern()); |
| 819 | 810 | switch (struct_obj.layout) { |
| 820 | 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 | 818 | .union_type => { |
| 825 | 819 | const union_obj = ip.loadUnionType(ty.toIntern()); |
| 826 | 820 | switch (union_obj.layout) { |
| 827 | 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 | 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 | 1274 | } |
| 1278 | 1275 | } |
| 1279 | 1276 | |
| 1280 | /// Given that `ty` is an indexable pointer, returns its element type. Specifically: | |
| 1281 | /// * for `*[n]T`, returns `T` | |
| 1282 | /// * for `*@Vector(n, T)`, returns `T` | |
| 1283 | /// * for `[]T`, returns `T` | |
| 1284 | /// * for `[*]T`, returns `T` | |
| 1285 | /// * for `[*c]T`, returns `T` | |
| 1286 | /// | |
| 1287 | /// Tuples are not supported because they do not have a single element type. | |
| 1277 | /// Asserts that `ty` is an indexable type, and returns its element type. Tuples (and pointers to | |
| 1278 | /// tuples) are not supported because they do not have a single element type. | |
| 1288 | 1279 | /// |
| 1289 | /// MLUGG TODO: should i even have this one? it's a subset of indexableElem | |
| 1290 | pub fn indexablePtrElem(ty: Type, zcu: *const Zcu) Type { | |
| 1291 | const ip = &zcu.intern_pool; | |
| 1292 | const ptr_type = ip.indexToKey(ty.toIntern()).ptr_type; | |
| 1293 | return switch (ptr_type.flags.size) { | |
| 1294 | .many, .slice, .c => return .fromInterned(ptr_type.child), | |
| 1295 | .one => switch (ip.indexToKey(ptr_type.child)) { | |
| 1296 | inline .array_type, .vector_type => |arr| return .fromInterned(arr.child), | |
| 1297 | else => unreachable, | |
| 1298 | }, | |
| 1299 | }; | |
| 1300 | } | |
| 1301 | ||
| 1302 | /// Given that `ty` is an indexable type, returns its element type. Specifically: | |
| 1303 | /// * for `[n]T`, returns `T` | |
| 1304 | /// * for `@Vector(n, T)`, returns `T` | |
| 1305 | /// * for `*[n]T`, returns `T` | |
| 1306 | /// * for `*@Vector(n, T)`, returns `T` | |
| 1307 | /// * for `[]T`, returns `T` | |
| 1308 | /// * for `[*]T`, returns `T` | |
| 1309 | /// * for `[*c]T`, returns `T` | |
| 1310 | /// | |
| 1311 | /// Tuples are not supported because they do not have a single element type. | |
| 1280 | /// Returns `T` for each of the following types: | |
| 1281 | /// * `[n]T` | |
| 1282 | /// * `@Vector(n, T)` | |
| 1283 | /// * `*[n]T` | |
| 1284 | /// * `*@Vector(n, T)` | |
| 1285 | /// * `[]T` | |
| 1286 | /// * `[*]T` | |
| 1287 | /// * `[*c]T` | |
| 1312 | 1288 | pub fn indexableElem(ty: Type, zcu: *const Zcu) Type { |
| 1313 | 1289 | const ip = &zcu.intern_pool; |
| 1314 | 1290 | return switch (ip.indexToKey(ty.toIntern())) { |
| ... | ... | @@ -1348,6 +1324,7 @@ pub fn optionalChild(ty: Type, zcu: *const Zcu) Type { |
| 1348 | 1324 | /// Returns the tag type of a union, if the type is a union and it has a tag type. |
| 1349 | 1325 | /// Otherwise, returns `null`. |
| 1350 | 1326 | pub fn unionTagType(ty: Type, zcu: *const Zcu) ?Type { |
| 1327 | assertHasLayout(ty, zcu); | |
| 1351 | 1328 | const ip = &zcu.intern_pool; |
| 1352 | 1329 | switch (ip.indexToKey(ty.toIntern())) { |
| 1353 | 1330 | .union_type => {}, |
| ... | ... | @@ -1363,6 +1340,7 @@ pub fn unionTagType(ty: Type, zcu: *const Zcu) ?Type { |
| 1363 | 1340 | /// Same as `unionTagType` but includes safety tag. |
| 1364 | 1341 | /// Codegen should use this version. |
| 1365 | 1342 | pub fn unionTagTypeSafety(ty: Type, zcu: *const Zcu) ?Type { |
| 1343 | assertHasLayout(ty, zcu); | |
| 1366 | 1344 | const ip = &zcu.intern_pool; |
| 1367 | 1345 | return switch (ip.indexToKey(ty.toIntern())) { |
| 1368 | 1346 | .union_type => { |
| ... | ... | @@ -1377,11 +1355,13 @@ pub fn unionTagTypeSafety(ty: Type, zcu: *const Zcu) ?Type { |
| 1377 | 1355 | /// Asserts the type is a union; returns the tag type, even if the tag will |
| 1378 | 1356 | /// not be stored at runtime. |
| 1379 | 1357 | pub fn unionTagTypeHypothetical(ty: Type, zcu: *const Zcu) Type { |
| 1358 | assertHasLayout(ty, zcu); | |
| 1380 | 1359 | const union_obj = zcu.typeToUnion(ty).?; |
| 1381 | 1360 | return Type.fromInterned(union_obj.enum_tag_type); |
| 1382 | 1361 | } |
| 1383 | 1362 | |
| 1384 | 1363 | pub fn unionFieldType(ty: Type, enum_tag: Value, zcu: *const Zcu) ?Type { |
| 1364 | assertHasLayout(ty, zcu); | |
| 1385 | 1365 | const ip = &zcu.intern_pool; |
| 1386 | 1366 | const union_obj = zcu.typeToUnion(ty).?; |
| 1387 | 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 | 1370 | } |
| 1391 | 1371 | |
| 1392 | 1372 | pub fn unionFieldTypeByIndex(ty: Type, index: usize, zcu: *const Zcu) Type { |
| 1373 | assertHasLayout(ty, zcu); | |
| 1393 | 1374 | const ip = &zcu.intern_pool; |
| 1394 | 1375 | const union_obj = zcu.typeToUnion(ty).?; |
| 1395 | 1376 | return Type.fromInterned(union_obj.field_types.get(ip)[index]); |
| 1396 | 1377 | } |
| 1397 | 1378 | |
| 1398 | 1379 | pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 { |
| 1380 | assertHasLayout(ty, zcu); | |
| 1399 | 1381 | const union_obj = zcu.typeToUnion(ty).?; |
| 1400 | 1382 | return zcu.unionTagFieldIndex(union_obj, enum_tag); |
| 1401 | 1383 | } |
| 1402 | 1384 | |
| 1403 | 1385 | pub fn unionHasAllZeroBitFieldTypes(ty: Type, zcu: *Zcu) bool { |
| 1386 | assertHasLayout(ty, zcu); | |
| 1404 | 1387 | const ip = &zcu.intern_pool; |
| 1405 | 1388 | const union_obj = zcu.typeToUnion(ty).?; |
| 1406 | 1389 | for (union_obj.field_types.get(ip)) |field_ty| { |
| ... | ... | @@ -1413,14 +1396,17 @@ pub fn unionHasAllZeroBitFieldTypes(ty: Type, zcu: *Zcu) bool { |
| 1413 | 1396 | /// Asserts the type is either an extern or packed union. |
| 1414 | 1397 | pub fn unionBackingType(ty: Type, pt: Zcu.PerThread) !Type { |
| 1415 | 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 | 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 | 1404 | .auto => unreachable, |
| 1420 | 1405 | }; |
| 1421 | 1406 | } |
| 1422 | 1407 | |
| 1423 | 1408 | pub fn unionGetLayout(ty: Type, zcu: *const Zcu) Zcu.UnionLayout { |
| 1409 | assertHasLayout(ty, zcu); | |
| 1424 | 1410 | const union_obj = zcu.intern_pool.loadUnionType(ty.toIntern()); |
| 1425 | 1411 | return Type.getUnionLayout(union_obj, zcu); |
| 1426 | 1412 | } |
| ... | ... | @@ -1865,11 +1851,8 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value { |
| 1865 | 1851 | for (field_vals, 0..) |*field_val, i_usize| { |
| 1866 | 1852 | const i: u32 = @intCast(i_usize); |
| 1867 | 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 | 1854 | field_val.* = struct_obj.field_defaults.get(ip)[i]; |
| 1855 | assert(field_val.* != .none); | |
| 1873 | 1856 | continue; |
| 1874 | 1857 | } |
| 1875 | 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 | 2240 | } |
| 2258 | 2241 | |
| 2259 | 2242 | pub fn enumFields(ty: Type, zcu: *const Zcu) InternPool.NullTerminatedString.Slice { |
| 2243 | assertHasLayout(ty, zcu); | |
| 2260 | 2244 | return zcu.intern_pool.loadEnumType(ty.toIntern()).field_names; |
| 2261 | 2245 | } |
| 2262 | 2246 | |
| 2263 | 2247 | pub fn enumFieldCount(ty: Type, zcu: *const Zcu) usize { |
| 2248 | assertHasLayout(ty, zcu); | |
| 2264 | 2249 | return zcu.intern_pool.loadEnumType(ty.toIntern()).field_names.len; |
| 2265 | 2250 | } |
| 2266 | 2251 | |
| 2267 | 2252 | pub fn enumFieldName(ty: Type, field_index: usize, zcu: *const Zcu) InternPool.NullTerminatedString { |
| 2253 | assertHasLayout(ty, zcu); | |
| 2268 | 2254 | const ip = &zcu.intern_pool; |
| 2269 | 2255 | return ip.loadEnumType(ty.toIntern()).field_names.get(ip)[field_index]; |
| 2270 | 2256 | } |
| 2271 | 2257 | |
| 2272 | 2258 | pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, zcu: *const Zcu) ?u32 { |
| 2259 | assertHasLayout(ty, zcu); | |
| 2273 | 2260 | const ip = &zcu.intern_pool; |
| 2274 | 2261 | const enum_type = ip.loadEnumType(ty.toIntern()); |
| 2275 | 2262 | return enum_type.nameIndex(ip, field_name); |
| ... | ... | @@ -2279,6 +2266,7 @@ pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, zcu |
| 2279 | 2266 | /// an integer which represents the enum value. Returns the field index in |
| 2280 | 2267 | /// declaration order, or `null` if `enum_tag` does not match any field. |
| 2281 | 2268 | pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 { |
| 2269 | assertHasLayout(ty, zcu); | |
| 2282 | 2270 | const ip = &zcu.intern_pool; |
| 2283 | 2271 | const enum_type = ip.loadEnumType(ty.toIntern()); |
| 2284 | 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 | 2281 | /// Returns none in the case of a tuple which uses the integer index as the field name. |
| 2294 | 2282 | pub fn structFieldName(ty: Type, index: usize, zcu: *const Zcu) InternPool.OptionalNullTerminatedString { |
| 2295 | 2283 | const ip = &zcu.intern_pool; |
| 2296 | return switch (ip.indexToKey(ty.toIntern())) { | |
| 2297 | .struct_type => ip.loadStructType(ty.toIntern()).field_names.get(ip)[index].toOptional(), | |
| 2298 | .tuple_type => .none, | |
| 2284 | switch (ip.indexToKey(ty.toIntern())) { | |
| 2285 | .struct_type => { | |
| 2286 | assertHasLayout(ty, zcu); | |
| 2287 | return ip.loadStructType(ty.toIntern()).field_names.get(ip)[index].toOptional(); | |
| 2288 | }, | |
| 2289 | .tuple_type => return .none, | |
| 2299 | 2290 | else => unreachable, |
| 2300 | }; | |
| 2291 | } | |
| 2301 | 2292 | } |
| 2302 | 2293 | |
| 2303 | 2294 | pub fn structFieldCount(ty: Type, zcu: *const Zcu) u32 { |
| 2304 | 2295 | const ip = &zcu.intern_pool; |
| 2305 | return switch (ip.indexToKey(ty.toIntern())) { | |
| 2306 | .struct_type => ip.loadStructType(ty.toIntern()).field_types.len, | |
| 2307 | .tuple_type => |tuple| tuple.types.len, | |
| 2296 | switch (ip.indexToKey(ty.toIntern())) { | |
| 2297 | .struct_type => { | |
| 2298 | assertHasLayout(ty, zcu); | |
| 2299 | return ip.loadStructType(ty.toIntern()).field_types.len; | |
| 2300 | }, | |
| 2301 | .tuple_type => |tuple| return tuple.types.len, | |
| 2308 | 2302 | else => unreachable, |
| 2309 | }; | |
| 2303 | } | |
| 2310 | 2304 | } |
| 2311 | 2305 | |
| 2312 | 2306 | /// Returns the field type. Supports structs and unions. |
| 2313 | 2307 | pub fn fieldType(ty: Type, index: usize, zcu: *const Zcu) Type { |
| 2314 | 2308 | const ip = &zcu.intern_pool; |
| 2315 | 2309 | const types = switch (ip.indexToKey(ty.toIntern())) { |
| 2316 | .struct_type => ip.loadStructType(ty.toIntern()).field_types, | |
| 2317 | .union_type => ip.loadUnionType(ty.toIntern()).field_types, | |
| 2310 | .struct_type => types: { | |
| 2311 | assertHasLayout(ty, zcu); | |
| 2312 | break :types ip.loadStructType(ty.toIntern()).field_types; | |
| 2313 | }, | |
| 2314 | .union_type => types: { | |
| 2315 | assertHasLayout(ty, zcu); | |
| 2316 | break :types ip.loadUnionType(ty.toIntern()).field_types; | |
| 2317 | }, | |
| 2318 | 2318 | .tuple_type => |tuple| tuple.types, |
| 2319 | 2319 | else => unreachable, |
| 2320 | 2320 | }; |
| ... | ... | @@ -2335,11 +2335,13 @@ pub fn resolvedFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment |
| 2335 | 2335 | return switch (ip.indexToKey(ty.toIntern())) { |
| 2336 | 2336 | .tuple_type => |tuple| Type.fromInterned(tuple.types.get(ip)[index]).abiAlignment(zcu), |
| 2337 | 2337 | .struct_type => { |
| 2338 | assertHasLayout(ty, zcu); | |
| 2338 | 2339 | const struct_obj = ip.loadStructType(ty.toIntern()); |
| 2339 | 2340 | const field_ty: Type = .fromInterned(struct_obj.field_types.get(ip)[index]); |
| 2340 | 2341 | return field_ty.defaultStructFieldAlignment(struct_obj.layout, zcu); |
| 2341 | 2342 | }, |
| 2342 | 2343 | .union_type => { |
| 2344 | assertHasLayout(ty, zcu); | |
| 2343 | 2345 | const union_obj = ip.loadUnionType(ty.toIntern()); |
| 2344 | 2346 | const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[index]); |
| 2345 | 2347 | return field_ty.abiAlignment(zcu); |
| ... | ... | @@ -2353,12 +2355,14 @@ pub fn explicitFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment |
| 2353 | 2355 | return switch (ip.indexToKey(ty.toIntern())) { |
| 2354 | 2356 | .tuple_type => .none, |
| 2355 | 2357 | .struct_type => { |
| 2358 | assertHasLayout(ty, zcu); | |
| 2356 | 2359 | const struct_obj = ip.loadStructType(ty.toIntern()); |
| 2357 | 2360 | assert(struct_obj.layout != .@"packed"); |
| 2358 | 2361 | if (struct_obj.field_aligns.len == 0) return .none; |
| 2359 | 2362 | return struct_obj.field_aligns.get(ip)[index]; |
| 2360 | 2363 | }, |
| 2361 | 2364 | .union_type => { |
| 2365 | assertHasLayout(ty, zcu); | |
| 2362 | 2366 | const union_obj = ip.loadUnionType(ty.toIntern()); |
| 2363 | 2367 | assert(union_obj.layout != .@"packed"); |
| 2364 | 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 | 2417 | .struct_type => { |
| 2414 | 2418 | const struct_type = ip.loadStructType(ty.toIntern()); |
| 2415 | 2419 | if (struct_type.field_is_comptime_bits.get(ip, index)) { |
| 2416 | assertHasInits(ty, zcu); | |
| 2417 | 2420 | return .fromInterned(struct_type.field_defaults.get(ip)[index]); |
| 2418 | 2421 | } else { |
| 2419 | 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 | 2436 | |
| 2434 | 2437 | pub fn structFieldIsComptime(ty: Type, index: usize, zcu: *const Zcu) bool { |
| 2435 | 2438 | const ip = &zcu.intern_pool; |
| 2436 | return switch (ip.indexToKey(ty.toIntern())) { | |
| 2437 | .struct_type => ip.loadStructType(ty.toIntern()).field_is_comptime_bits.get(ip, index), | |
| 2438 | .tuple_type => |tuple| tuple.values.get(ip)[index] != .none, | |
| 2439 | switch (ip.indexToKey(ty.toIntern())) { | |
| 2440 | .struct_type => { | |
| 2441 | assertHasLayout(ty, zcu); | |
| 2442 | return ip.loadStructType(ty.toIntern()).field_is_comptime_bits.get(ip, index); | |
| 2443 | }, | |
| 2444 | .tuple_type => |tuple| return tuple.values.get(ip)[index] != .none, | |
| 2439 | 2445 | else => unreachable, |
| 2440 | }; | |
| 2446 | } | |
| 2441 | 2447 | } |
| 2442 | 2448 | |
| 2443 | 2449 | pub const FieldOffset = struct { |
| ... | ... | @@ -2850,34 +2856,166 @@ pub fn isNullFromType(ty: Type, zcu: *const Zcu) ?bool { |
| 2850 | 2856 | return null; |
| 2851 | 2857 | } |
| 2852 | 2858 | |
| 2853 | /// Returns true if `ty` is allowed in packed types. | |
| 2854 | pub fn packable(ty: Type, zcu: *const Zcu) bool { | |
| 2859 | pub const UnpackableReason = union(enum) { | |
| 2860 | comptime_only, | |
| 2861 | pointer, | |
| 2862 | enum_inferred_int_tag: Type, | |
| 2863 | non_packed_struct: Type, | |
| 2864 | non_packed_union: Type, | |
| 2865 | other, | |
| 2866 | }; | |
| 2867 | ||
| 2868 | /// Returns `null` iff `ty` is allowed in packed types. | |
| 2869 | pub fn unpackable(ty: Type, zcu: *const Zcu) ?UnpackableReason { | |
| 2855 | 2870 | return switch (ty.zigTypeTag(zcu)) { |
| 2871 | .void, | |
| 2872 | .bool, | |
| 2873 | .float, | |
| 2874 | .int, | |
| 2875 | => null, | |
| 2876 | ||
| 2856 | 2877 | .type, |
| 2857 | 2878 | .comptime_float, |
| 2858 | 2879 | .comptime_int, |
| 2859 | 2880 | .enum_literal, |
| 2860 | 2881 | .undefined, |
| 2861 | 2882 | .null, |
| 2883 | => .comptime_only, | |
| 2884 | ||
| 2885 | .noreturn, | |
| 2886 | .@"opaque", | |
| 2862 | 2887 | .error_union, |
| 2863 | 2888 | .error_set, |
| 2864 | 2889 | .frame, |
| 2865 | .noreturn, | |
| 2866 | .@"opaque", | |
| 2867 | 2890 | .@"anyframe", |
| 2868 | 2891 | .@"fn", |
| 2869 | 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 | ||
| 2919 | pub 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`. | |
| 2931 | pub 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 | 2942 | => false, |
| 2871 | .optional => return ty.isPtrLikeOptional(zcu), | |
| 2872 | .void, | |
| 2943 | ||
| 2944 | .void => switch (position) { | |
| 2945 | .ret_ty, | |
| 2946 | .union_field, | |
| 2947 | .struct_field, | |
| 2948 | .element, | |
| 2949 | => true, | |
| 2950 | .param_ty, | |
| 2951 | .other, | |
| 2952 | => false, | |
| 2953 | }, | |
| 2954 | ||
| 2955 | .noreturn => position == .ret_ty, | |
| 2956 | ||
| 2957 | .@"opaque", | |
| 2873 | 2958 | .bool, |
| 2874 | 2959 | .float, |
| 2875 | .int, | |
| 2876 | .vector, | |
| 2960 | .@"anyframe", | |
| 2877 | 2961 | => true, |
| 2878 | .@"enum" => zcu.intern_pool.loadEnumType(ty.toIntern()).int_tag_is_explicit, | |
| 2879 | .pointer => !ty.isSlice(zcu), | |
| 2880 | .@"struct", .@"union" => ty.containerLayout(zcu) == .@"packed", | |
| 2962 | ||
| 2963 | .pointer => { | |
| 2964 | if (ty.isSlice(zcu)) return false; | |
| 2965 | const child_ty = ty.childType(zcu); | |
| 2966 | if (child_ty.zigTypeTag(zcu) == .@"fn") { | |
| 2967 | return ty.isConstPtr(zcu) and child_ty.validateExtern(.other, zcu); | |
| 2968 | } | |
| 2969 | return true; | |
| 2970 | }, | |
| 2971 | .int => switch (ty.intInfo(zcu).bits) { | |
| 2972 | 0, 8, 16, 32, 64, 128 => true, | |
| 2973 | else => false, | |
| 2974 | }, | |
| 2975 | .@"fn" => { | |
| 2976 | if (position != .other) return false; | |
| 2977 | // For now we want to authorize PTX kernel to use zig objects, even if we end up exposing the ABI. | |
| 2978 | // The goal is to experiment with more integrated CPU/GPU code. | |
| 2979 | if (ty.fnCallingConvention(zcu) == .nvptx_kernel) { | |
| 2980 | return true; | |
| 2981 | } | |
| 2982 | return !target_util.fnCallConvAllowsZigTypes(ty.fnCallingConvention(zcu)); | |
| 2983 | }, | |
| 2984 | .@"enum" => { | |
| 2985 | const enum_obj = zcu.intern_pool.loadEnumType(ty.toIntern()); | |
| 2986 | return switch (enum_obj.int_tag_mode) { | |
| 2987 | .auto => false, | |
| 2988 | .explicit => Type.fromInterned(enum_obj.int_tag_type).validateExtern(position, zcu), | |
| 2989 | }; | |
| 2990 | }, | |
| 2991 | .@"struct" => { | |
| 2992 | const struct_obj = zcu.intern_pool.loadStructType(ty.toIntern()); | |
| 2993 | return switch (struct_obj.layout) { | |
| 2994 | .auto => false, | |
| 2995 | .@"extern" => true, | |
| 2996 | .@"packed" => switch (struct_obj.packed_backing_mode) { | |
| 2997 | .auto => false, | |
| 2998 | .explicit => Type.fromInterned(struct_obj.packed_backing_int_type).validateExtern(position, zcu), | |
| 2999 | }, | |
| 3000 | }; | |
| 3001 | }, | |
| 3002 | .@"union" => { | |
| 3003 | const union_obj = zcu.intern_pool.loadUnionType(ty.toIntern()); | |
| 3004 | return switch (union_obj.layout) { | |
| 3005 | .auto => false, | |
| 3006 | .@"extern" => true, | |
| 3007 | .@"packed" => switch (union_obj.packed_backing_mode) { | |
| 3008 | .auto => false, | |
| 3009 | .explicit => Type.fromInterned(union_obj.packed_backing_int_type).validateExtern(position, zcu), | |
| 3010 | }, | |
| 3011 | }; | |
| 3012 | }, | |
| 3013 | .array => { | |
| 3014 | if (position == .ret_ty or position == .param_ty) return false; | |
| 3015 | return ty.childType(zcu).validateExtern(.element, zcu); | |
| 3016 | }, | |
| 3017 | .vector => ty.childType(zcu).validateExtern(.element, zcu), | |
| 3018 | .optional => ty.isPtrLikeOptional(zcu), | |
| 2881 | 3019 | }; |
| 2882 | 3020 | } |
| 2883 | 3021 | |
| ... | ... | @@ -2889,7 +3027,6 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void { |
| 2889 | 3027 | .anyframe_type, |
| 2890 | 3028 | .simple_type, |
| 2891 | 3029 | .opaque_type, |
| 2892 | .enum_type, | |
| 2893 | 3030 | .error_set_type, |
| 2894 | 3031 | .inferred_error_set_type, |
| 2895 | 3032 | => {}, |
| ... | ... | @@ -2906,12 +3043,11 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void { |
| 2906 | 3043 | .tuple_type => |tuple| for (tuple.types.get(&zcu.intern_pool)) |field_ty| { |
| 2907 | 3044 | assertHasLayout(.fromInterned(field_ty), zcu); |
| 2908 | 3045 | }, |
| 2909 | .struct_type, .union_type => { | |
| 3046 | .struct_type, .union_type, .enum_type => { | |
| 2910 | 3047 | const unit: InternPool.AnalUnit = .wrap(.{ .type_layout = ty.toIntern() }); |
| 2911 | 3048 | assert(!zcu.outdated.contains(unit)); |
| 2912 | 3049 | assert(!zcu.potentially_outdated.contains(unit)); |
| 2913 | 3050 | }, |
| 2914 | else => unreachable, // assertion failure; not a struct or union | |
| 2915 | 3051 | |
| 2916 | 3052 | // values, not types |
| 2917 | 3053 | .simple_value, |
| ... | ... | @@ -2930,23 +3066,13 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void { |
| 2930 | 3066 | .opt, |
| 2931 | 3067 | .aggregate, |
| 2932 | 3068 | .un, |
| 3069 | .undef, | |
| 2933 | 3070 | // memoization, not types |
| 2934 | 3071 | .memoized_call, |
| 2935 | 3072 | => unreachable, |
| 2936 | 3073 | } |
| 2937 | 3074 | } |
| 2938 | 3075 | |
| 2939 | /// Asserts that `ty` is an enum or struct type whose field values/defaults are resolved. | |
| 2940 | pub 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 | 3076 | /// Recursively walks the type and marks for each subtype how many times it has been seen |
| 2951 | 3077 | fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUnmanaged(Type, u16)) error{OutOfMemory}!void { |
| 2952 | 3078 | const zcu = pt.zcu; |
| ... | ... | @@ -3116,6 +3242,7 @@ pub const Comparison = struct { |
| 3116 | 3242 | }; |
| 3117 | 3243 | }; |
| 3118 | 3244 | |
| 3245 | pub const @"u0": Type = .{ .ip_index = .u0_type }; | |
| 3119 | 3246 | pub const @"u1": Type = .{ .ip_index = .u1_type }; |
| 3120 | 3247 | pub const @"u8": Type = .{ .ip_index = .u8_type }; |
| 3121 | 3248 | pub 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 | 2207 | |
| 2208 | 2208 | const ptr_ty_info = Type.fromInterned(ptr.ty).ptrInfo(zcu); |
| 2209 | 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 | 2211 | // No refinement can happen - this pointer is presumably invalid. |
| 2212 | 2212 | // Just offset it. |
| 2213 | 2213 | const parent = try arena.create(PointerDeriveStep); |
| ... | ... | @@ -2595,8 +2595,8 @@ pub fn uninterpret(val: anytype, ty: Type, pt: Zcu.PerThread) error{ OutOfMemory |
| 2595 | 2595 | pub fn doPointersOverlap(ptr_val_a: Value, ptr_val_b: Value, elem_count: u64, zcu: *const Zcu) bool { |
| 2596 | 2596 | const ip = &zcu.intern_pool; |
| 2597 | 2597 | |
| 2598 | const a_elem_ty = ptr_val_a.typeOf(zcu).indexablePtrElem(zcu); | |
| 2599 | const b_elem_ty = ptr_val_b.typeOf(zcu).indexablePtrElem(zcu); | |
| 2598 | const a_elem_ty = ptr_val_a.typeOf(zcu).indexableElem(zcu); | |
| 2599 | const b_elem_ty = ptr_val_b.typeOf(zcu).indexableElem(zcu); | |
| 2600 | 2600 | |
| 2601 | 2601 | const a_ptr = ip.indexToKey(ptr_val_a.toIntern()).ptr; |
| 2602 | 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 | 2682 | const rhs_bigint = rhs.toBigInt(&rhs_bigint_space, zcu); |
| 2683 | 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. | |
| 2690 | pub 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 | 1912 | const full = tree.fullPtrType(parent_node).?; |
| 1913 | 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 | 1915 | .node_offset_init_ty => |node_off| { |
| 1950 | 1916 | const tree = try src_loc.file_scope.getTree(zcu); |
| 1951 | 1917 | const parent_node = node_off.toAbsolute(src_loc.base_node); |
| ... | ... | @@ -2021,6 +1987,14 @@ pub const SrcLoc = struct { |
| 2021 | 1987 | } |
| 2022 | 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 | 1998 | .container_field_name, |
| 2025 | 1999 | .container_field_value, |
| 2026 | 2000 | .container_field_type, |
| ... | ... | @@ -2262,7 +2236,11 @@ pub const SrcLoc = struct { |
| 2262 | 2236 | var param_it = full.iterate(tree); |
| 2263 | 2237 | for (0..param_idx) |_| assert(param_it.next() != null); |
| 2264 | 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 | 2462 | node_offset_ptr_bitoffset: Ast.Node.Offset, |
| 2485 | 2463 | /// The source location points to the host size of a pointer. |
| 2486 | 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 | 2465 | /// The source location points to the type of an array or struct initializer. |
| 2492 | 2466 | node_offset_init_ty: Ast.Node.Offset, |
| 2493 | 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 | 2506 | fn_proto_param_type: FnProtoParam, |
| 2533 | 2507 | array_cat_lhs: ArrayCat, |
| 2534 | 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 | 2514 | /// The source location points to the name of the field at the given index |
| 2536 | 2515 | /// of the container type declaration at the base node. |
| 2537 | 2516 | container_field_name: u32, |
| ... | ... | @@ -3149,7 +3128,7 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void { |
| 3149 | 3128 | .nav_val => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_val = nav }), |
| 3150 | 3129 | .nav_ty => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_ty = nav }), |
| 3151 | 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 | 3132 | .func => |func| try zcu.markPoDependeeUpToDate(.{ .func_ies = func }), |
| 3154 | 3133 | .memoized_state => |stage| try zcu.markPoDependeeUpToDate(.{ .memoized_state = stage }), |
| 3155 | 3134 | } |
| ... | ... | @@ -3165,7 +3144,7 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni |
| 3165 | 3144 | .nav_val => |nav| .{ .nav_val = nav }, |
| 3166 | 3145 | .nav_ty => |nav| .{ .nav_ty = nav }, |
| 3167 | 3146 | .type_layout => |ty| .{ .type_layout = ty }, |
| 3168 | .type_inits => |ty| .{ .type_inits = ty }, | |
| 3147 | .struct_defaults => |ty| .{ .struct_defaults = ty }, | |
| 3169 | 3148 | .func => |func_index| .{ .func_ies = func_index }, |
| 3170 | 3149 | .memoized_state => |stage| .{ .memoized_state = stage }, |
| 3171 | 3150 | }; |
| ... | ... | @@ -3195,88 +3174,44 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni |
| 3195 | 3174 | } |
| 3196 | 3175 | } |
| 3197 | 3176 | |
| 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. | |
| 3198 | 3181 | pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { |
| 3199 | 3182 | if (!zcu.comp.config.incremental) return null; |
| 3200 | 3183 | |
| 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 | 3184 | if (zcu.outdated_ready.count() > 0) { |
| 3220 | 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 | 3187 | return unit; |
| 3223 | 3188 | } |
| 3224 | 3189 | |
| 3225 | // There is no single AnalUnit which is ready for re-analysis. Instead, we must assume that some | |
| 3226 | // AnalUnit with PO dependencies is outdated -- e.g. in the above example we arbitrarily pick one of | |
| 3227 | // A or B. We should definitely not select a function, since a function can't be responsible for the | |
| 3228 | // loop (IES dependencies can't have loops). We should also, of course, not select a `comptime` | |
| 3229 | // declaration, since you can't depend on those! | |
| 3230 | ||
| 3231 | // The choice of this unit could have a big impact on how much total analysis we perform, since | |
| 3232 | // if analysis concludes any dependencies on its result are up-to-date, then other PO AnalUnit | |
| 3233 | // may be resolved as up-to-date. To hopefully avoid doing too much work, let's find a unit | |
| 3234 | // which the most things depend on - the idea is that this will resolve a lot of loops (but this | |
| 3235 | // is only a heuristic). | |
| 3236 | ||
| 3237 | log.debug("findOutdatedToAnalyze: no trivial ready, using heuristic; {d} outdated, {d} PO", .{ | |
| 3238 | zcu.outdated.count(), | |
| 3239 | zcu.potentially_outdated.count(), | |
| 3240 | }); | |
| 3241 | ||
| 3242 | const ip = &zcu.intern_pool; | |
| 3243 | ||
| 3244 | var chosen_unit: ?AnalUnit = null; | |
| 3245 | var chosen_unit_dependers: u32 = undefined; | |
| 3246 | ||
| 3247 | // MLUGG TODO: i'm 99% sure this is now impossible. check!!! | |
| 3248 | inline for (.{ zcu.outdated.keys(), zcu.potentially_outdated.keys() }) |outdated_units| { | |
| 3249 | for (outdated_units) |unit| { | |
| 3250 | var n: u32 = 0; | |
| 3251 | var it = ip.dependencyIterator(switch (unit.unwrap()) { | |
| 3252 | .func => continue, // a `func` definitely can't be causing the loop so it is a bad choice | |
| 3253 | .@"comptime" => continue, // a `comptime` block can't even be depended on so it is a terrible choice | |
| 3254 | .type_layout => |ty| .{ .type_layout = ty }, | |
| 3255 | .type_inits => |ty| .{ .type_inits = ty }, | |
| 3256 | .nav_val => |nav| .{ .nav_val = nav }, | |
| 3257 | .nav_ty => |nav| .{ .nav_ty = nav }, | |
| 3258 | .memoized_state => { | |
| 3259 | // If we've hit a loop and some `.memoized_state` is outdated, we should make that choice eagerly. | |
| 3260 | // In general, it's good to resolve this early on, since -- for instance -- almost every function | |
| 3261 | // references the panic handler. | |
| 3262 | return unit; | |
| 3263 | }, | |
| 3264 | }); | |
| 3265 | while (it.next()) |_| n += 1; | |
| 3190 | // Usually, getting here means that everything is up-to-date, so there is no more work to do. We | |
| 3191 | // will see that `zcu.outdated` and `zcu.potentially_outdated` are both empty. | |
| 3192 | // | |
| 3193 | // However, if a previous update had a dependency loop compile error, there is a cycle in the | |
| 3194 | // dependency graph (which is usually acyclic), which can cause a scenario where no unit appears | |
| 3195 | // to be ready, because they're all waiting for the next in the loop to be up-to-date. In that | |
| 3196 | // case, we usually have to just bite the bullet and analyze one of them. An exception is if | |
| 3197 | // `zcu.outdated` is empty but `zcu.potentially_outdated` is non-empty: in that case, the only | |
| 3198 | // possible situation is a cycle where everything is actually up-to-date, so we can clear out | |
| 3199 | // `zcu.potentially_outdated` and we are done. | |
| 3266 | 3200 | |
| 3267 | if (chosen_unit == null or n > chosen_unit_dependers) { | |
| 3268 | chosen_unit = unit; | |
| 3269 | chosen_unit_dependers = n; | |
| 3270 | } | |
| 3271 | } | |
| 3201 | if (zcu.outdated.count() == 0) { | |
| 3202 | // Everything is up-to-date. There could be lingering entries in `zcu.potentially_outdated` | |
| 3203 | // from a dependency loop on a previous update. | |
| 3204 | zcu.potentially_outdated.clearRetainingCapacity(); | |
| 3205 | log.debug("findOutdatedToAnalyze: all up-to-date", .{}); | |
| 3206 | return null; | |
| 3272 | 3207 | } |
| 3273 | 3208 | |
| 3274 | log.debug("findOutdatedToAnalyze: heuristic returned '{f}' ({d} dependers)", .{ | |
| 3275 | zcu.fmtAnalUnit(chosen_unit.?), | |
| 3276 | chosen_unit_dependers, | |
| 3209 | const unit = zcu.outdated.keys()[0]; | |
| 3210 | log.debug("findOutdatedToAnalyze: dependency loop affecting {d} units, selected {f}", .{ | |
| 3211 | zcu.outdated.count(), | |
| 3212 | zcu.fmtAnalUnit(unit), | |
| 3277 | 3213 | }); |
| 3278 | ||
| 3279 | return chosen_unit.?; | |
| 3214 | return unit; | |
| 3280 | 3215 | } |
| 3281 | 3216 | |
| 3282 | 3217 | /// During an incremental update, before semantic analysis, call this to flush all values from |
| ... | ... | @@ -3356,12 +3291,59 @@ pub fn mapOldZirToNew( |
| 3356 | 3291 | } |
| 3357 | 3292 | |
| 3358 | 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, because | |
| 3360 | // we wouldn't know how to correlate type information with the last update. | |
| 3361 | // Synchronizes with logic in `Zcu.PerThread.recreateStructType` etc. | |
| 3362 | if (old_zir.typeCapturesLen(match_item.old_inst) != new_zir.typeCapturesLen(match_item.new_inst)) { | |
| 3363 | // Don't map this type or anything within it. | |
| 3364 | continue; | |
| 3294 | // There are some properties of type declarations which cannot change across incremental | |
| 3295 | // updates. If they have, we need to ignore this mapping. These properties are essentially | |
| 3296 | // everything passed into `InternPool.getDeclaredStructType` (likewise for unions, enums, | |
| 3297 | // and opaques). | |
| 3298 | const old_tag = old_zir.instructions.items(.data)[@intFromEnum(match_item.old_inst)].extended.opcode; | |
| 3299 | const new_tag = new_zir.instructions.items(.data)[@intFromEnum(match_item.new_inst)].extended.opcode; | |
| 3300 | if (old_tag != new_tag) continue; | |
| 3301 | switch (old_tag) { | |
| 3302 | .struct_decl => { | |
| 3303 | const old = old_zir.getStructDecl(match_item.old_inst); | |
| 3304 | const new = new_zir.getStructDecl(match_item.new_inst); | |
| 3305 | if (old.captures.len != new.captures.len) continue; | |
| 3306 | if (old.field_names.len != new.field_names.len) continue; | |
| 3307 | if (old.layout != new.layout) continue; | |
| 3308 | const old_any_field_aligns = old.field_align_body_lens != null; | |
| 3309 | const old_any_field_defaults = old.field_default_body_lens != null; | |
| 3310 | const old_any_comptime_fields = old.field_comptime_bits != null; | |
| 3311 | const old_explicit_backing_int = old.backing_int_type_body != null; | |
| 3312 | const new_any_field_aligns = new.field_align_body_lens != null; | |
| 3313 | const new_any_field_defaults = new.field_default_body_lens != null; | |
| 3314 | const new_any_comptime_fields = new.field_comptime_bits != null; | |
| 3315 | const new_explicit_backing_int = new.backing_int_type_body != null; | |
| 3316 | if (old_any_field_aligns != new_any_field_aligns) continue; | |
| 3317 | if (old_any_field_defaults != new_any_field_defaults) continue; | |
| 3318 | if (old_any_comptime_fields != new_any_comptime_fields) continue; | |
| 3319 | if (old_explicit_backing_int != new_explicit_backing_int) continue; | |
| 3320 | }, | |
| 3321 | .union_decl => { | |
| 3322 | const old = old_zir.getUnionDecl(match_item.old_inst); | |
| 3323 | const new = new_zir.getUnionDecl(match_item.new_inst); | |
| 3324 | if (old.captures.len != new.captures.len) continue; | |
| 3325 | if (old.field_names.len != new.field_names.len) continue; | |
| 3326 | if (old.kind != new.kind) continue; | |
| 3327 | const old_any_field_aligns = old.field_align_body_lens != null; | |
| 3328 | const new_any_field_aligns = new.field_align_body_lens != null; | |
| 3329 | if (old_any_field_aligns != new_any_field_aligns) continue; | |
| 3330 | }, | |
| 3331 | .enum_decl => { | |
| 3332 | const old = old_zir.getEnumDecl(match_item.old_inst); | |
| 3333 | const new = new_zir.getEnumDecl(match_item.new_inst); | |
| 3334 | if (old.captures.len != new.captures.len) continue; | |
| 3335 | if (old.field_names.len != new.field_names.len) continue; | |
| 3336 | if (old.nonexhaustive != new.nonexhaustive) continue; | |
| 3337 | const old_explicit_tag_type = old.tag_type_body != null; | |
| 3338 | const new_explicit_tag_type = new.tag_type_body != null; | |
| 3339 | if (old_explicit_tag_type != new_explicit_tag_type) continue; | |
| 3340 | }, | |
| 3341 | .opaque_decl => { | |
| 3342 | const old = old_zir.getOpaqueDecl(match_item.old_inst); | |
| 3343 | const new = new_zir.getOpaqueDecl(match_item.new_inst); | |
| 3344 | if (old.captures.len != new.captures.len) continue; | |
| 3345 | }, | |
| 3346 | else => unreachable, | |
| 3365 | 3347 | } |
| 3366 | 3348 | |
| 3367 | 3349 | // Match the namespace declaration itself |
| ... | ... | @@ -4068,7 +4050,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R |
| 4068 | 4050 | } |
| 4069 | 4051 | if (has_inits) { |
| 4070 | 4052 | // 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 | 4054 | try units.putNoClobber(gpa, unit, referencer); |
| 4073 | 4055 | } |
| 4074 | 4056 | |
| ... | ... | @@ -4184,7 +4166,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R |
| 4184 | 4166 | const other: AnalUnit = .wrap(switch (unit.unwrap()) { |
| 4185 | 4167 | .nav_val => |n| .{ .nav_ty = n }, |
| 4186 | 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 | 4171 | const gop = try units.getOrPut(gpa, other); |
| 4190 | 4172 | if (gop.found_existing) break :queue_paired; |
| ... | ... | @@ -4305,6 +4287,16 @@ pub fn navFileScope(zcu: *Zcu, nav: InternPool.Nav.Index) *File { |
| 4305 | 4287 | return zcu.fileByIndex(zcu.navFileScopeIndex(nav)); |
| 4306 | 4288 | } |
| 4307 | 4289 | |
| 4290 | pub 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 | ||
| 4308 | 4300 | pub fn fmtAnalUnit(zcu: *Zcu, unit: AnalUnit) std.fmt.Alt(FormatAnalUnit, formatAnalUnit) { |
| 4309 | 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 | 4323 | } |
| 4332 | 4324 | }, |
| 4333 | 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 | 4327 | .func => |func| { |
| 4336 | 4328 | const nav = zcu.funcInfo(func).owner_nav; |
| 4337 | 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 | 4349 | const fqn = ip.getNav(nav).fqn; |
| 4358 | 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 | 4353 | const name = Type.fromInterned(ip_index).containerTypeName(ip); |
| 4362 | 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 | 695 | .file = file_index, |
| 696 | 696 | .inst = .main_struct_inst, |
| 697 | 697 | }); |
| 698 | const file_root_type = try Sema.analyzeStructDecl( | |
| 699 | pt, | |
| 700 | file_index, | |
| 701 | &file.zir.?, | |
| 702 | .none, | |
| 703 | tracked_inst, | |
| 704 | &struct_decl, | |
| 705 | null, | |
| 706 | &.{}, | |
| 707 | .{ .exact = .{ | |
| 708 | .name = try file.internFullyQualifiedName(pt), | |
| 709 | .nav = .none, | |
| 710 | } }, | |
| 711 | ); | |
| 698 | const wip: InternPool.WipContainerType = switch (try ip.getDeclaredStructType(gpa, io, pt.tid, .{ | |
| 699 | .zir_index = tracked_inst, | |
| 700 | .captures = &.{}, | |
| 701 | .fields_len = @intCast(struct_decl.field_names.len), | |
| 702 | .layout = struct_decl.layout, | |
| 703 | .any_comptime_fields = struct_decl.field_comptime_bits != null, | |
| 704 | .any_field_defaults = struct_decl.field_default_body_lens != null, | |
| 705 | .any_field_aligns = struct_decl.field_align_body_lens != null, | |
| 706 | .packed_backing_mode = if (struct_decl.backing_int_type_body != null) .explicit else .auto, | |
| 707 | })) { | |
| 708 | .existing => unreachable, // it would have been set as `zcu.fileRootType` already | |
| 709 | .wip => |wip| wip, | |
| 710 | }; | |
| 711 | errdefer wip.cancel(ip, pt.tid); | |
| 712 | ||
| 713 | wip.setName(ip, try file.internFullyQualifiedName(pt), .none); | |
| 714 | const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ | |
| 715 | .parent = .none, | |
| 716 | .owner_type = wip.index, | |
| 717 | .file_scope = file_index, | |
| 718 | .generation = zcu.generation, | |
| 719 | }); | |
| 720 | errdefer pt.destroyNamespace(new_namespace_index); | |
| 721 | try pt.scanNamespace(new_namespace_index, struct_decl.decls); | |
| 722 | // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind | |
| 723 | try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) }); | |
| 724 | try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .struct_defaults = wip.index }) }); | |
| 725 | ||
| 726 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); | |
| 727 | ||
| 728 | try zcu.outdated.ensureUnusedCapacity(gpa, 2); | |
| 729 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 2); | |
| 730 | errdefer comptime unreachable; // because we don't remove the `outdated` entries | |
| 731 | zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); | |
| 732 | zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .struct_defaults = wip.index }), 0); | |
| 733 | zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); | |
| 734 | zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .struct_defaults = wip.index }), {}); | |
| 735 | ||
| 736 | const file_root_type: Type = .fromInterned(wip.finish(ip, new_namespace_index)); | |
| 737 | ||
| 712 | 738 | zcu.setFileRootType(file_index, file_root_type.toIntern()); |
| 713 | 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 | 1074 | |
| 1049 | 1075 | assert(!zcu.analysis_in_progress.contains(anal_unit)); |
| 1050 | 1076 | |
| 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 | 1077 | const was_outdated = zcu.outdated.swapRemove(anal_unit) or |
| 1057 | 1078 | zcu.potentially_outdated.swapRemove(anal_unit); |
| 1058 | 1079 | |
| ... | ... | @@ -1113,17 +1134,11 @@ pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void |
| 1113 | 1134 | }; |
| 1114 | 1135 | defer sema.deinit(); |
| 1115 | 1136 | |
| 1116 | const result = switch (ty.containerLayout(zcu)) { | |
| 1117 | .auto, .@"extern" => switch (ty.zigTypeTag(zcu)) { | |
| 1118 | .@"struct" => Sema.type_resolution.resolveStructLayout(&sema, ty), | |
| 1119 | .@"union" => Sema.type_resolution.resolveUnionLayout(&sema, ty), | |
| 1120 | else => unreachable, | |
| 1121 | }, | |
| 1122 | .@"packed" => switch (ty.zigTypeTag(zcu)) { | |
| 1123 | .@"struct" => Sema.type_resolution.resolvePackedStructLayout(&sema, ty), | |
| 1124 | .@"union" => Sema.type_resolution.resolvePackedUnionLayout(&sema, ty), | |
| 1125 | else => unreachable, | |
| 1126 | }, | |
| 1137 | const result = switch (ty.zigTypeTag(zcu)) { | |
| 1138 | .@"enum" => Sema.type_resolution.resolveEnumLayout(&sema, ty), | |
| 1139 | .@"struct" => Sema.type_resolution.resolveStructLayout(&sema, ty), | |
| 1140 | .@"union" => Sema.type_resolution.resolveUnionLayout(&sema, ty), | |
| 1141 | else => unreachable, | |
| 1127 | 1142 | }; |
| 1128 | 1143 | result catch |err| switch (err) { |
| 1129 | 1144 | error.AnalysisFail => { |
| ... | ... | @@ -1145,36 +1160,31 @@ pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void |
| 1145 | 1160 | sema.flushExports() catch |err| switch (err) { |
| 1146 | 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 | } |
| 1156 | 1164 | |
| 1157 | /// Ensures that the default/tag values of the given `struct` or `enum` type are fully up-to-date, | |
| 1158 | /// performing re-analysis if necessary. Asserts that `ty` is a struct (not a tuple!) or an enum. | |
| 1159 | /// Returns `error.AnalysisFail` if an analysis error is encountered during resolution; the caller | |
| 1160 | /// is free to ignore this, since the error is already registered. | |
| 1161 | pub fn ensureTypeInitsUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void { | |
| 1165 | /// Ensures that the default values of the given "declared" (not reified) `struct` type are fully | |
| 1166 | /// up-to-date, performing re-analysis if necessary. Asserts that `ty` is a struct (not tuple) type. | |
| 1167 | /// Returns `error.AnalysisFail` if an analysis error is encountered while resolving the default | |
| 1168 | /// field values; the caller is free to ignore this, since the error is already registered. | |
| 1169 | pub fn ensureStructDefaultsUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void { | |
| 1162 | 1170 | const tracy = trace(@src()); |
| 1163 | 1171 | defer tracy.end(); |
| 1164 | 1172 | |
| 1165 | 1173 | const zcu = pt.zcu; |
| 1166 | 1174 | const gpa = zcu.gpa; |
| 1167 | 1175 | |
| 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() }); | |
| 1169 | 1180 | |
| 1170 | log.debug("ensureTypeInitsUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 1181 | log.debug("ensureStructDefaultsUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 1171 | 1182 | |
| 1172 | 1183 | assert(!zcu.analysis_in_progress.contains(anal_unit)); |
| 1173 | 1184 | |
| 1174 | 1185 | // Determine whether or not this type is outdated. For this kind of `AnalUnit`, that's |
| 1175 | 1186 | // the only indicator as to whether or not analysis is required; when a struct/enum is |
| 1176 | 1187 | // first created, it's marked as outdated. |
| 1177 | // MLUGG TODO: make that actually true, it's a good strategy here! | |
| 1178 | 1188 | |
| 1179 | 1189 | const was_outdated = zcu.outdated.swapRemove(anal_unit) or |
| 1180 | 1190 | zcu.potentially_outdated.swapRemove(anal_unit); |
| ... | ... | @@ -1194,7 +1204,7 @@ pub fn ensureTypeInitsUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void { |
| 1194 | 1204 | } |
| 1195 | 1205 | // For types, we already know that we have to invalidate all dependees. |
| 1196 | 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 | 1208 | } else { |
| 1199 | 1209 | // We can trust the current information about this unit. |
| 1200 | 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 | 1246 | }; |
| 1237 | 1247 | defer sema.deinit(); |
| 1238 | 1248 | |
| 1239 | const result = switch (ty.zigTypeTag(zcu)) { | |
| 1240 | .@"struct" => Sema.type_resolution.resolveStructDefaults(&sema, ty), | |
| 1241 | .@"enum" => Sema.type_resolution.resolveEnumValues(&sema, ty), | |
| 1242 | else => unreachable, | |
| 1243 | }; | |
| 1244 | result catch |err| switch (err) { | |
| 1249 | Sema.type_resolution.resolveStructDefaults(&sema, ty) catch |err| switch (err) { | |
| 1245 | 1250 | error.AnalysisFail => { |
| 1246 | 1251 | if (!zcu.failed_analysis.contains(anal_unit)) { |
| 1247 | 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 | 1275 | const tracy = trace(@src()); |
| 1271 | 1276 | defer tracy.end(); |
| 1272 | 1277 | |
| 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 | 1278 | const zcu = pt.zcu; |
| 1288 | 1279 | const gpa = zcu.gpa; |
| 1289 | 1280 | const ip = &zcu.intern_pool; |
| ... | ... | @@ -3033,7 +3024,7 @@ fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.Sem |
| 3033 | 3024 | const zir = file.zir.?; |
| 3034 | 3025 | |
| 3035 | 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)); | |
| 3037 | 3028 | |
| 3038 | 3029 | func.setAnalyzed(ip, io); |
| 3039 | 3030 | if (func.analysisUnordered(ip).inferred_error_set) { |
| ... | ... | @@ -3231,9 +3222,6 @@ fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.Sem |
| 3231 | 3222 | func.setResolvedErrorSet(ip, io, ies.resolved); |
| 3232 | 3223 | } |
| 3233 | 3224 | |
| 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 | 3225 | try sema.flushExports(); |
| 3238 | 3226 | |
| 3239 | 3227 | defer { |
| ... | ... | @@ -3835,7 +3823,6 @@ pub fn enumValue(pt: Zcu.PerThread, ty: Type, tag_int: InternPool.Index) Allocat |
| 3835 | 3823 | /// declaration order. |
| 3836 | 3824 | pub fn enumValueFieldIndex(pt: Zcu.PerThread, ty: Type, field_index: u32) Allocator.Error!Value { |
| 3837 | 3825 | const ip = &pt.zcu.intern_pool; |
| 3838 | ty.assertHasInits(pt.zcu); | |
| 3839 | 3826 | const enum_type = ip.loadEnumType(ty.toIntern()); |
| 3840 | 3827 | |
| 3841 | 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 | 3846 | |
| 3860 | 3847 | pub fn undefValue(pt: Zcu.PerThread, ty: Type) Allocator.Error!Value { |
| 3861 | 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 | 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 | 3930 | for (elems) |elem| { |
| 3942 | 3931 | if (!Value.fromInterned(elem).isUndef(pt.zcu)) break; |
| 3943 | 3932 | } else if (elems.len > 0) { |
| 3944 | return pt.undefValue(ty); // all-undef | |
| 3933 | // All undef, so return an undef struct. However, don't use `undefValue`, because its | |
| 3934 | // non-OPV assertion can loop on `[1]@TypeOf(undefined)`: that type has an OPV of | |
| 3935 | // `.{undefined}`, which here we normalize to `undefined`. | |
| 3936 | return .fromInterned(try pt.intern(.{ .undef = ty.toIntern() })); | |
| 3945 | 3937 | } |
| 3946 | 3938 | return .fromInterned(try pt.intern(.{ .aggregate = .{ |
| 3947 | 3939 | .ty = ty.toIntern(), |
| ... | ... | @@ -4096,19 +4088,6 @@ pub fn getExtern(pt: Zcu.PerThread, key: InternPool.Key.Extern) Allocator.Error! |
| 4096 | 4088 | return result.index; |
| 4097 | 4089 | } |
| 4098 | 4090 | |
| 4099 | // TODO: this shouldn't need a `PerThread`! Fix the signature of `Type.abiAlignment`. | |
| 4100 | // MLUGG TODO: that's done, move it! | |
| 4101 | pub 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 | 4091 | /// Given a namespace, re-scan its declarations from the type definition if they have not |
| 4113 | 4092 | /// yet been re-scanned on this update. |
| 4114 | 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 | 4372 | .@"struct" => switch (ip.indexToKey(ty.toIntern())) { |
| 4394 | 4373 | .struct_type => { |
| 4395 | 4374 | try pt.ensureTypeLayoutUpToDate(ty); |
| 4396 | try pt.ensureTypeInitsUpToDate(ty); | |
| 4375 | try pt.ensureStructDefaultsUpToDate(ty); | |
| 4397 | 4376 | }, |
| 4398 | 4377 | .tuple_type => |tuple| for (0..tuple.types.len) |i| { |
| 4399 | 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 | 4384 | }, |
| 4406 | 4385 | |
| 4407 | 4386 | .@"union" => try pt.ensureTypeLayoutUpToDate(ty), |
| 4408 | .@"enum" => try pt.ensureTypeInitsUpToDate(ty), | |
| 4387 | .@"enum" => try pt.ensureTypeLayoutUpToDate(ty), | |
| 4409 | 4388 | } |
| 4410 | 4389 | } |
| 4411 | 4390 | pub fn resolveValueTypesForCodegen(pt: Zcu.PerThread, val: Value) Zcu.SemaError!void { |
src/codegen.zig+5-6| ... | ... | @@ -347,7 +347,6 @@ pub fn generateSymbol( |
| 347 | 347 | .void => unreachable, // non-runtime value |
| 348 | 348 | .null => unreachable, // non-runtime value |
| 349 | 349 | .@"unreachable" => unreachable, // non-runtime value |
| 350 | .empty_tuple => return, | |
| 351 | 350 | .false, .true => try w.writeByte(switch (simple_value) { |
| 352 | 351 | .false => 0, |
| 353 | 352 | .true => 1, |
| ... | ... | @@ -1065,20 +1064,20 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo |
| 1065 | 1064 | const elem_ty = ty.childType(zcu); |
| 1066 | 1065 | const ptr = ip.indexToKey(val.toIntern()).ptr; |
| 1067 | 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 | 1068 | .int => unreachable, // handled above |
| 1070 | 1069 | |
| 1071 | .nav => |nav| if (elem_ty.isFnOrHasRuntimeBits(zcu)) { | |
| 1070 | .nav => |nav| if (elem_ty.isRuntimeFnOrHasRuntimeBits(zcu)) { | |
| 1072 | 1071 | return .{ .lea_nav = nav }; |
| 1073 | 1072 | } else { |
| 1074 | 1073 | // Create the 0xaa bit pattern... |
| 1075 | 1074 | const undef_ptr_bits: u64 = @intCast((@as(u66, 1) << @intCast(target.ptrBitWidth() + 1)) / 3); |
| 1076 | 1075 | // ...but align the pointer |
| 1077 | const alignment = pt.navAlignment(nav); | |
| 1076 | const alignment = zcu.navAlignment(nav); | |
| 1078 | 1077 | return .{ .immediate = alignment.forward(undef_ptr_bits) }; |
| 1079 | 1078 | }, |
| 1080 | 1079 | |
| 1081 | .uav => |uav| if (elem_ty.isFnOrHasRuntimeBits(zcu)) { | |
| 1080 | .uav => |uav| if (elem_ty.isRuntimeFnOrHasRuntimeBits(zcu)) { | |
| 1082 | 1081 | return .{ .lea_uav = uav }; |
| 1083 | 1082 | } else { |
| 1084 | 1083 | // Create the 0xaa bit pattern... |
| ... | ... | @@ -1089,7 +1088,7 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo |
| 1089 | 1088 | }, |
| 1090 | 1089 | |
| 1091 | 1090 | else => {}, |
| 1092 | } | |
| 1091 | }; | |
| 1093 | 1092 | }, |
| 1094 | 1093 | }, |
| 1095 | 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 | 6594 | if (try isel.hasRepeatedByteRepr(.fromInterned(fill_val))) |fill_byte| |
| 6595 | 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 | 6598 | 0 => unreachable, |
| 6599 | 6599 | 1 => break :fill_byte .{ .value = bin_op.rhs }, |
| 6600 | 6600 | 2, 4, 8 => |size| { |
| ... | ... | @@ -7217,7 +7217,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, |
| 7217 | 7217 | const ptr_ra = try ptr_vi.value.defReg(isel) orelse break :unused; |
| 7218 | 7218 | |
| 7219 | 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 | 7221 | false => { |
| 7222 | 7222 | try isel.nav_relocs.append(gpa, .{ |
| 7223 | 7223 | .nav = ty_nav.nav, |
| ... | ... | @@ -7240,7 +7240,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, |
| 7240 | 7240 | }); |
| 7241 | 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 | 7245 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; |
| 7246 | 7246 | }, |
| ... | ... | @@ -10738,7 +10738,7 @@ pub const Value = struct { |
| 10738 | 10738 | } }), |
| 10739 | 10739 | }), |
| 10740 | 10740 | .simple_value => |simple_value| switch (simple_value) { |
| 10741 | .undefined, .void, .null, .empty_tuple, .@"unreachable" => unreachable, | |
| 10741 | .undefined, .void, .null, .@"unreachable" => unreachable, | |
| 10742 | 10742 | .true => continue :constant_key .{ .int = .{ |
| 10743 | 10743 | .ty = .bool_type, |
| 10744 | 10744 | .storage = .{ .u64 = 1 }, |
| ... | ... | @@ -10931,7 +10931,7 @@ pub const Value = struct { |
| 10931 | 10931 | .ptr => |ptr| { |
| 10932 | 10932 | assert(offset == 0 and size == 8); |
| 10933 | 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 | 10935 | false => { |
| 10936 | 10936 | try isel.nav_relocs.append(zcu.gpa, .{ |
| 10937 | 10937 | .nav = nav, |
| ... | ... | @@ -10965,9 +10965,9 @@ pub const Value = struct { |
| 10965 | 10965 | }, |
| 10966 | 10966 | } else continue :constant_key .{ .int = .{ |
| 10967 | 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 | 10971 | false => { |
| 10972 | 10972 | try isel.uav_relocs.append(zcu.gpa, .{ |
| 10973 | 10973 | .uav = uav, |
src/codegen/c.zig+8-9| ... | ... | @@ -789,7 +789,7 @@ pub const DeclGen = struct { |
| 789 | 789 | |
| 790 | 790 | // Render an undefined pointer if we have a pointer to a zero-bit or comptime type. |
| 791 | 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 | 793 | return dg.writeCValue(w, .{ .undef = ptr_ty }); |
| 794 | 794 | } |
| 795 | 795 | |
| ... | ... | @@ -862,7 +862,7 @@ pub const DeclGen = struct { |
| 862 | 862 | // Render an undefined pointer if we have a pointer to a zero-bit or comptime type. |
| 863 | 863 | const nav_ty: Type = .fromInterned(ip.getNav(owner_nav).typeOf(ip)); |
| 864 | 864 | const ptr_ty = try pt.navPtrType(owner_nav); |
| 865 | if (!nav_ty.isFnOrHasRuntimeBits(zcu)) { | |
| 865 | if (!nav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) { | |
| 866 | 866 | return dg.writeCValue(w, .{ .undef = ptr_ty }); |
| 867 | 867 | } |
| 868 | 868 | |
| ... | ... | @@ -1043,7 +1043,6 @@ pub const DeclGen = struct { |
| 1043 | 1043 | .undefined => unreachable, |
| 1044 | 1044 | .void => unreachable, |
| 1045 | 1045 | .null => unreachable, |
| 1046 | .empty_tuple => unreachable, | |
| 1047 | 1046 | .@"unreachable" => unreachable, |
| 1048 | 1047 | |
| 1049 | 1048 | .false => try w.writeAll("false"), |
| ... | ... | @@ -3077,7 +3076,7 @@ pub fn genDecl(o: *Object) Error!void { |
| 3077 | 3076 | const nav = ip.getNav(o.dg.pass.nav); |
| 3078 | 3077 | const nav_ty: Type = .fromInterned(nav.typeOf(ip)); |
| 3079 | 3078 | |
| 3080 | if (!nav_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return; | |
| 3079 | if (!nav_ty.hasRuntimeBits(zcu)) return; | |
| 3081 | 3080 | switch (ip.indexToKey(nav.status.fully_resolved.val)) { |
| 3082 | 3081 | .@"extern" => |@"extern"| { |
| 3083 | 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 | 3675 | |
| 3677 | 3676 | const inst_ty = f.typeOfIndex(inst); |
| 3678 | 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); | |
| 3680 | 3679 | |
| 3681 | 3680 | const ptr = try f.resolveInst(bin_op.lhs); |
| 3682 | 3681 | const index = try f.resolveInst(bin_op.rhs); |
| ... | ... | @@ -3792,7 +3791,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3792 | 3791 | const zcu = pt.zcu; |
| 3793 | 3792 | const inst_ty = f.typeOfIndex(inst); |
| 3794 | 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 }; | |
| 3796 | 3795 | |
| 3797 | 3796 | const local = try f.allocLocalValue(.{ |
| 3798 | 3797 | .ctype = try f.ctypeFromType(elem_ty, .complete), |
| ... | ... | @@ -3829,7 +3828,7 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3829 | 3828 | const zcu = pt.zcu; |
| 3830 | 3829 | const inst_ty = f.typeOfIndex(inst); |
| 3831 | 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 }; | |
| 3833 | 3832 | |
| 3834 | 3833 | const local = try f.allocLocalValue(.{ |
| 3835 | 3834 | .ctype = try f.ctypeFromType(elem_ty, .complete), |
| ... | ... | @@ -4502,7 +4501,7 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue { |
| 4502 | 4501 | |
| 4503 | 4502 | const inst_ty = f.typeOfIndex(inst); |
| 4504 | 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 | 4505 | if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) return f.moveCValue(inst, inst_ty, lhs); |
| 4507 | 4506 | const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete); |
| 4508 | 4507 | |
| ... | ... | @@ -7037,7 +7036,7 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index, function_paren: []const u8) !CV |
| 7037 | 7036 | try w.writeAll(", "); |
| 7038 | 7037 | try writeArrayLen(f, dest_ptr, dest_ty); |
| 7039 | 7038 | try w.writeAll(" * sizeof("); |
| 7040 | try f.renderType(w, dest_ty.indexablePtrElem(zcu)); | |
| 7039 | try f.renderType(w, dest_ty.indexableElem(zcu)); | |
| 7041 | 7040 | try w.writeAll("));"); |
| 7042 | 7041 | try f.object.newline(); |
| 7043 | 7042 |
src/codegen/llvm.zig+7-8| ... | ... | @@ -3725,7 +3725,6 @@ pub const Object = struct { |
| 3725 | 3725 | .undefined => unreachable, // non-runtime value |
| 3726 | 3726 | .void => unreachable, // non-runtime value |
| 3727 | 3727 | .null => unreachable, // non-runtime value |
| 3728 | .empty_tuple => unreachable, // non-runtime value | |
| 3729 | 3728 | .@"unreachable" => unreachable, // non-runtime value |
| 3730 | 3729 | |
| 3731 | 3730 | .false => .false, |
| ... | ... | @@ -4604,7 +4603,7 @@ pub const NavGen = struct { |
| 4604 | 4603 | _ = try o.resolveLlvmFunction(pt, owner_nav); |
| 4605 | 4604 | } else { |
| 4606 | 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 | 4607 | if (resolved.@"linksection".toSlice(ip)) |section| |
| 4609 | 4608 | variable_index.setSection(try o.builder.string(section), &o.builder); |
| 4610 | 4609 | if (is_const) variable_index.setMutability(.constant, &o.builder); |
| ... | ... | @@ -5953,7 +5952,7 @@ pub const FuncGen = struct { |
| 5953 | 5952 | return .none; |
| 5954 | 5953 | } |
| 5955 | 5954 | |
| 5956 | const have_block_result = inst_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu); | |
| 5955 | const have_block_result = inst_ty.hasRuntimeBits(zcu); | |
| 5957 | 5956 | |
| 5958 | 5957 | var breaks: BreakList = if (have_block_result) .{ .list = .{} } else .{ .len = 0 }; |
| 5959 | 5958 | defer if (have_block_result) breaks.list.deinit(self.gpa); |
| ... | ... | @@ -6000,7 +5999,7 @@ pub const FuncGen = struct { |
| 6000 | 5999 | |
| 6001 | 6000 | // Add the values to the lists only if the break provides a value. |
| 6002 | 6001 | const operand_ty = self.typeOf(branch.operand); |
| 6003 | if (operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) { | |
| 6002 | if (operand_ty.hasRuntimeBits(zcu)) { | |
| 6004 | 6003 | const val = try self.resolveInst(branch.operand); |
| 6005 | 6004 | |
| 6006 | 6005 | // For the phi node, we need the basic blocks and the values of the |
| ... | ... | @@ -9581,7 +9580,7 @@ pub const FuncGen = struct { |
| 9581 | 9580 | const zcu = pt.zcu; |
| 9582 | 9581 | const ptr_ty = self.typeOfIndex(inst); |
| 9583 | 9582 | const pointee_type = ptr_ty.childType(zcu); |
| 9584 | if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) | |
| 9583 | if (!pointee_type.hasRuntimeBits(zcu)) | |
| 9585 | 9584 | return (try o.lowerPtrToVoid(pt, ptr_ty)).toValue(); |
| 9586 | 9585 | |
| 9587 | 9586 | const pointee_llvm_ty = try o.lowerType(pt, pointee_type); |
| ... | ... | @@ -9595,7 +9594,7 @@ pub const FuncGen = struct { |
| 9595 | 9594 | const zcu = pt.zcu; |
| 9596 | 9595 | const ptr_ty = self.typeOfIndex(inst); |
| 9597 | 9596 | const ret_ty = ptr_ty.childType(zcu); |
| 9598 | if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) | |
| 9597 | if (!ret_ty.hasRuntimeBits(zcu)) | |
| 9599 | 9598 | return (try o.lowerPtrToVoid(pt, ptr_ty)).toValue(); |
| 9600 | 9599 | if (self.ret_ptr != .none) return self.ret_ptr; |
| 9601 | 9600 | const ret_llvm_ty = try o.lowerType(pt, ret_ty); |
| ... | ... | @@ -9897,7 +9896,7 @@ pub const FuncGen = struct { |
| 9897 | 9896 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 9898 | 9897 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 9899 | 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 | 9900 | const ptr = try self.resolveInst(bin_op.lhs); |
| 9902 | 9901 | var element = try self.resolveInst(bin_op.rhs); |
| 9903 | 9902 | const llvm_abi_ty = try o.getAtomicAbiType(pt, operand_ty, false); |
| ... | ... | @@ -11478,7 +11477,7 @@ pub const FuncGen = struct { |
| 11478 | 11477 | const zcu = pt.zcu; |
| 11479 | 11478 | const info = ptr_ty.ptrInfo(zcu); |
| 11480 | 11479 | const elem_ty = Type.fromInterned(info.child); |
| 11481 | if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) { | |
| 11480 | if (!elem_ty.hasRuntimeBits(zcu)) { | |
| 11482 | 11481 | return; |
| 11483 | 11482 | } |
| 11484 | 11483 | const ptr_alignment = ptr_ty.ptrAlignment(zcu).toLlvm(); |
src/codegen/riscv64/CodeGen.zig+2-2| ... | ... | @@ -2673,7 +2673,7 @@ fn genBinOp( |
| 2673 | 2673 | defer func.register_manager.unlockReg(tmp_lock); |
| 2674 | 2674 | |
| 2675 | 2675 | // 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 | 2677 | const elem_size_reg = try func.copyToTmpRegister(Type.u64, .{ .immediate = elem_size }); |
| 2678 | 2678 | |
| 2679 | 2679 | try func.genBinOp( |
| ... | ... | @@ -3913,7 +3913,7 @@ fn airPtrElemVal(func: *Func, inst: Air.Inst.Index) !void { |
| 3913 | 3913 | const base_ptr_ty = func.typeOf(bin_op.lhs); |
| 3914 | 3914 | |
| 3915 | 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 | 3917 | if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none; |
| 3918 | 3918 | const base_ptr_mcv = try func.resolveInst(bin_op.lhs); |
| 3919 | 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 | 821 | .undefined, |
| 822 | 822 | .void, |
| 823 | 823 | .null, |
| 824 | .empty_tuple, | |
| 825 | 824 | .@"unreachable", |
| 826 | 825 | => unreachable, // non-runtime values |
| 827 | 826 | |
| ... | ... | @@ -1150,7 +1149,7 @@ fn constantUavRef( |
| 1150 | 1149 | } |
| 1151 | 1150 | |
| 1152 | 1151 | // const is_fn_body = decl_ty.zigTypeTag(zcu) == .@"fn"; |
| 1153 | if (!uav_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) { | |
| 1152 | if (!uav_ty.hasRuntimeBits(zcu)) { | |
| 1154 | 1153 | // Pointer to nothing - return undefined |
| 1155 | 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 | 1195 | }, |
| 1197 | 1196 | } |
| 1198 | 1197 | |
| 1199 | if (!nav_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) { | |
| 1198 | if (!nav_ty.hasRuntimeBits(zcu)) { | |
| 1200 | 1199 | // Pointer to nothing - return undefined. |
| 1201 | 1200 | return cg.module.constUndef(ty_id); |
| 1202 | 1201 | } |
| ... | ... | @@ -4381,7 +4380,7 @@ fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 4381 | 4380 | fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id { |
| 4382 | 4381 | const zcu = cg.module.zcu; |
| 4383 | 4382 | // 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 | 4384 | const elem_ty_id = try cg.resolveType(elem_ty, .indirect); |
| 4386 | 4385 | const elem_ptr_ty_id = try cg.module.ptrType(elem_ty_id, cg.module.storageClass(ptr_ty.ptrAddressSpace(zcu))); |
| 4387 | 4386 | if (ptr_ty.isSinglePointer(zcu)) { |
| ... | ... | @@ -5028,7 +5027,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index) |
| 5028 | 5027 | const gpa = cg.module.gpa; |
| 5029 | 5028 | const zcu = cg.module.zcu; |
| 5030 | 5029 | const ty = cg.typeOfIndex(inst); |
| 5031 | const have_block_result = ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu); | |
| 5030 | const have_block_result = ty.hasRuntimeBits(zcu); | |
| 5032 | 5031 | |
| 5033 | 5032 | const cf = switch (cg.control_flow) { |
| 5034 | 5033 | .structured => |*cf| cf, |
| ... | ... | @@ -5166,7 +5165,7 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void { |
| 5166 | 5165 | |
| 5167 | 5166 | switch (cg.control_flow) { |
| 5168 | 5167 | .structured => |*cf| { |
| 5169 | if (operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) { | |
| 5168 | if (operand_ty.hasRuntimeBits(zcu)) { | |
| 5170 | 5169 | const operand_id = try cg.resolve(br.operand); |
| 5171 | 5170 | const block_result_var_id = cf.block_results.get(br.block_inst).?; |
| 5172 | 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 | 5176 | }, |
| 5178 | 5177 | .unstructured => |cf| { |
| 5179 | 5178 | const block = cf.blocks.get(br.block_inst).?; |
| 5180 | if (operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) { | |
| 5179 | if (operand_ty.hasRuntimeBits(zcu)) { | |
| 5181 | 5180 | const operand_id = try cg.resolve(br.operand); |
| 5182 | 5181 | // block_label should not be undefined here, lest there |
| 5183 | 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 | 2099 | const child_type = cg.typeOfIndex(inst).childType(zcu); |
| 2100 | 2100 | |
| 2101 | 2101 | const result = result: { |
| 2102 | if (!child_type.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) { | |
| 2102 | if (!child_type.hasRuntimeBits(zcu)) { | |
| 2103 | 2103 | break :result try cg.allocStack(Type.usize); // create pointer to void |
| 2104 | 2104 | } |
| 2105 | 2105 | |
| ... | ... | @@ -3161,7 +3161,6 @@ fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue { |
| 3161 | 3161 | .undefined, |
| 3162 | 3162 | .void, |
| 3163 | 3163 | .null, |
| 3164 | .empty_tuple, | |
| 3165 | 3164 | .@"unreachable", |
| 3166 | 3165 | => unreachable, // non-runtime values |
| 3167 | 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 | 104121 | }, |
| 104122 | 104122 | .slice_elem_val, .ptr_elem_val => { |
| 104123 | 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 | 104125 | var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs }); |
| 104126 | 104126 | try ops[0].toSlicePtr(cg); |
| 104127 | 104127 | var res: [1]Temp = undefined; |
| ... | ... | @@ -188179,8 +188179,8 @@ const Select = struct { |
| 188179 | 188179 | .signed => false, |
| 188180 | 188180 | .unsigned => size.bitSize(cg.target) >= int_info.bits, |
| 188181 | 188181 | } else false, |
| 188182 | .elem_size_is => |size| size == ty.indexablePtrElem(zcu).abiSize(zcu), | |
| 188183 | .po2_elem_size => std.math.isPowerOfTwo(ty.indexablePtrElem(zcu).abiSize(zcu)), | |
| 188182 | .elem_size_is => |size| size == ty.indexableElem(zcu).abiSize(zcu), | |
| 188183 | .po2_elem_size => std.math.isPowerOfTwo(ty.indexableElem(zcu).abiSize(zcu)), | |
| 188184 | 188184 | }; |
| 188185 | 188185 | } |
| 188186 | 188186 | }; |
| ... | ... | @@ -189941,9 +189941,9 @@ const Select = struct { |
| 189941 | 189941 | op.flags.base.ref.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu), |
| 189942 | 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)), | |
| 189945 | .src0_elem_size => @intCast(Select.Operand.Ref.src0.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)), | |
| 189946 | .dst0_elem_size => @intCast(Select.Operand.Ref.dst0.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)), | |
| 189944 | .elem_size => @intCast(op.flags.base.ref.typeOf(s).indexableElem(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)), | |
| 189945 | .src0_elem_size => @intCast(Select.Operand.Ref.src0.typeOf(s).indexableElem(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)), | |
| 189946 | .dst0_elem_size => @intCast(Select.Operand.Ref.dst0.typeOf(s).indexableElem(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)), | |
| 189947 | 189947 | .src0_elem_size_mul_src1 => @intCast(Select.Operand.Ref.src0.typeOf(s).indexableElem(s.cg.pt.zcu).abiSize(s.cg.pt.zcu) * |
| 189948 | 189948 | Select.Operand.Ref.src1.valueOf(s).immediate), |
| 189949 | 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 | 189953 | .src1 => @intCast(Select.Operand.Ref.src1.valueOf(s).immediate), |
| 189954 | 189954 | .src1_sub_bit_size => @as(SignedImm, @intCast(Select.Operand.Ref.src1.valueOf(s).immediate)) - |
| 189955 | 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 | 189957 | .elem_mask => @as(u8, std.math.maxInt(u8)) >> @intCast( |
| 189958 | 189958 | 8 - ((s.cg.unalignedSize(op.flags.base.ref.typeOf(s)) - 1) % |
| 189959 | 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 | 1552 | const sec_si = try coff.navSection(zcu, nav.status.fully_resolved); |
| 1553 | 1553 | try coff.nodes.ensureUnusedCapacity(gpa, 1); |
| 1554 | 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 | 1556 | .moved = true, |
| 1557 | 1557 | }); |
| 1558 | 1558 | coff.nodes.appendAssumeCapacity(.{ .nav = nmi }); |
src/link/Elf/ZigObject.zig+1-1| ... | ... | @@ -1479,7 +1479,7 @@ fn updateTlv( |
| 1479 | 1479 | |
| 1480 | 1480 | log.debug("updateTlv {f}({d})", .{ nav.fqn.fmt(ip), nav_index }); |
| 1481 | 1481 | |
| 1482 | const required_alignment = pt.navAlignment(nav_index); | |
| 1482 | const required_alignment = zcu.navAlignment(nav_index); | |
| 1483 | 1483 | |
| 1484 | 1484 | const sym = self.symbol(sym_index); |
| 1485 | 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 | 2906 | try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 2907 | 2907 | const sec_si = elf.navSection(ip, nav.status.fully_resolved); |
| 2908 | 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 | 2910 | .moved = true, |
| 2911 | 2911 | }); |
| 2912 | 2912 | elf.nodes.appendAssumeCapacity(.{ .nav = nmi }); |
src/link/MachO/ZigObject.zig+4-4| ... | ... | @@ -925,7 +925,7 @@ pub fn updateNav( |
| 925 | 925 | |
| 926 | 926 | const sect_index = try self.getNavOutputSection(macho_file, zcu, nav_index, code); |
| 927 | 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 | 929 | else |
| 930 | 930 | try self.updateNavCode(macho_file, pt, nav_index, sym_index, sect_index, code); |
| 931 | 931 | |
| ... | ... | @@ -1030,13 +1030,13 @@ fn updateNavCode( |
| 1030 | 1030 | fn updateTlv( |
| 1031 | 1031 | self: *ZigObject, |
| 1032 | 1032 | macho_file: *MachO, |
| 1033 | pt: Zcu.PerThread, | |
| 1033 | zcu: *Zcu, | |
| 1034 | 1034 | nav_index: InternPool.Nav.Index, |
| 1035 | 1035 | sym_index: Symbol.Index, |
| 1036 | 1036 | sect_index: u8, |
| 1037 | 1037 | code: []const u8, |
| 1038 | 1038 | ) !void { |
| 1039 | const ip = &pt.zcu.intern_pool; | |
| 1039 | const ip = &zcu.intern_pool; | |
| 1040 | 1040 | const nav = ip.getNav(nav_index); |
| 1041 | 1041 | |
| 1042 | 1042 | log.debug("updateTlv {f} (0x{x})", .{ nav.fqn.fmt(ip), nav_index }); |
| ... | ... | @@ -1045,7 +1045,7 @@ fn updateTlv( |
| 1045 | 1045 | const init_sym_index = try self.createTlvInitializer( |
| 1046 | 1046 | macho_file, |
| 1047 | 1047 | nav.fqn.toSlice(ip), |
| 1048 | pt.navAlignment(nav_index), | |
| 1048 | zcu.navAlignment(nav_index), | |
| 1049 | 1049 | sect_index, |
| 1050 | 1050 | code, |
| 1051 | 1051 | ); |
src/print_value.zig+26-12| ... | ... | @@ -72,8 +72,13 @@ pub fn print( |
| 72 | 72 | .undef => try writer.writeAll("undefined"), |
| 73 | 73 | .simple_value => |simple_value| switch (simple_value) { |
| 74 | 74 | .void => try writer.writeAll("{}"), |
| 75 | .empty_tuple => try writer.writeAll(".{}"), | |
| 76 | else => try writer.writeAll(@tagName(simple_value)), | |
| 75 | ||
| 76 | .undefined, | |
| 77 | .null, | |
| 78 | .true, | |
| 79 | .false, | |
| 80 | .@"unreachable", | |
| 81 | => try writer.writeAll(@tagName(simple_value)), | |
| 77 | 82 | }, |
| 78 | 83 | .variable => try writer.writeAll("(variable)"), |
| 79 | 84 | .@"extern" => |e| try writer.print("(extern '{f}')", .{e.name.fmt(ip)}), |
| ... | ... | @@ -248,17 +253,26 @@ fn printAggregate( |
| 248 | 253 | const len = ty.arrayLen(zcu); |
| 249 | 254 | |
| 250 | 255 | if (is_ref) try writer.writeByte('&'); |
| 251 | try writer.writeAll(".{ "); | |
| 252 | ||
| 253 | const max_len = @min(len, max_aggregate_items); | |
| 254 | for (0..max_len) |i| { | |
| 255 | if (i != 0) try writer.writeAll(", "); | |
| 256 | try print(try val.fieldValue(pt, i), writer, level - 1, pt, opt_sema); | |
| 257 | } | |
| 258 | if (len > max_aggregate_items) { | |
| 259 | try writer.writeAll(", ..."); | |
| 256 | switch (len) { | |
| 257 | 0 => try writer.writeAll(".{}"), | |
| 258 | 1 => { | |
| 259 | try writer.writeAll(".{"); | |
| 260 | try print(try val.fieldValue(pt, 0), writer, level - 1, pt, opt_sema); | |
| 261 | try writer.writeByte('}'); | |
| 262 | }, | |
| 263 | else => { | |
| 264 | try writer.writeAll(".{ "); | |
| 265 | const max_len = @min(len, max_aggregate_items); | |
| 266 | for (0..max_len) |i| { | |
| 267 | if (i != 0) try writer.writeAll(", "); | |
| 268 | try print(try val.fieldValue(pt, i), writer, level - 1, pt, opt_sema); | |
| 269 | } | |
| 270 | if (len > max_aggregate_items) { | |
| 271 | try writer.writeAll(", ..."); | |
| 272 | } | |
| 273 | try writer.writeAll(" }"); | |
| 274 | }, | |
| 260 | 275 | } |
| 261 | return writer.writeAll(" }"); | |
| 262 | 276 | } |
| 263 | 277 | |
| 264 | 278 | fn printPtr( |
src/print_zir.zig+15-11| ... | ... | @@ -1439,10 +1439,10 @@ const Writer = struct { |
| 1439 | 1439 | |
| 1440 | 1440 | try stream.print("{s}, ", .{@tagName(struct_decl.name_strategy)}); |
| 1441 | 1441 | |
| 1442 | if (struct_decl.backing_int_type != .none) { | |
| 1442 | if (struct_decl.backing_int_type_body) |backing_int_type_body| { | |
| 1443 | 1443 | assert(struct_decl.layout == .@"packed"); |
| 1444 | 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 | 1446 | try stream.writeAll("), "); |
| 1447 | 1447 | } else { |
| 1448 | 1448 | try stream.print("{s}, ", .{@tagName(struct_decl.layout)}); |
| ... | ... | @@ -1507,18 +1507,18 @@ const Writer = struct { |
| 1507 | 1507 | .@"packed" => try stream.writeAll("packed, "), |
| 1508 | 1508 | .packed_explicit => { |
| 1509 | 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 | 1511 | try stream.writeAll("), "); |
| 1512 | 1512 | }, |
| 1513 | 1513 | .tagged_explicit => { |
| 1514 | try stream.writeAll("auto("); | |
| 1515 | try self.writeInstRef(stream, union_decl.arg_type); | |
| 1514 | try stream.writeAll("tagged("); | |
| 1515 | try self.writeBracedDecl(stream, union_decl.arg_type_body.?); | |
| 1516 | 1516 | try stream.writeAll("), "); |
| 1517 | 1517 | }, |
| 1518 | .tagged_enum => try stream.writeAll("auto(enum)"), | |
| 1518 | .tagged_enum => try stream.writeAll("tagged(enum), "), | |
| 1519 | 1519 | .tagged_enum_explicit => { |
| 1520 | try stream.writeAll("auto(enum("); | |
| 1521 | try self.writeInstRef(stream, union_decl.arg_type); | |
| 1520 | try stream.writeAll("tagged(enum("); | |
| 1521 | try self.writeBracedDecl(stream, union_decl.arg_type_body.?); | |
| 1522 | 1522 | try stream.writeAll(")), "); |
| 1523 | 1523 | }, |
| 1524 | 1524 | } |
| ... | ... | @@ -1577,7 +1577,11 @@ const Writer = struct { |
| 1577 | 1577 | |
| 1578 | 1578 | try stream.print("{s}, ", .{@tagName(enum_decl.name_strategy)}); |
| 1579 | 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 | } | |
| 1581 | 1585 | |
| 1582 | 1586 | try self.writeCaptures(stream, enum_decl.captures, enum_decl.capture_names); |
| 1583 | 1587 | try stream.writeAll(", "); |
| ... | ... | @@ -1585,9 +1589,9 @@ const Writer = struct { |
| 1585 | 1589 | try stream.writeAll(", "); |
| 1586 | 1590 | |
| 1587 | 1591 | if (enum_decl.field_names.len == 0) { |
| 1588 | try stream.writeAll(", {}) "); | |
| 1592 | try stream.writeAll("{}) "); | |
| 1589 | 1593 | } else { |
| 1590 | try stream.writeAll(", {\n"); | |
| 1594 | try stream.writeAll("{\n"); | |
| 1591 | 1595 | self.indent += 2; |
| 1592 | 1596 | |
| 1593 | 1597 | var it = enum_decl.iterateFields(); |