| 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,6 +837,10 @@ pub const SimpleComptimeReason = enum(u32) { |
| 837 | tuple_field_types, | 837 | tuple_field_types, |
| 838 | enum_field_names, | 838 | enum_field_names, |
| 839 | enum_field_values, | 839 | enum_field_values, |
| 840 | union_enum_tag_type, | ||
| 841 | enum_int_tag_type, | ||
| 842 | packed_struct_backing_int_type, | ||
| 843 | packed_union_backing_int_type, | ||
| 840 | 844 | ||
| 841 | // Evaluating at comptime because decl/field name must be comptime-known. | 845 | // Evaluating at comptime because decl/field name must be comptime-known. |
| 842 | decl_name, | 846 | decl_name, |
| ... | @@ -925,6 +929,11 @@ pub const SimpleComptimeReason = enum(u32) { | ... | @@ -925,6 +929,11 @@ pub const SimpleComptimeReason = enum(u32) { |
| 925 | .enum_field_names => "enum field names must be comptime-known", | 929 | .enum_field_names => "enum field names must be comptime-known", |
| 926 | .enum_field_values => "enum field values must be comptime-known", | 930 | .enum_field_values => "enum field values must be comptime-known", |
| 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 | .decl_name => "declaration name must be comptime-known", | 937 | .decl_name => "declaration name must be comptime-known", |
| 929 | .field_name => "field name must be comptime-known", | 938 | .field_name => "field name must be comptime-known", |
| 930 | .tuple_field_index => "tuple field index must be comptime-known", | 939 | .tuple_field_index => "tuple field index must be comptime-known", |
lib/std/zig/AstGen.zig+69-54| ... | @@ -4922,24 +4922,14 @@ fn structDeclInner( | ... | @@ -4922,24 +4922,14 @@ fn structDeclInner( |
| 4922 | 4922 | ||
| 4923 | astgen.advanceSourceCursorToNode(node); | 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 | const decl_inst = try gz.reserveInstructionIndex(); | 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 | try gz.setStruct(decl_inst, .{ | 4928 | try gz.setStruct(decl_inst, .{ |
| 4939 | .src_node = node, | 4929 | .src_node = node, |
| 4940 | .name_strat = name_strat, | 4930 | .name_strat = name_strat, |
| 4941 | .layout = layout, | 4931 | .layout = layout, |
| 4942 | .backing_int_type = .none, | 4932 | .backing_int_type_body_len = null, |
| 4943 | .decls_len = 0, | 4933 | .decls_len = 0, |
| 4944 | .fields_len = 0, | 4934 | .fields_len = 0, |
| 4945 | .any_field_aligns = false, | 4935 | .any_field_aligns = false, |
| ... | @@ -4993,6 +4983,22 @@ fn structDeclInner( | ... | @@ -4993,6 +4983,22 @@ fn structDeclInner( |
| 4993 | ); | 4983 | ); |
| 4994 | if (field_comptime_bits) |bits| @memset(bits.get(astgen), 0); | 4984 | if (field_comptime_bits) |bits| @memset(bits.get(astgen), 0); |
| 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 | const old_hasher = astgen.src_hasher; | 5002 | const old_hasher = astgen.src_hasher; |
| 4997 | defer astgen.src_hasher = old_hasher; | 5003 | defer astgen.src_hasher = old_hasher; |
| 4998 | astgen.src_hasher = .init(.{}); | 5004 | astgen.src_hasher = .init(.{}); |
| ... | @@ -5076,7 +5082,7 @@ fn structDeclInner( | ... | @@ -5076,7 +5082,7 @@ fn structDeclInner( |
| 5076 | .src_node = node, | 5082 | .src_node = node, |
| 5077 | .name_strat = name_strat, | 5083 | .name_strat = name_strat, |
| 5078 | .layout = layout, | 5084 | .layout = layout, |
| 5079 | .backing_int_type = backing_int_type_ref, | 5085 | .backing_int_type_body_len = backing_int_type_body_len, |
| 5080 | .decls_len = scan_result.decls_len, | 5086 | .decls_len = scan_result.decls_len, |
| 5081 | .fields_len = scan_result.fields_len, | 5087 | .fields_len = scan_result.fields_len, |
| 5082 | .any_field_aligns = scan_result.any_field_aligns, | 5088 | .any_field_aligns = scan_result.any_field_aligns, |
| ... | @@ -5220,11 +5226,6 @@ fn unionDeclInner( | ... | @@ -5220,11 +5226,6 @@ fn unionDeclInner( |
| 5220 | 5226 | ||
| 5221 | astgen.advanceSourceCursorToNode(node); | 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 | const decl_inst = try gz.reserveInstructionIndex(); | 5229 | const decl_inst = try gz.reserveInstructionIndex(); |
| 5229 | 5230 | ||
| 5230 | var namespace: Scope.Namespace = .{ | 5231 | var namespace: Scope.Namespace = .{ |
| ... | @@ -5262,6 +5263,17 @@ fn unionDeclInner( | ... | @@ -5262,6 +5263,17 @@ fn unionDeclInner( |
| 5262 | const field_align_body_lens = try scratch.addOptionalSlice(scan_result.any_field_aligns, scan_result.fields_len); | 5263 | const field_align_body_lens = try scratch.addOptionalSlice(scan_result.any_field_aligns, scan_result.fields_len); |
| 5263 | const field_value_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, scan_result.fields_len); | 5264 | const field_value_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, scan_result.fields_len); |
| 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 | const old_hasher = astgen.src_hasher; | 5277 | const old_hasher = astgen.src_hasher; |
| 5266 | defer astgen.src_hasher = old_hasher; | 5278 | defer astgen.src_hasher = old_hasher; |
| 5267 | astgen.src_hasher = .init(.{}); | 5279 | astgen.src_hasher = .init(.{}); |
| ... | @@ -5358,7 +5370,7 @@ fn unionDeclInner( | ... | @@ -5358,7 +5370,7 @@ fn unionDeclInner( |
| 5358 | .@"extern" => .@"extern", | 5370 | .@"extern" => .@"extern", |
| 5359 | .@"packed" => if (opt_arg_node != .none) .packed_explicit else .@"packed", | 5371 | .@"packed" => if (opt_arg_node != .none) .packed_explicit else .@"packed", |
| 5360 | }, | 5372 | }, |
| 5361 | .arg_type = arg_type_ref, | 5373 | .arg_type_body_len = arg_type_body_len, |
| 5362 | .decls_len = scan_result.decls_len, | 5374 | .decls_len = scan_result.decls_len, |
| 5363 | .fields_len = scan_result.fields_len, | 5375 | .fields_len = scan_result.fields_len, |
| 5364 | .any_field_aligns = scan_result.any_field_aligns, | 5376 | .any_field_aligns = scan_result.any_field_aligns, |
| ... | @@ -5420,11 +5432,6 @@ fn containerDecl( | ... | @@ -5420,11 +5432,6 @@ fn containerDecl( |
| 5420 | 5432 | ||
| 5421 | astgen.advanceSourceCursorToNode(node); | 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 | const decl_inst = try gz.reserveInstructionIndex(); | 5435 | const decl_inst = try gz.reserveInstructionIndex(); |
| 5429 | 5436 | ||
| 5430 | var namespace: Scope.Namespace = .{ | 5437 | var namespace: Scope.Namespace = .{ |
| ... | @@ -5461,6 +5468,17 @@ fn containerDecl( | ... | @@ -5461,6 +5468,17 @@ fn containerDecl( |
| 5461 | const field_names = try scratch.addSlice(fields_len); | 5468 | const field_names = try scratch.addSlice(fields_len); |
| 5462 | const field_value_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, fields_len); | 5469 | const field_value_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, fields_len); |
| 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 | const old_hasher = astgen.src_hasher; | 5482 | const old_hasher = astgen.src_hasher; |
| 5465 | defer astgen.src_hasher = old_hasher; | 5483 | defer astgen.src_hasher = old_hasher; |
| 5466 | astgen.src_hasher = .init(.{}); | 5484 | astgen.src_hasher = .init(.{}); |
| ... | @@ -5508,7 +5526,7 @@ fn containerDecl( | ... | @@ -5508,7 +5526,7 @@ fn containerDecl( |
| 5508 | field_names.get(astgen)[field_idx] = @intFromEnum(try astgen.identAsString(member.ast.main_token)); | 5526 | field_names.get(astgen)[field_idx] = @intFromEnum(try astgen.identAsString(member.ast.main_token)); |
| 5509 | 5527 | ||
| 5510 | if (member.ast.value_expr.unwrap()) |value_node| { | 5528 | if (member.ast.value_expr.unwrap()) |value_node| { |
| 5511 | if (tag_type_ref == .none) { | 5529 | if (tag_type_body_len == null) { |
| 5512 | return astgen.failNodeNotes(node, "explicitly valued enum missing integer tag type", .{}, &.{ | 5530 | return astgen.failNodeNotes(node, "explicitly valued enum missing integer tag type", .{}, &.{ |
| 5513 | try astgen.errNoteNode(value_node, "tag value specified here", .{}), | 5531 | try astgen.errNoteNode(value_node, "tag value specified here", .{}), |
| 5514 | }); | 5532 | }); |
| ... | @@ -5535,7 +5553,7 @@ fn containerDecl( | ... | @@ -5535,7 +5553,7 @@ fn containerDecl( |
| 5535 | try gz.setEnum(decl_inst, .{ | 5553 | try gz.setEnum(decl_inst, .{ |
| 5536 | .src_node = node, | 5554 | .src_node = node, |
| 5537 | .name_strat = name_strat, | 5555 | .name_strat = name_strat, |
| 5538 | .tag_type = tag_type_ref, | 5556 | .tag_type_body_len = tag_type_body_len, |
| 5539 | .nonexhaustive = scan_result.has_underscore_field, | 5557 | .nonexhaustive = scan_result.has_underscore_field, |
| 5540 | .decls_len = scan_result.decls_len, | 5558 | .decls_len = scan_result.decls_len, |
| 5541 | .fields_len = fields_len, | 5559 | .fields_len = fields_len, |
| ... | @@ -12406,7 +12424,7 @@ const GenZir = struct { | ... | @@ -12406,7 +12424,7 @@ const GenZir = struct { |
| 12406 | src_node: Ast.Node.Index, | 12424 | src_node: Ast.Node.Index, |
| 12407 | name_strat: Zir.Inst.NameStrategy, | 12425 | name_strat: Zir.Inst.NameStrategy, |
| 12408 | layout: std.builtin.Type.ContainerLayout, | 12426 | layout: std.builtin.Type.ContainerLayout, |
| 12409 | backing_int_type: Zir.Inst.Ref, | 12427 | backing_int_type_body_len: ?u32, |
| 12410 | decls_len: u32, | 12428 | decls_len: u32, |
| 12411 | fields_len: u32, | 12429 | fields_len: u32, |
| 12412 | any_field_aligns: bool, | 12430 | any_field_aligns: bool, |
| ... | @@ -12430,7 +12448,7 @@ const GenZir = struct { | ... | @@ -12430,7 +12448,7 @@ const GenZir = struct { |
| 12430 | const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash); | 12448 | const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash); |
| 12431 | 12449 | ||
| 12432 | try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len + | 12450 | try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len + |
| 12433 | 4 + // `captures_len`, `decls_len`, `fields_len`, `backing_int_type` | 12451 | 4 + // `captures_len`, `decls_len`, `fields_len`, `backing_int_type_body_len` |
| 12434 | captures_len * 2 + // `capture`, `capture_name` | 12452 | captures_len * 2 + // `capture`, `capture_name` |
| 12435 | args.remaining.len); | 12453 | args.remaining.len); |
| 12436 | 12454 | ||
| ... | @@ -12446,7 +12464,7 @@ const GenZir = struct { | ... | @@ -12446,7 +12464,7 @@ const GenZir = struct { |
| 12446 | if (captures_len != 0) astgen.extra.appendAssumeCapacity(captures_len); | 12464 | if (captures_len != 0) astgen.extra.appendAssumeCapacity(captures_len); |
| 12447 | if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len); | 12465 | if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len); |
| 12448 | if (args.fields_len != 0) astgen.extra.appendAssumeCapacity(args.fields_len); | 12466 | if (args.fields_len != 0) astgen.extra.appendAssumeCapacity(args.fields_len); |
| 12449 | if (args.backing_int_type != .none) astgen.extra.appendAssumeCapacity(@intFromEnum(args.backing_int_type)); | 12467 | if (args.backing_int_type_body_len) |n| astgen.extra.appendAssumeCapacity(n); |
| 12450 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures)); | 12468 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures)); |
| 12451 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names)); | 12469 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names)); |
| 12452 | astgen.extra.appendSliceAssumeCapacity(args.remaining); | 12470 | astgen.extra.appendSliceAssumeCapacity(args.remaining); |
| ... | @@ -12461,7 +12479,7 @@ const GenZir = struct { | ... | @@ -12461,7 +12479,7 @@ const GenZir = struct { |
| 12461 | .has_fields_len = args.fields_len != 0, | 12479 | .has_fields_len = args.fields_len != 0, |
| 12462 | .name_strategy = args.name_strat, | 12480 | .name_strategy = args.name_strat, |
| 12463 | .layout = args.layout, | 12481 | .layout = args.layout, |
| 12464 | .has_backing_int_type = args.backing_int_type != .none, | 12482 | .has_backing_int_type = args.backing_int_type_body_len != null, |
| 12465 | .any_field_aligns = args.any_field_aligns, | 12483 | .any_field_aligns = args.any_field_aligns, |
| 12466 | .any_field_defaults = args.any_field_defaults, | 12484 | .any_field_defaults = args.any_field_defaults, |
| 12467 | .any_comptime_fields = args.any_comptime_fields, | 12485 | .any_comptime_fields = args.any_comptime_fields, |
| ... | @@ -12475,7 +12493,7 @@ const GenZir = struct { | ... | @@ -12475,7 +12493,7 @@ const GenZir = struct { |
| 12475 | src_node: Ast.Node.Index, | 12493 | src_node: Ast.Node.Index, |
| 12476 | name_strat: Zir.Inst.NameStrategy, | 12494 | name_strat: Zir.Inst.NameStrategy, |
| 12477 | kind: Zir.Inst.UnionDecl.Kind, | 12495 | kind: Zir.Inst.UnionDecl.Kind, |
| 12478 | arg_type: Zir.Inst.Ref, | 12496 | arg_type_body_len: ?u32, |
| 12479 | decls_len: u32, | 12497 | decls_len: u32, |
| 12480 | fields_len: u32, | 12498 | fields_len: u32, |
| 12481 | any_field_aligns: bool, | 12499 | any_field_aligns: bool, |
| ... | @@ -12497,7 +12515,7 @@ const GenZir = struct { | ... | @@ -12497,7 +12515,7 @@ const GenZir = struct { |
| 12497 | const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash); | 12515 | const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash); |
| 12498 | 12516 | ||
| 12499 | try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.UnionDecl).@"struct".fields.len + | 12517 | try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.UnionDecl).@"struct".fields.len + |
| 12500 | 4 + // `captures_len`, `decls_len`, `fields_len`, `backing_int_type` | 12518 | 4 + // `captures_len`, `decls_len`, `fields_len`, `arg_type_body_len` |
| 12501 | captures_len * 2 + // `capture`, `capture_name` | 12519 | captures_len * 2 + // `capture`, `capture_name` |
| 12502 | args.remaining.len); | 12520 | args.remaining.len); |
| 12503 | 12521 | ||
| ... | @@ -12514,10 +12532,9 @@ const GenZir = struct { | ... | @@ -12514,10 +12532,9 @@ const GenZir = struct { |
| 12514 | if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len); | 12532 | if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len); |
| 12515 | if (args.fields_len != 0) astgen.extra.appendAssumeCapacity(args.fields_len); | 12533 | if (args.fields_len != 0) astgen.extra.appendAssumeCapacity(args.fields_len); |
| 12516 | if (args.kind.hasArgType()) { | 12534 | if (args.kind.hasArgType()) { |
| 12517 | assert(args.arg_type != .none); | 12535 | astgen.extra.appendAssumeCapacity(args.arg_type_body_len.?); |
| 12518 | astgen.extra.appendAssumeCapacity(@intFromEnum(args.arg_type)); | ||
| 12519 | } else { | 12536 | } else { |
| 12520 | assert(args.arg_type == .none); | 12537 | assert(args.arg_type_body_len == null); |
| 12521 | } | 12538 | } |
| 12522 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures)); | 12539 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures)); |
| 12523 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names)); | 12540 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names)); |
| ... | @@ -12525,28 +12542,26 @@ const GenZir = struct { | ... | @@ -12525,28 +12542,26 @@ const GenZir = struct { |
| 12525 | 12542 | ||
| 12526 | astgen.instructions.set(@intFromEnum(inst), .{ | 12543 | astgen.instructions.set(@intFromEnum(inst), .{ |
| 12527 | .tag = .extended, | 12544 | .tag = .extended, |
| 12528 | .data = .{ | 12545 | .data = .{ .extended = .{ |
| 12529 | .extended = .{ | 12546 | .opcode = .union_decl, |
| 12530 | .opcode = .union_decl, | 12547 | .small = @bitCast(Zir.Inst.UnionDecl.Small{ |
| 12531 | .small = @bitCast(Zir.Inst.UnionDecl.Small{ | 12548 | .has_captures_len = captures_len != 0, |
| 12532 | .has_captures_len = captures_len != 0, | 12549 | .has_decls_len = args.decls_len != 0, |
| 12533 | .has_decls_len = args.decls_len != 0, | 12550 | .has_fields_len = args.fields_len != 0, |
| 12534 | .has_fields_len = args.fields_len != 0, | 12551 | .name_strategy = args.name_strat, |
| 12535 | .name_strategy = args.name_strat, | 12552 | .kind = args.kind, |
| 12536 | .kind = args.kind, | 12553 | .any_field_aligns = args.any_field_aligns, |
| 12537 | .any_field_aligns = args.any_field_aligns, | 12554 | .any_field_values = args.any_field_values, |
| 12538 | .any_field_values = args.any_field_values, | 12555 | }), |
| 12539 | }), | 12556 | .operand = payload_index, |
| 12540 | .operand = payload_index, | 12557 | } }, |
| 12541 | }, | ||
| 12542 | }, | ||
| 12543 | }); | 12558 | }); |
| 12544 | } | 12559 | } |
| 12545 | 12560 | ||
| 12546 | fn setEnum(gz: *GenZir, inst: Zir.Inst.Index, args: struct { | 12561 | fn setEnum(gz: *GenZir, inst: Zir.Inst.Index, args: struct { |
| 12547 | src_node: Ast.Node.Index, | 12562 | src_node: Ast.Node.Index, |
| 12548 | name_strat: Zir.Inst.NameStrategy, | 12563 | name_strat: Zir.Inst.NameStrategy, |
| 12549 | tag_type: Zir.Inst.Ref, | 12564 | tag_type_body_len: ?u32, |
| 12550 | nonexhaustive: bool, | 12565 | nonexhaustive: bool, |
| 12551 | decls_len: u32, | 12566 | decls_len: u32, |
| 12552 | fields_len: u32, | 12567 | fields_len: u32, |
| ... | @@ -12568,7 +12583,7 @@ const GenZir = struct { | ... | @@ -12568,7 +12583,7 @@ const GenZir = struct { |
| 12568 | const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash); | 12583 | const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash); |
| 12569 | 12584 | ||
| 12570 | try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.EnumDecl).@"struct".fields.len + | 12585 | try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.EnumDecl).@"struct".fields.len + |
| 12571 | 4 + // `captures_len`, `decls_len`, `fields_len`, `tag_type` | 12586 | 4 + // `captures_len`, `decls_len`, `fields_len`, `tag_type_body_len` |
| 12572 | captures_len * 2 + // `capture`, `capture_name` | 12587 | captures_len * 2 + // `capture`, `capture_name` |
| 12573 | args.remaining.len); | 12588 | args.remaining.len); |
| 12574 | 12589 | ||
| ... | @@ -12584,7 +12599,7 @@ const GenZir = struct { | ... | @@ -12584,7 +12599,7 @@ const GenZir = struct { |
| 12584 | if (captures_len != 0) astgen.extra.appendAssumeCapacity(captures_len); | 12599 | if (captures_len != 0) astgen.extra.appendAssumeCapacity(captures_len); |
| 12585 | if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len); | 12600 | if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len); |
| 12586 | if (args.fields_len != 0) astgen.extra.appendAssumeCapacity(args.fields_len); | 12601 | if (args.fields_len != 0) astgen.extra.appendAssumeCapacity(args.fields_len); |
| 12587 | if (args.tag_type != .none) astgen.extra.appendAssumeCapacity(@intFromEnum(args.tag_type)); | 12602 | if (args.tag_type_body_len) |n| astgen.extra.appendAssumeCapacity(n); |
| 12588 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures)); | 12603 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures)); |
| 12589 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names)); | 12604 | astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names)); |
| 12590 | astgen.extra.appendSliceAssumeCapacity(args.remaining); | 12605 | astgen.extra.appendSliceAssumeCapacity(args.remaining); |
| ... | @@ -12598,7 +12613,7 @@ const GenZir = struct { | ... | @@ -12598,7 +12613,7 @@ const GenZir = struct { |
| 12598 | .has_decls_len = args.decls_len != 0, | 12613 | .has_decls_len = args.decls_len != 0, |
| 12599 | .has_fields_len = args.fields_len != 0, | 12614 | .has_fields_len = args.fields_len != 0, |
| 12600 | .name_strategy = args.name_strat, | 12615 | .name_strategy = args.name_strat, |
| 12601 | .has_tag_type = args.tag_type != .none, | 12616 | .has_tag_type = args.tag_type_body_len != null, |
| 12602 | .nonexhaustive = args.nonexhaustive, | 12617 | .nonexhaustive = args.nonexhaustive, |
| 12603 | .any_field_values = args.any_field_values, | 12618 | .any_field_values = args.any_field_values, |
| 12604 | }), | 12619 | }), |
lib/std/zig/Zir.zig+42-36| ... | @@ -3465,7 +3465,7 @@ pub const Inst = struct { | ... | @@ -3465,7 +3465,7 @@ pub const Inst = struct { |
| 3465 | /// 0. captures_len: u32 // if `has_captures_len` | 3465 | /// 0. captures_len: u32 // if `has_captures_len` |
| 3466 | /// 1. decls_len: u32, // if `has_decls_len` | 3466 | /// 1. decls_len: u32, // if `has_decls_len` |
| 3467 | /// 2. fields_len: u32, // if `has_fields_len` | 3467 | /// 2. fields_len: u32, // if `has_fields_len` |
| 3468 | /// 3. backing_int_type: Ref // if `has_backing_int` | 3468 | /// 3. backing_int_body_len: u32 // if `has_backing_int` |
| 3469 | /// 4. capture: Capture // for every `captures_len` | 3469 | /// 4. capture: Capture // for every `captures_len` |
| 3470 | /// 5. capture_name: NullTerminatedString // for every `captures_len` | 3470 | /// 5. capture_name: NullTerminatedString // for every `captures_len` |
| 3471 | /// 6. decl: Index, // for every `decls_len`; points to a `declaration` instruction | 3471 | /// 6. decl: Index, // for every `decls_len`; points to a `declaration` instruction |
| ... | @@ -3475,7 +3475,8 @@ pub const Inst = struct { | ... | @@ -3475,7 +3475,8 @@ pub const Inst = struct { |
| 3475 | /// 10. field_default_body_len: u32 // for every `fields_len` if `any_field_defaults` | 3475 | /// 10. field_default_body_len: u32 // for every `fields_len` if `any_field_defaults` |
| 3476 | /// 11. field_comptime_bits: u32 // one bit per `fields_len` if `any_comptime_fields` | 3476 | /// 11. field_comptime_bits: u32 // one bit per `fields_len` if `any_comptime_fields` |
| 3477 | /// // LSB is first field, minimum number of `u32` needed | 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 | pub const StructDecl = struct { | 3480 | pub const StructDecl = struct { |
| 3480 | // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`. | 3481 | // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`. |
| 3481 | // This hash contains the source of all fields, and any specified attributes (`extern`, backing type, etc). | 3482 | // This hash contains the source of all fields, and any specified attributes (`extern`, backing type, etc). |
| ... | @@ -3622,13 +3623,14 @@ pub const Inst = struct { | ... | @@ -3622,13 +3623,14 @@ pub const Inst = struct { |
| 3622 | /// 0. captures_len: u32, // if has_captures_len | 3623 | /// 0. captures_len: u32, // if has_captures_len |
| 3623 | /// 1. decls_len: u32, // if has_decls_len | 3624 | /// 1. decls_len: u32, // if has_decls_len |
| 3624 | /// 2. fields_len: u32, // if has_fields_len | 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 | /// 4. capture: Capture // for every `captures_len` | 3627 | /// 4. capture: Capture // for every `captures_len` |
| 3627 | /// 5. capture_name: NullTerminatedString // for every `captures_len` | 3628 | /// 5. capture_name: NullTerminatedString // for every `captures_len` |
| 3628 | /// 6. decl: Index, // for every `decls_len`; points to a `declaration` instruction | 3629 | /// 6. decl: Index, // for every `decls_len`; points to a `declaration` instruction |
| 3629 | /// 7. field_name: NullTerminatedString // for every `fields_len` | 3630 | /// 7. field_name: NullTerminatedString // for every `fields_len` |
| 3630 | /// 8. field_value_body_len: u32 // for every `fields_len` if `any_field_values` | 3631 | /// 8. field_value_body_len: u32 // for every `fields_len` if `any_field_values` |
| 3631 | /// 9. body_inst: Inst.Index // value body for each 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 | pub const EnumDecl = struct { | 3634 | pub const EnumDecl = struct { |
| 3633 | // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`. | 3635 | // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`. |
| 3634 | // This hash contains the source of all fields, and the backing type if specified. | 3636 | // This hash contains the source of all fields, and the backing type if specified. |
| ... | @@ -3656,7 +3658,7 @@ pub const Inst = struct { | ... | @@ -3656,7 +3658,7 @@ pub const Inst = struct { |
| 3656 | /// 0. captures_len: u32 // if `has_captures_len` | 3658 | /// 0. captures_len: u32 // if `has_captures_len` |
| 3657 | /// 1. decls_len: u32, // if `has_decls_len` | 3659 | /// 1. decls_len: u32, // if `has_decls_len` |
| 3658 | /// 2. fields_len: u32, // if `has_fields_len` | 3660 | /// 2. fields_len: u32, // if `has_fields_len` |
| 3659 | /// 3. arg_type: Ref, // if `kind.hasArgType()` | 3661 | /// 3. arg_type_body_len: u32, // if `kind.hasArgType()` |
| 3660 | /// 4. capture: Capture // for every `captures_len` | 3662 | /// 4. capture: Capture // for every `captures_len` |
| 3661 | /// 5. capture_name: NullTerminatedString // for every `captures_len` | 3663 | /// 5. capture_name: NullTerminatedString // for every `captures_len` |
| 3662 | /// 6. decl: Index, // for every `decls_len`; points to a `declaration` instruction | 3664 | /// 6. decl: Index, // for every `decls_len`; points to a `declaration` instruction |
| ... | @@ -3664,7 +3666,8 @@ pub const Inst = struct { | ... | @@ -3664,7 +3666,8 @@ pub const Inst = struct { |
| 3664 | /// 8. field_type_body_len: u32 // for every `fields_len` | 3666 | /// 8. field_type_body_len: u32 // for every `fields_len` |
| 3665 | /// 9 . field_align_body_len: u32 // for every `fields_len` if `any_field_aligns` | 3667 | /// 9 . field_align_body_len: u32 // for every `fields_len` if `any_field_aligns` |
| 3666 | /// 10. field_value_body_len: u32 // for every `fields_len` if `any_field_values` | 3668 | /// 10. field_value_body_len: u32 // for every `fields_len` if `any_field_values` |
| 3667 | /// 11. body_inst: Inst.Index // type body, then align body, then value body, for each 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 | pub const UnionDecl = struct { | 3671 | pub const UnionDecl = struct { |
| 3669 | // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`. | 3672 | // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`. |
| 3670 | // This hash contains the source of all fields, and any specified attributes (`extern` etc). | 3673 | // This hash contains the source of all fields, and any specified attributes (`extern` etc). |
| ... | @@ -5235,18 +5238,6 @@ pub fn assertTrackable(zir: Zir, inst_idx: Zir.Inst.Index) void { | ... | @@ -5235,18 +5238,6 @@ pub fn assertTrackable(zir: Zir, inst_idx: Zir.Inst.Index) void { |
| 5235 | } | 5238 | } |
| 5236 | } | 5239 | } |
| 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 | pub fn typeDecls(zir: Zir, type_decl: Inst.Index) []const Zir.Inst.Index { | 5241 | pub fn typeDecls(zir: Zir, type_decl: Inst.Index) []const Zir.Inst.Index { |
| 5251 | const inst = zir.instructions.get(@intFromEnum(type_decl)); | 5242 | const inst = zir.instructions.get(@intFromEnum(type_decl)); |
| 5252 | assert(inst.tag == .extended); | 5243 | assert(inst.tag == .extended); |
| ... | @@ -5281,11 +5272,11 @@ pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDe | ... | @@ -5281,11 +5272,11 @@ pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDe |
| 5281 | extra_index += 1; | 5272 | extra_index += 1; |
| 5282 | break :blk fields_len; | 5273 | break :blk fields_len; |
| 5283 | } else 0; | 5274 | } else 0; |
| 5284 | const backing_int_type: Inst.Ref = if (small.has_backing_int_type) ty: { | 5275 | const backing_int_type_body_len: u32 = if (small.has_backing_int_type) len: { |
| 5285 | const ty = zir.extra[extra_index]; | 5276 | const body_len = zir.extra[extra_index]; |
| 5286 | extra_index += 1; | 5277 | extra_index += 1; |
| 5287 | break :ty @enumFromInt(ty); | 5278 | break :len body_len; |
| 5288 | } else .none; | 5279 | } else 0; |
| 5289 | const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]); | 5280 | const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]); |
| 5290 | extra_index += captures_len; | 5281 | extra_index += captures_len; |
| 5291 | const capture_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..captures_len]); | 5282 | const capture_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..captures_len]); |
| ... | @@ -5312,6 +5303,11 @@ pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDe | ... | @@ -5312,6 +5303,11 @@ pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDe |
| 5312 | extra_index += bits_len; | 5303 | extra_index += bits_len; |
| 5313 | break :bits bits; | 5304 | break :bits bits; |
| 5314 | } else null; | 5305 | } else null; |
| 5306 | const backing_int_type_body: ?[]const Zir.Inst.Index = switch (backing_int_type_body_len) { | ||
| 5307 | 0 => null, | ||
| 5308 | else => |n| zir.bodySlice(extra_index, n), | ||
| 5309 | }; | ||
| 5310 | extra_index += backing_int_type_body_len; | ||
| 5315 | const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]); | 5311 | const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]); |
| 5316 | return .{ | 5312 | return .{ |
| 5317 | .src_line = extra.data.src_line, | 5313 | .src_line = extra.data.src_line, |
| ... | @@ -5321,7 +5317,7 @@ pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDe | ... | @@ -5321,7 +5317,7 @@ pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDe |
| 5321 | .capture_names = capture_names, | 5317 | .capture_names = capture_names, |
| 5322 | .decls = decls, | 5318 | .decls = decls, |
| 5323 | .layout = small.layout, | 5319 | .layout = small.layout, |
| 5324 | .backing_int_type = backing_int_type, | 5320 | .backing_int_type_body = backing_int_type_body, |
| 5325 | .field_names = field_names, | 5321 | .field_names = field_names, |
| 5326 | .field_type_body_lens = field_type_body_lens, | 5322 | .field_type_body_lens = field_type_body_lens, |
| 5327 | .field_align_body_lens = field_align_body_lens, | 5323 | .field_align_body_lens = field_align_body_lens, |
| ... | @@ -5341,7 +5337,7 @@ pub const UnwrappedStructDecl = struct { | ... | @@ -5341,7 +5337,7 @@ pub const UnwrappedStructDecl = struct { |
| 5341 | decls: []const Inst.Index, | 5337 | decls: []const Inst.Index, |
| 5342 | 5338 | ||
| 5343 | layout: std.builtin.Type.ContainerLayout, | 5339 | layout: std.builtin.Type.ContainerLayout, |
| 5344 | backing_int_type: Inst.Ref, | 5340 | backing_int_type_body: ?[]const Inst.Index, |
| 5345 | 5341 | ||
| 5346 | field_names: []const NullTerminatedString, | 5342 | field_names: []const NullTerminatedString, |
| 5347 | field_type_body_lens: []const u32, | 5343 | field_type_body_lens: []const u32, |
| ... | @@ -5427,11 +5423,11 @@ pub fn getUnionDecl(zir: *const Zir, union_decl: Inst.Index) UnwrappedUnionDecl | ... | @@ -5427,11 +5423,11 @@ pub fn getUnionDecl(zir: *const Zir, union_decl: Inst.Index) UnwrappedUnionDecl |
| 5427 | extra_index += 1; | 5423 | extra_index += 1; |
| 5428 | break :blk fields_len; | 5424 | break :blk fields_len; |
| 5429 | } else 0; | 5425 | } else 0; |
| 5430 | const arg_type: Inst.Ref = if (small.kind.hasArgType()) ty: { | 5426 | const arg_type_body_len: u32 = if (small.kind.hasArgType()) len: { |
| 5431 | const ty = zir.extra[extra_index]; | 5427 | const body_len = zir.extra[extra_index]; |
| 5432 | extra_index += 1; | 5428 | extra_index += 1; |
| 5433 | break :ty @enumFromInt(ty); | 5429 | break :len body_len; |
| 5434 | } else .none; | 5430 | } else 0; |
| 5435 | const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]); | 5431 | const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]); |
| 5436 | extra_index += captures_len; | 5432 | extra_index += captures_len; |
| 5437 | const capture_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..captures_len]); | 5433 | const capture_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..captures_len]); |
| ... | @@ -5452,6 +5448,11 @@ pub fn getUnionDecl(zir: *const Zir, union_decl: Inst.Index) UnwrappedUnionDecl | ... | @@ -5452,6 +5448,11 @@ pub fn getUnionDecl(zir: *const Zir, union_decl: Inst.Index) UnwrappedUnionDecl |
| 5452 | extra_index += fields_len; | 5448 | extra_index += fields_len; |
| 5453 | break :lens @ptrCast(lens); | 5449 | break :lens @ptrCast(lens); |
| 5454 | } else null; | 5450 | } else null; |
| 5451 | const arg_type_body: ?[]const Zir.Inst.Index = switch (arg_type_body_len) { | ||
| 5452 | 0 => null, | ||
| 5453 | else => |n| zir.bodySlice(extra_index, n), | ||
| 5454 | }; | ||
| 5455 | extra_index += arg_type_body_len; | ||
| 5455 | const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]); | 5456 | const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]); |
| 5456 | return .{ | 5457 | return .{ |
| 5457 | .src_line = extra.data.src_line, | 5458 | .src_line = extra.data.src_line, |
| ... | @@ -5461,7 +5462,7 @@ pub fn getUnionDecl(zir: *const Zir, union_decl: Inst.Index) UnwrappedUnionDecl | ... | @@ -5461,7 +5462,7 @@ pub fn getUnionDecl(zir: *const Zir, union_decl: Inst.Index) UnwrappedUnionDecl |
| 5461 | .capture_names = capture_names, | 5462 | .capture_names = capture_names, |
| 5462 | .decls = decls, | 5463 | .decls = decls, |
| 5463 | .kind = small.kind, | 5464 | .kind = small.kind, |
| 5464 | .arg_type = arg_type, | 5465 | .arg_type_body = arg_type_body, |
| 5465 | .field_names = field_names, | 5466 | .field_names = field_names, |
| 5466 | .field_type_body_lens = field_type_body_lens, | 5467 | .field_type_body_lens = field_type_body_lens, |
| 5467 | .field_align_body_lens = field_align_body_lens, | 5468 | .field_align_body_lens = field_align_body_lens, |
| ... | @@ -5480,7 +5481,7 @@ pub const UnwrappedUnionDecl = struct { | ... | @@ -5480,7 +5481,7 @@ pub const UnwrappedUnionDecl = struct { |
| 5480 | decls: []const Inst.Index, | 5481 | decls: []const Inst.Index, |
| 5481 | 5482 | ||
| 5482 | kind: Inst.UnionDecl.Kind, | 5483 | kind: Inst.UnionDecl.Kind, |
| 5483 | arg_type: Inst.Ref, | 5484 | arg_type_body: ?[]const Inst.Index, |
| 5484 | 5485 | ||
| 5485 | field_names: []const NullTerminatedString, | 5486 | field_names: []const NullTerminatedString, |
| 5486 | field_type_body_lens: []const u32, | 5487 | field_type_body_lens: []const u32, |
| ... | @@ -5556,11 +5557,11 @@ pub fn getEnumDecl(zir: *const Zir, enum_decl: Inst.Index) UnwrappedEnumDecl { | ... | @@ -5556,11 +5557,11 @@ pub fn getEnumDecl(zir: *const Zir, enum_decl: Inst.Index) UnwrappedEnumDecl { |
| 5556 | extra_index += 1; | 5557 | extra_index += 1; |
| 5557 | break :blk fields_len; | 5558 | break :blk fields_len; |
| 5558 | } else 0; | 5559 | } else 0; |
| 5559 | const tag_type: Inst.Ref = if (small.has_tag_type) ty: { | 5560 | const tag_type_body_len: u32 = if (small.has_tag_type) len: { |
| 5560 | const ty = zir.extra[extra_index]; | 5561 | const body_len = zir.extra[extra_index]; |
| 5561 | extra_index += 1; | 5562 | extra_index += 1; |
| 5562 | break :ty @enumFromInt(ty); | 5563 | break :len body_len; |
| 5563 | } else .none; | 5564 | } else 0; |
| 5564 | const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]); | 5565 | const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]); |
| 5565 | extra_index += captures_len; | 5566 | extra_index += captures_len; |
| 5566 | const capture_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..captures_len]); | 5567 | const capture_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..captures_len]); |
| ... | @@ -5574,6 +5575,11 @@ pub fn getEnumDecl(zir: *const Zir, enum_decl: Inst.Index) UnwrappedEnumDecl { | ... | @@ -5574,6 +5575,11 @@ pub fn getEnumDecl(zir: *const Zir, enum_decl: Inst.Index) UnwrappedEnumDecl { |
| 5574 | extra_index += fields_len; | 5575 | extra_index += fields_len; |
| 5575 | break :lens @ptrCast(lens); | 5576 | break :lens @ptrCast(lens); |
| 5576 | } else null; | 5577 | } else null; |
| 5578 | const tag_type_body: ?[]const Zir.Inst.Index = switch (tag_type_body_len) { | ||
| 5579 | 0 => null, | ||
| 5580 | else => |n| zir.bodySlice(extra_index, n), | ||
| 5581 | }; | ||
| 5582 | extra_index += tag_type_body_len; | ||
| 5577 | const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]); | 5583 | const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]); |
| 5578 | return .{ | 5584 | return .{ |
| 5579 | .src_line = extra.data.src_line, | 5585 | .src_line = extra.data.src_line, |
| ... | @@ -5582,7 +5588,7 @@ pub fn getEnumDecl(zir: *const Zir, enum_decl: Inst.Index) UnwrappedEnumDecl { | ... | @@ -5582,7 +5588,7 @@ pub fn getEnumDecl(zir: *const Zir, enum_decl: Inst.Index) UnwrappedEnumDecl { |
| 5582 | .captures = captures, | 5588 | .captures = captures, |
| 5583 | .capture_names = capture_names, | 5589 | .capture_names = capture_names, |
| 5584 | .decls = decls, | 5590 | .decls = decls, |
| 5585 | .tag_type = tag_type, | 5591 | .tag_type_body = tag_type_body, |
| 5586 | .nonexhaustive = small.nonexhaustive, | 5592 | .nonexhaustive = small.nonexhaustive, |
| 5587 | .field_names = field_names, | 5593 | .field_names = field_names, |
| 5588 | .field_value_body_lens = field_value_body_lens, | 5594 | .field_value_body_lens = field_value_body_lens, |
| ... | @@ -5599,7 +5605,7 @@ pub const UnwrappedEnumDecl = struct { | ... | @@ -5599,7 +5605,7 @@ pub const UnwrappedEnumDecl = struct { |
| 5599 | 5605 | ||
| 5600 | decls: []const Inst.Index, | 5606 | decls: []const Inst.Index, |
| 5601 | 5607 | ||
| 5602 | tag_type: Inst.Ref, | 5608 | tag_type_body: ?[]const Inst.Index, |
| 5603 | nonexhaustive: bool, | 5609 | nonexhaustive: bool, |
| 5604 | 5610 | ||
| 5605 | field_names: []const NullTerminatedString, | 5611 | field_names: []const NullTerminatedString, |
src/Compilation.zig+6-6| ... | @@ -3713,7 +3713,7 @@ const Header = extern struct { | ... | @@ -3713,7 +3713,7 @@ const Header = extern struct { |
| 3713 | nav_val_deps_len: u32, | 3713 | nav_val_deps_len: u32, |
| 3714 | nav_ty_deps_len: u32, | 3714 | nav_ty_deps_len: u32, |
| 3715 | type_layout_deps_len: u32, | 3715 | type_layout_deps_len: u32, |
| 3716 | type_inits_deps_len: u32, | 3716 | struct_defaults_deps_len: u32, |
| 3717 | func_ies_deps_len: u32, | 3717 | func_ies_deps_len: u32, |
| 3718 | zon_file_deps_len: u32, | 3718 | zon_file_deps_len: u32, |
| 3719 | embed_file_deps_len: u32, | 3719 | embed_file_deps_len: u32, |
| ... | @@ -3763,7 +3763,7 @@ pub fn saveState(comp: *Compilation) !void { | ... | @@ -3763,7 +3763,7 @@ pub fn saveState(comp: *Compilation) !void { |
| 3763 | .nav_val_deps_len = @intCast(ip.nav_val_deps.count()), | 3763 | .nav_val_deps_len = @intCast(ip.nav_val_deps.count()), |
| 3764 | .nav_ty_deps_len = @intCast(ip.nav_ty_deps.count()), | 3764 | .nav_ty_deps_len = @intCast(ip.nav_ty_deps.count()), |
| 3765 | .type_layout_deps_len = @intCast(ip.type_layout_deps.count()), | 3765 | .type_layout_deps_len = @intCast(ip.type_layout_deps.count()), |
| 3766 | .type_inits_deps_len = @intCast(ip.type_inits_deps.count()), | 3766 | .struct_defaults_deps_len = @intCast(ip.struct_defaults_deps.count()), |
| 3767 | .func_ies_deps_len = @intCast(ip.func_ies_deps.count()), | 3767 | .func_ies_deps_len = @intCast(ip.func_ies_deps.count()), |
| 3768 | .zon_file_deps_len = @intCast(ip.zon_file_deps.count()), | 3768 | .zon_file_deps_len = @intCast(ip.zon_file_deps.count()), |
| 3769 | .embed_file_deps_len = @intCast(ip.embed_file_deps.count()), | 3769 | .embed_file_deps_len = @intCast(ip.embed_file_deps.count()), |
| ... | @@ -3800,8 +3800,8 @@ pub fn saveState(comp: *Compilation) !void { | ... | @@ -3800,8 +3800,8 @@ pub fn saveState(comp: *Compilation) !void { |
| 3800 | addBuf(&bufs, @ptrCast(ip.nav_ty_deps.values())); | 3800 | addBuf(&bufs, @ptrCast(ip.nav_ty_deps.values())); |
| 3801 | addBuf(&bufs, @ptrCast(ip.type_layout_deps.keys())); | 3801 | addBuf(&bufs, @ptrCast(ip.type_layout_deps.keys())); |
| 3802 | addBuf(&bufs, @ptrCast(ip.type_layout_deps.values())); | 3802 | addBuf(&bufs, @ptrCast(ip.type_layout_deps.values())); |
| 3803 | addBuf(&bufs, @ptrCast(ip.type_inits_deps.keys())); | 3803 | addBuf(&bufs, @ptrCast(ip.struct_defaults_deps.keys())); |
| 3804 | addBuf(&bufs, @ptrCast(ip.type_inits_deps.values())); | 3804 | addBuf(&bufs, @ptrCast(ip.struct_defaults_deps.values())); |
| 3805 | addBuf(&bufs, @ptrCast(ip.func_ies_deps.keys())); | 3805 | addBuf(&bufs, @ptrCast(ip.func_ies_deps.keys())); |
| 3806 | addBuf(&bufs, @ptrCast(ip.func_ies_deps.values())); | 3806 | addBuf(&bufs, @ptrCast(ip.func_ies_deps.values())); |
| 3807 | addBuf(&bufs, @ptrCast(ip.zon_file_deps.keys())); | 3807 | addBuf(&bufs, @ptrCast(ip.zon_file_deps.keys())); |
| ... | @@ -4481,7 +4481,7 @@ pub fn addModuleErrorMsg( | ... | @@ -4481,7 +4481,7 @@ pub fn addModuleErrorMsg( |
| 4481 | const root_name: ?[]const u8 = switch (ref.referencer.unwrap()) { | 4481 | const root_name: ?[]const u8 = switch (ref.referencer.unwrap()) { |
| 4482 | .@"comptime" => "comptime", | 4482 | .@"comptime" => "comptime", |
| 4483 | .nav_val, .nav_ty => |nav| ip.getNav(nav).name.toSlice(ip), | 4483 | .nav_val, .nav_ty => |nav| ip.getNav(nav).name.toSlice(ip), |
| 4484 | .type_layout, .type_inits => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip), | 4484 | .type_layout, .struct_defaults => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip), |
| 4485 | .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip), | 4485 | .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip), |
| 4486 | .memoized_state => null, | 4486 | .memoized_state => null, |
| 4487 | }; | 4487 | }; |
| ... | @@ -5251,7 +5251,7 @@ fn processOneJob(tid: Zcu.PerThread.Id, comp: *Compilation, job: Job) JobError!v | ... | @@ -5251,7 +5251,7 @@ fn processOneJob(tid: Zcu.PerThread.Id, comp: *Compilation, job: Job) JobError!v |
| 5251 | .nav_ty => |nav| pt.ensureNavTypeUpToDate(nav), | 5251 | .nav_ty => |nav| pt.ensureNavTypeUpToDate(nav), |
| 5252 | .nav_val => |nav| pt.ensureNavValUpToDate(nav), | 5252 | .nav_val => |nav| pt.ensureNavValUpToDate(nav), |
| 5253 | .type_layout => |ty| pt.ensureTypeLayoutUpToDate(.fromInterned(ty)), | 5253 | .type_layout => |ty| pt.ensureTypeLayoutUpToDate(.fromInterned(ty)), |
| 5254 | .type_inits => |ty| pt.ensureTypeInitsUpToDate(.fromInterned(ty)), | 5254 | .struct_defaults => |ty| pt.ensureStructDefaultsUpToDate(.fromInterned(ty)), |
| 5255 | .memoized_state => |stage| pt.ensureMemoizedStateUpToDate(stage), | 5255 | .memoized_state => |stage| pt.ensureMemoizedStateUpToDate(stage), |
| 5256 | .func => |func| pt.ensureFuncBodyUpToDate(func), | 5256 | .func => |func| pt.ensureFuncBodyUpToDate(func), |
| 5257 | }; | 5257 | }; |
src/IncrementalDebugServer.zig+3-3| ... | @@ -307,7 +307,7 @@ fn handleCommand(zcu: *Zcu, w: *Io.Writer, cmd_str: []const u8, arg_str: []const | ... | @@ -307,7 +307,7 @@ fn handleCommand(zcu: *Zcu, w: *Io.Writer, cmd_str: []const u8, arg_str: []const |
| 307 | switch (dependee) { | 307 | switch (dependee) { |
| 308 | .src_hash, .namespace, .namespace_name, .zon_file, .embed_file => try w.print("{f}", .{zcu.fmtDependee(dependee)}), | 308 | .src_hash, .namespace, .namespace_name, .zon_file, .embed_file => try w.print("{f}", .{zcu.fmtDependee(dependee)}), |
| 309 | .nav_val, .nav_ty => |nav| try w.print("{t} {d}", .{ dependee, @intFromEnum(nav) }), | 309 | .nav_val, .nav_ty => |nav| try w.print("{t} {d}", .{ dependee, @intFromEnum(nav) }), |
| 310 | .type_layout, .type_inits, .func_ies => |ip_index| try w.print("{t} {d}", .{ dependee, @intFromEnum(ip_index) }), | 310 | .type_layout, .struct_defaults, .func_ies => |ip_index| try w.print("{t} {d}", .{ dependee, @intFromEnum(ip_index) }), |
| 311 | .memoized_state => |stage| try w.print("memoized_state {s}", .{@tagName(stage)}), | 311 | .memoized_state => |stage| try w.print("memoized_state {s}", .{@tagName(stage)}), |
| 312 | } | 312 | } |
| 313 | try w.writeByte('\n'); | 313 | try w.writeByte('\n'); |
| ... | @@ -374,8 +374,8 @@ fn parseAnalUnit(str: []const u8) ?AnalUnit { | ... | @@ -374,8 +374,8 @@ fn parseAnalUnit(str: []const u8) ?AnalUnit { |
| 374 | return .wrap(.{ .nav_ty = @enumFromInt(parseIndex(idx_str) orelse return null) }); | 374 | return .wrap(.{ .nav_ty = @enumFromInt(parseIndex(idx_str) orelse return null) }); |
| 375 | } else if (std.mem.eql(u8, kind, "type_layout")) { | 375 | } else if (std.mem.eql(u8, kind, "type_layout")) { |
| 376 | return .wrap(.{ .type_layout = @enumFromInt(parseIndex(idx_str) orelse return null) }); | 376 | return .wrap(.{ .type_layout = @enumFromInt(parseIndex(idx_str) orelse return null) }); |
| 377 | } else if (std.mem.eql(u8, kind, "type_inits")) { | 377 | } else if (std.mem.eql(u8, kind, "struct_defaults")) { |
| 378 | return .wrap(.{ .type_inits = @enumFromInt(parseIndex(idx_str) orelse return null) }); | 378 | return .wrap(.{ .struct_defaults = @enumFromInt(parseIndex(idx_str) orelse return null) }); |
| 379 | } else if (std.mem.eql(u8, kind, "func")) { | 379 | } else if (std.mem.eql(u8, kind, "func")) { |
| 380 | return .wrap(.{ .func = @enumFromInt(parseIndex(idx_str) orelse return null) }); | 380 | return .wrap(.{ .func = @enumFromInt(parseIndex(idx_str) orelse return null) }); |
| 381 | } else if (std.mem.eql(u8, kind, "memoized_state")) { | 381 | } else if (std.mem.eql(u8, kind, "memoized_state")) { |
src/InternPool.zig+865-425| ... | @@ -50,12 +50,12 @@ nav_ty_deps: std.AutoArrayHashMapUnmanaged(Nav.Index, DepEntry.Index), | ... | @@ -50,12 +50,12 @@ nav_ty_deps: std.AutoArrayHashMapUnmanaged(Nav.Index, DepEntry.Index), |
| 50 | /// Dependencies on a function's inferred error set. Key is the function body, not the IES. | 50 | /// Dependencies on a function's inferred error set. Key is the function body, not the IES. |
| 51 | /// Value is index into `dep_entries` of the first dependency on this function's IES. | 51 | /// Value is index into `dep_entries` of the first dependency on this function's IES. |
| 52 | func_ies_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index), | 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 | /// Value is index into `dep_entries` of the first dependency on this type's layout. | 54 | /// Value is index into `dep_entries` of the first dependency on this type's layout. |
| 55 | type_layout_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index), | 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 | /// Value is index into `dep_entries` of the first dependency on this type's inits. | 57 | /// Value is index into `dep_entries` of the first dependency on this type's inits. |
| 58 | type_inits_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index), | 58 | struct_defaults_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index), |
| 59 | /// Dependencies on a ZON file. Triggered by `@import` of ZON. | 59 | /// Dependencies on a ZON file. Triggered by `@import` of ZON. |
| 60 | /// Value is index into `dep_entries` of the first dependency on this ZON file. | 60 | /// Value is index into `dep_entries` of the first dependency on this ZON file. |
| 61 | zon_file_deps: std.AutoArrayHashMapUnmanaged(FileIndex, DepEntry.Index), | 61 | zon_file_deps: std.AutoArrayHashMapUnmanaged(FileIndex, DepEntry.Index), |
| ... | @@ -110,7 +110,7 @@ pub const empty: InternPool = .{ | ... | @@ -110,7 +110,7 @@ pub const empty: InternPool = .{ |
| 110 | .nav_ty_deps = .empty, | 110 | .nav_ty_deps = .empty, |
| 111 | .func_ies_deps = .empty, | 111 | .func_ies_deps = .empty, |
| 112 | .type_layout_deps = .empty, | 112 | .type_layout_deps = .empty, |
| 113 | .type_inits_deps = .empty, | 113 | .struct_defaults_deps = .empty, |
| 114 | .zon_file_deps = .empty, | 114 | .zon_file_deps = .empty, |
| 115 | .embed_file_deps = .empty, | 115 | .embed_file_deps = .empty, |
| 116 | .namespace_deps = .empty, | 116 | .namespace_deps = .empty, |
| ... | @@ -422,7 +422,7 @@ pub const AnalUnit = packed struct(u64) { | ... | @@ -422,7 +422,7 @@ pub const AnalUnit = packed struct(u64) { |
| 422 | nav_val, | 422 | nav_val, |
| 423 | nav_ty, | 423 | nav_ty, |
| 424 | type_layout, | 424 | type_layout, |
| 425 | type_inits, | 425 | struct_defaults, |
| 426 | func, | 426 | func, |
| 427 | memoized_state, | 427 | memoized_state, |
| 428 | }; | 428 | }; |
| ... | @@ -434,11 +434,10 @@ pub const AnalUnit = packed struct(u64) { | ... | @@ -434,11 +434,10 @@ pub const AnalUnit = packed struct(u64) { |
| 434 | nav_val: Nav.Index, | 434 | nav_val: Nav.Index, |
| 435 | /// This `AnalUnit` resolves the type of the given `Nav`. | 435 | /// This `AnalUnit` resolves the type of the given `Nav`. |
| 436 | nav_ty: Nav.Index, | 436 | nav_ty: Nav.Index, |
| 437 | /// This `AnalUnit` resolves the layout of the given `struct` or `union` type. | 437 | /// This `AnalUnit` resolves the layout of the given `struct`, `union`, or `enum` type. |
| 438 | type_layout: InternPool.Index, | 438 | type_layout: InternPool.Index, |
| 439 | /// This `AnalUnit` resolves the field inits of the given `struct` or `enum` type. | 439 | /// This `AnalUnit` resolves the default field values of the given `struct` type. |
| 440 | /// The type may be a union's auto-generated tag enum, if the union has explicit field values. | 440 | struct_defaults: InternPool.Index, |
| 441 | type_inits: InternPool.Index, | ||
| 442 | /// This `AnalUnit` analyzes the body of the given runtime function. | 441 | /// This `AnalUnit` analyzes the body of the given runtime function. |
| 443 | func: InternPool.Index, | 442 | func: InternPool.Index, |
| 444 | /// This `AnalUnit` resolves all state which is memoized in fields on `Zcu`. | 443 | /// This `AnalUnit` resolves all state which is memoized in fields on `Zcu`. |
| ... | @@ -852,7 +851,7 @@ pub const Dependee = union(enum) { | ... | @@ -852,7 +851,7 @@ pub const Dependee = union(enum) { |
| 852 | /// Index is the function, not its IES. | 851 | /// Index is the function, not its IES. |
| 853 | func_ies: Index, | 852 | func_ies: Index, |
| 854 | type_layout: Index, | 853 | type_layout: Index, |
| 855 | type_inits: Index, | 854 | struct_defaults: Index, |
| 856 | zon_file: FileIndex, | 855 | zon_file: FileIndex, |
| 857 | embed_file: Zcu.EmbedFile.Index, | 856 | embed_file: Zcu.EmbedFile.Index, |
| 858 | namespace: TrackedInst.Index, | 857 | namespace: TrackedInst.Index, |
| ... | @@ -906,7 +905,7 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI | ... | @@ -906,7 +905,7 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI |
| 906 | .nav_ty => |x| ip.nav_ty_deps.get(x), | 905 | .nav_ty => |x| ip.nav_ty_deps.get(x), |
| 907 | .func_ies => |x| ip.func_ies_deps.get(x), | 906 | .func_ies => |x| ip.func_ies_deps.get(x), |
| 908 | .type_layout => |x| ip.type_layout_deps.get(x), | 907 | .type_layout => |x| ip.type_layout_deps.get(x), |
| 909 | .type_inits => |x| ip.type_inits_deps.get(x), | 908 | .struct_defaults => |x| ip.struct_defaults_deps.get(x), |
| 910 | .zon_file => |x| ip.zon_file_deps.get(x), | 909 | .zon_file => |x| ip.zon_file_deps.get(x), |
| 911 | .embed_file => |x| ip.embed_file_deps.get(x), | 910 | .embed_file => |x| ip.embed_file_deps.get(x), |
| 912 | .namespace => |x| ip.namespace_deps.get(x), | 911 | .namespace => |x| ip.namespace_deps.get(x), |
| ... | @@ -981,7 +980,7 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend | ... | @@ -981,7 +980,7 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend |
| 981 | .nav_ty => ip.nav_ty_deps, | 980 | .nav_ty => ip.nav_ty_deps, |
| 982 | .func_ies => ip.func_ies_deps, | 981 | .func_ies => ip.func_ies_deps, |
| 983 | .type_layout => ip.type_layout_deps, | 982 | .type_layout => ip.type_layout_deps, |
| 984 | .type_inits => ip.type_inits_deps, | 983 | .struct_defaults => ip.struct_defaults_deps, |
| 985 | .zon_file => ip.zon_file_deps, | 984 | .zon_file => ip.zon_file_deps, |
| 986 | .embed_file => ip.embed_file_deps, | 985 | .embed_file => ip.embed_file_deps, |
| 987 | .namespace => ip.namespace_deps, | 986 | .namespace => ip.namespace_deps, |
| ... | @@ -2248,10 +2247,6 @@ pub const Key = union(enum) { | ... | @@ -2248,10 +2247,6 @@ pub const Key = union(enum) { |
| 2248 | pub const Declared = struct { | 2247 | pub const Declared = struct { |
| 2249 | /// A `struct_decl`, `union_decl`, `enum_decl`, or `opaque_decl` instruction. | 2248 | /// A `struct_decl`, `union_decl`, `enum_decl`, or `opaque_decl` instruction. |
| 2250 | zir_index: TrackedInst.Index, | 2249 | zir_index: TrackedInst.Index, |
| 2251 | /// If the type declaration had an argument type (tag type or packed backing type), this | ||
| 2252 | /// is that type. Otherwise, this is `.none`. It is always `.none` for `opaque` types as | ||
| 2253 | /// `opaque(T)` does not exist. | ||
| 2254 | arg_ty: Index, | ||
| 2255 | /// The captured values of this type. These values must be fully resolved per the language spec. | 2250 | /// The captured values of this type. These values must be fully resolved per the language spec. |
| 2256 | captures: union(enum) { | 2251 | captures: union(enum) { |
| 2257 | owned: CaptureValue.Slice, | 2252 | owned: CaptureValue.Slice, |
| ... | @@ -2745,7 +2740,6 @@ pub const Key = union(enum) { | ... | @@ -2745,7 +2740,6 @@ pub const Key = union(enum) { |
| 2745 | switch (namespace_type) { | 2740 | switch (namespace_type) { |
| 2746 | .declared => |declared| { | 2741 | .declared => |declared| { |
| 2747 | std.hash.autoHash(&hasher, declared.zir_index); | 2742 | std.hash.autoHash(&hasher, declared.zir_index); |
| 2748 | std.hash.autoHash(&hasher, declared.arg_ty); | ||
| 2749 | const captures = switch (declared.captures) { | 2743 | const captures = switch (declared.captures) { |
| 2750 | .owned => |cvs| cvs.get(ip), | 2744 | .owned => |cvs| cvs.get(ip), |
| 2751 | .external => |cvs| cvs, | 2745 | .external => |cvs| cvs, |
| ... | @@ -3155,7 +3149,6 @@ pub const Key = union(enum) { | ... | @@ -3155,7 +3149,6 @@ pub const Key = union(enum) { |
| 3155 | .declared => |a_d| { | 3149 | .declared => |a_d| { |
| 3156 | const b_d = b_info.declared; | 3150 | const b_d = b_info.declared; |
| 3157 | if (a_d.zir_index != b_d.zir_index) return false; | 3151 | if (a_d.zir_index != b_d.zir_index) return false; |
| 3158 | if (a_d.arg_ty != b_d.arg_ty) return false; | ||
| 3159 | const a_captures = switch (a_d.captures) { | 3152 | const a_captures = switch (a_d.captures) { |
| 3160 | .owned => |s| s.get(ip), | 3153 | .owned => |s| s.get(ip), |
| 3161 | .external => |cvs| cvs, | 3154 | .external => |cvs| cvs, |
| ... | @@ -3295,7 +3288,6 @@ pub const Key = union(enum) { | ... | @@ -3295,7 +3288,6 @@ pub const Key = union(enum) { |
| 3295 | .void => .void_type, | 3288 | .void => .void_type, |
| 3296 | .null => .null_type, | 3289 | .null => .null_type, |
| 3297 | .false, .true => .bool_type, | 3290 | .false, .true => .bool_type, |
| 3298 | .empty_tuple => .empty_tuple_type, | ||
| 3299 | .@"unreachable" => .noreturn_type, | 3291 | .@"unreachable" => .noreturn_type, |
| 3300 | }, | 3292 | }, |
| 3301 | 3293 | ||
| ... | @@ -3308,6 +3300,7 @@ pub const LoadedStructType = struct { | ... | @@ -3308,6 +3300,7 @@ pub const LoadedStructType = struct { |
| 3308 | /// Index of the `struct_decl` or `reify` ZIR instruction. | 3300 | /// Index of the `struct_decl` or `reify` ZIR instruction. |
| 3309 | zir_index: TrackedInst.Index, | 3301 | zir_index: TrackedInst.Index, |
| 3310 | captures: CaptureValue.Slice, | 3302 | captures: CaptureValue.Slice, |
| 3303 | is_reified: bool, | ||
| 3311 | 3304 | ||
| 3312 | // TODO: the non-fqn will be needed by the new dwarf structure | 3305 | // TODO: the non-fqn will be needed by the new dwarf structure |
| 3313 | /// The name of this struct type. | 3306 | /// The name of this struct type. |
| ... | @@ -3319,10 +3312,9 @@ pub const LoadedStructType = struct { | ... | @@ -3319,10 +3312,9 @@ pub const LoadedStructType = struct { |
| 3319 | 3312 | ||
| 3320 | layout: std.builtin.Type.ContainerLayout, | 3313 | layout: std.builtin.Type.ContainerLayout, |
| 3321 | /// May be `undefined` if `layout != .@"packed"`. | 3314 | /// May be `undefined` if `layout != .@"packed"`. |
| 3322 | packed_backing_mode: PackedBackingMode, | 3315 | packed_backing_mode: BackingTypeMode, |
| 3323 | /// May be `undefined` if `layout != .@"packed", | ||
| 3324 | packed_backing_int_type: Index, | ||
| 3325 | 3316 | ||
| 3317 | // The remaining fields are only valid once the struct's layout is resolved. | ||
| 3326 | field_name_map: MapIndex, | 3318 | field_name_map: MapIndex, |
| 3327 | field_names: NullTerminatedString.Slice, | 3319 | field_names: NullTerminatedString.Slice, |
| 3328 | field_types: Index.Slice, | 3320 | field_types: Index.Slice, |
| ... | @@ -3331,11 +3323,11 @@ pub const LoadedStructType = struct { | ... | @@ -3331,11 +3323,11 @@ pub const LoadedStructType = struct { |
| 3331 | field_is_comptime_bits: ComptimeBits, | 3323 | field_is_comptime_bits: ComptimeBits, |
| 3332 | field_runtime_order: RuntimeOrder.Slice, | 3324 | field_runtime_order: RuntimeOrder.Slice, |
| 3333 | field_offsets: Offsets, | 3325 | field_offsets: Offsets, |
| 3334 | 3326 | packed_backing_int_type: Index, | |
| 3335 | // These fields are only valid once the layout is resolved, and are never valid for `layout == .@"packed"`. | ||
| 3336 | has_no_possible_value: bool, | 3327 | has_no_possible_value: bool, |
| 3337 | has_one_possible_value: bool, | 3328 | has_one_possible_value: bool, |
| 3338 | comptime_only: bool, | 3329 | comptime_only: bool, |
| 3330 | has_runtime_bits: bool, | ||
| 3339 | size: u32, | 3331 | size: u32, |
| 3340 | alignment: Alignment, | 3332 | alignment: Alignment, |
| 3341 | 3333 | ||
| ... | @@ -3478,6 +3470,7 @@ pub const LoadedUnionType = struct { | ... | @@ -3478,6 +3470,7 @@ pub const LoadedUnionType = struct { |
| 3478 | /// Index of the `union_decl` or `reify` ZIR instruction. | 3470 | /// Index of the `union_decl` or `reify` ZIR instruction. |
| 3479 | zir_index: TrackedInst.Index, | 3471 | zir_index: TrackedInst.Index, |
| 3480 | captures: CaptureValue.Slice, | 3472 | captures: CaptureValue.Slice, |
| 3473 | is_reified: bool, | ||
| 3481 | 3474 | ||
| 3482 | // TODO: the non-fqn will be needed by the new dwarf structure | 3475 | // TODO: the non-fqn will be needed by the new dwarf structure |
| 3483 | /// The name of this union type. | 3476 | /// The name of this union type. |
| ... | @@ -3488,23 +3481,26 @@ pub const LoadedUnionType = struct { | ... | @@ -3488,23 +3481,26 @@ pub const LoadedUnionType = struct { |
| 3488 | namespace: NamespaceIndex, | 3481 | namespace: NamespaceIndex, |
| 3489 | 3482 | ||
| 3490 | layout: std.builtin.Type.ContainerLayout, | 3483 | layout: std.builtin.Type.ContainerLayout, |
| 3491 | runtime_tag: RuntimeTag, | 3484 | enum_tag_mode: BackingTypeMode, |
| 3492 | /// Even if `runtime_tag == .none`, this is populated with the union's "hypothetical" tag type. | ||
| 3493 | enum_tag_type: Index, | ||
| 3494 | /// May be `undefined` if `layout != .@"packed"`. | 3485 | /// May be `undefined` if `layout != .@"packed"`. |
| 3495 | packed_backing_mode: PackedBackingMode, | 3486 | packed_backing_mode: BackingTypeMode, |
| 3496 | /// May be `undefined` if `layout != .@"packed", | 3487 | |
| 3497 | packed_backing_int_type: Index, | 3488 | /// Only reified unions store field names; typically they should be loaded from `enum_tag_type` |
| 3489 | /// instead. Reified unions store them because type resolution needs them in order to validate | ||
| 3490 | /// or populate `enum_tag_type`. | ||
| 3491 | reified_field_names: NullTerminatedString.Slice, | ||
| 3498 | 3492 | ||
| 3499 | // Field names are not stored here, because fields are guaranteed to map one-to-one to the | 3493 | // The remaining fields are only valid once the union's layout is resolved. |
| 3500 | // fields of the enum tag type. If you need field names, load them from `enum_tag_type`. | ||
| 3501 | field_types: Index.Slice, | 3494 | field_types: Index.Slice, |
| 3502 | field_aligns: Alignment.Slice, | 3495 | field_aligns: Alignment.Slice, |
| 3503 | 3496 | runtime_tag: RuntimeTag, | |
| 3504 | // These fields are only valid once the layout is resolved, and are never valid for `layout == .@"packed"`. | 3497 | /// Even if `runtime_tag == .none`, this is populated with the union's "hypothetical" tag type. |
| 3498 | enum_tag_type: Index, | ||
| 3499 | packed_backing_int_type: Index, | ||
| 3505 | has_no_possible_value: bool, | 3500 | has_no_possible_value: bool, |
| 3506 | has_one_possible_value: bool, | 3501 | has_one_possible_value: bool, |
| 3507 | comptime_only: bool, | 3502 | comptime_only: bool, |
| 3503 | has_runtime_bits: bool, | ||
| 3508 | size: u32, | 3504 | size: u32, |
| 3509 | padding: u32, | 3505 | padding: u32, |
| 3510 | alignment: Alignment, | 3506 | alignment: Alignment, |
| ... | @@ -3523,6 +3519,7 @@ pub const LoadedEnumType = struct { | ... | @@ -3523,6 +3519,7 @@ pub const LoadedEnumType = struct { |
| 3523 | captures: CaptureValue.Slice, | 3519 | captures: CaptureValue.Slice, |
| 3524 | /// If `zir_index` is `.none`, this is the union type for which this enum is the tag type. | 3520 | /// If `zir_index` is `.none`, this is the union type for which this enum is the tag type. |
| 3525 | owner_union: Index, | 3521 | owner_union: Index, |
| 3522 | is_reified: bool, | ||
| 3526 | 3523 | ||
| 3527 | // TODO: the non-fqn will be needed by the new dwarf structure | 3524 | // TODO: the non-fqn will be needed by the new dwarf structure |
| 3528 | /// The name of this enum type. | 3525 | /// The name of this enum type. |
| ... | @@ -3532,19 +3529,14 @@ pub const LoadedEnumType = struct { | ... | @@ -3532,19 +3529,14 @@ pub const LoadedEnumType = struct { |
| 3532 | name_nav: Nav.Index.Optional, | 3529 | name_nav: Nav.Index.Optional, |
| 3533 | namespace: NamespaceIndex, | 3530 | namespace: NamespaceIndex, |
| 3534 | 3531 | ||
| 3535 | /// An integer type which is used for the numerical value of the enum. Populated immediately, regardless | 3532 | int_tag_mode: BackingTypeMode, |
| 3536 | /// of whether the integer tag type was explicitly provided or inferred by the compiler. | ||
| 3537 | int_tag_type: Index, | ||
| 3538 | int_tag_is_explicit: bool, | ||
| 3539 | nonexhaustive: bool, | 3533 | nonexhaustive: bool, |
| 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 | field_name_map: MapIndex, | 3537 | field_name_map: MapIndex, |
| 3543 | /// If this is `.none`, the enum tag type is auto-generated and so the fields are auto-numbered. | ||
| 3544 | /// Otherwise, uses `Index.Adapter` with `field_values`. | ||
| 3545 | field_value_map: OptionalMapIndex, | ||
| 3546 | field_names: NullTerminatedString.Slice, | 3538 | field_names: NullTerminatedString.Slice, |
| 3547 | /// Empty if `field_value_map` is `.none`. | 3539 | field_value_map: OptionalMapIndex, |
| 3548 | field_values: Index.Slice, | 3540 | field_values: Index.Slice, |
| 3549 | 3541 | ||
| 3550 | /// Look up field index based on field name. | 3542 | /// Look up field index based on field name. |
| ... | @@ -3596,7 +3588,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { | ... | @@ -3596,7 +3588,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { |
| 3596 | const extra_items = extra_list.view().items(.@"0"); | 3588 | const extra_items = extra_list.view().items(.@"0"); |
| 3597 | const item = unwrapped_index.getItem(ip); | 3589 | const item = unwrapped_index.getItem(ip); |
| 3598 | // Exiting this `switch` means this is a `packed struct`. | 3590 | // Exiting this `switch` means this is a `packed struct`. |
| 3599 | const backing_mode: PackedBackingMode, const any_defaults: bool = switch (item.tag) { | 3591 | const backing_mode: BackingTypeMode, const any_defaults: bool = switch (item.tag) { |
| 3600 | .type_struct_packed_auto => .{ .auto, false }, | 3592 | .type_struct_packed_auto => .{ .auto, false }, |
| 3601 | .type_struct_packed_explicit => .{ .explicit, false }, | 3593 | .type_struct_packed_explicit => .{ .explicit, false }, |
| 3602 | .type_struct_packed_auto_defaults => .{ .auto, true }, | 3594 | .type_struct_packed_auto_defaults => .{ .auto, true }, |
| ... | @@ -3667,6 +3659,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { | ... | @@ -3667,6 +3659,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { |
| 3667 | return .{ | 3659 | return .{ |
| 3668 | .zir_index = extra.data.zir_index, | 3660 | .zir_index = extra.data.zir_index, |
| 3669 | .captures = captures, | 3661 | .captures = captures, |
| 3662 | .is_reified = extra.data.flags.any_captures == .reified, | ||
| 3670 | .name = extra.data.name, | 3663 | .name = extra.data.name, |
| 3671 | .name_nav = extra.data.name_nav, | 3664 | .name_nav = extra.data.name_nav, |
| 3672 | .namespace = extra.data.namespace, | 3665 | .namespace = extra.data.namespace, |
| ... | @@ -3675,7 +3668,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { | ... | @@ -3675,7 +3668,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { |
| 3675 | .@"extern" => .@"extern", | 3668 | .@"extern" => .@"extern", |
| 3676 | }, | 3669 | }, |
| 3677 | .packed_backing_mode = undefined, | 3670 | .packed_backing_mode = undefined, |
| 3678 | .packed_backing_int_type = undefined, | 3671 | |
| 3679 | .field_name_map = extra.data.field_name_map, | 3672 | .field_name_map = extra.data.field_name_map, |
| 3680 | .field_names = field_names, | 3673 | .field_names = field_names, |
| 3681 | .field_types = field_types, | 3674 | .field_types = field_types, |
| ... | @@ -3684,9 +3677,11 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { | ... | @@ -3684,9 +3677,11 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { |
| 3684 | .field_is_comptime_bits = field_is_comptime_bits, | 3677 | .field_is_comptime_bits = field_is_comptime_bits, |
| 3685 | .field_runtime_order = field_runtime_order, | 3678 | .field_runtime_order = field_runtime_order, |
| 3686 | .field_offsets = field_offsets, | 3679 | .field_offsets = field_offsets, |
| 3680 | .packed_backing_int_type = .none, | ||
| 3687 | .has_no_possible_value = extra.data.flags.has_no_possible_value, | 3681 | .has_no_possible_value = extra.data.flags.has_no_possible_value, |
| 3688 | .has_one_possible_value = extra.data.flags.has_one_possible_value, | 3682 | .has_one_possible_value = extra.data.flags.has_one_possible_value, |
| 3689 | .comptime_only = extra.data.flags.comptime_only, | 3683 | .comptime_only = extra.data.flags.comptime_only, |
| 3684 | .has_runtime_bits = extra.data.flags.has_runtime_bits, | ||
| 3690 | .size = extra.data.size, | 3685 | .size = extra.data.size, |
| 3691 | .alignment = extra.data.flags.alignment, | 3686 | .alignment = extra.data.flags.alignment, |
| 3692 | }; | 3687 | }; |
| ... | @@ -3728,12 +3723,13 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { | ... | @@ -3728,12 +3723,13 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { |
| 3728 | return .{ | 3723 | return .{ |
| 3729 | .zir_index = extra.data.zir_index, | 3724 | .zir_index = extra.data.zir_index, |
| 3730 | .captures = captures, | 3725 | .captures = captures, |
| 3726 | .is_reified = extra.data.captures_len == .reified, | ||
| 3731 | .name = extra.data.name, | 3727 | .name = extra.data.name, |
| 3732 | .name_nav = extra.data.name_nav, | 3728 | .name_nav = extra.data.name_nav, |
| 3733 | .namespace = extra.data.namespace, | 3729 | .namespace = extra.data.namespace, |
| 3734 | .layout = .@"packed", | 3730 | .layout = .@"packed", |
| 3735 | .packed_backing_mode = backing_mode, | 3731 | .packed_backing_mode = backing_mode, |
| 3736 | .packed_backing_int_type = extra.data.backing_int_type, | 3732 | |
| 3737 | .field_name_map = extra.data.field_name_map, | 3733 | .field_name_map = extra.data.field_name_map, |
| 3738 | .field_names = field_names, | 3734 | .field_names = field_names, |
| 3739 | .field_types = field_types, | 3735 | .field_types = field_types, |
| ... | @@ -3742,9 +3738,11 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { | ... | @@ -3742,9 +3738,11 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { |
| 3742 | .field_is_comptime_bits = .empty, | 3738 | .field_is_comptime_bits = .empty, |
| 3743 | .field_runtime_order = .empty, | 3739 | .field_runtime_order = .empty, |
| 3744 | .field_offsets = .empty, | 3740 | .field_offsets = .empty, |
| 3741 | .packed_backing_int_type = extra.data.backing_int_type, | ||
| 3745 | .has_no_possible_value = undefined, | 3742 | .has_no_possible_value = undefined, |
| 3746 | .has_one_possible_value = undefined, | 3743 | .has_one_possible_value = undefined, |
| 3747 | .comptime_only = undefined, | 3744 | .comptime_only = undefined, |
| 3745 | .has_runtime_bits = undefined, | ||
| 3748 | .size = undefined, | 3746 | .size = undefined, |
| 3749 | .alignment = undefined, | 3747 | .alignment = undefined, |
| 3750 | }; | 3748 | }; |
| ... | @@ -3756,7 +3754,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { | ... | @@ -3756,7 +3754,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { |
| 3756 | const extra_items = extra_list.view().items(.@"0"); | 3754 | const extra_items = extra_list.view().items(.@"0"); |
| 3757 | const item = unwrapped_index.getItem(ip); | 3755 | const item = unwrapped_index.getItem(ip); |
| 3758 | // Exiting this `switch` means this is a `packed union`. | 3756 | // Exiting this `switch` means this is a `packed union`. |
| 3759 | const backing_mode: PackedBackingMode = switch (item.tag) { | 3757 | const backing_mode: BackingTypeMode = switch (item.tag) { |
| 3760 | .type_union_packed_auto => .auto, | 3758 | .type_union_packed_auto => .auto, |
| 3761 | .type_union_packed_explicit => .explicit, | 3759 | .type_union_packed_explicit => .explicit, |
| 3762 | .type_union => { | 3760 | .type_union => { |
| ... | @@ -3779,6 +3777,12 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { | ... | @@ -3779,6 +3777,12 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { |
| 3779 | }, | 3777 | }, |
| 3780 | }; | 3778 | }; |
| 3781 | extra_index += captures.len; | 3779 | extra_index += captures.len; |
| 3780 | const reified_field_names: NullTerminatedString.Slice = if (extra.data.flags.any_captures == .reified) .{ | ||
| 3781 | .tid = unwrapped_index.tid, | ||
| 3782 | .start = extra_index, | ||
| 3783 | .len = extra.data.fields_len, | ||
| 3784 | } else .empty; | ||
| 3785 | extra_index += reified_field_names.len; | ||
| 3782 | const field_types: Index.Slice = .{ | 3786 | const field_types: Index.Slice = .{ |
| 3783 | .tid = unwrapped_index.tid, | 3787 | .tid = unwrapped_index.tid, |
| 3784 | .start = extra_index, | 3788 | .start = extra_index, |
| ... | @@ -3795,6 +3799,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { | ... | @@ -3795,6 +3799,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { |
| 3795 | return .{ | 3799 | return .{ |
| 3796 | .zir_index = extra.data.zir_index, | 3800 | .zir_index = extra.data.zir_index, |
| 3797 | .captures = captures, | 3801 | .captures = captures, |
| 3802 | .is_reified = extra.data.flags.any_captures == .reified, | ||
| 3798 | .name = extra.data.name, | 3803 | .name = extra.data.name, |
| 3799 | .name_nav = extra.data.name_nav, | 3804 | .name_nav = extra.data.name_nav, |
| 3800 | .namespace = extra.data.namespace, | 3805 | .namespace = extra.data.namespace, |
| ... | @@ -3803,14 +3808,17 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { | ... | @@ -3803,14 +3808,17 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { |
| 3803 | .@"extern" => .@"extern", | 3808 | .@"extern" => .@"extern", |
| 3804 | }, | 3809 | }, |
| 3805 | .runtime_tag = extra.data.flags.runtime_tag, | 3810 | .runtime_tag = extra.data.flags.runtime_tag, |
| 3811 | .enum_tag_mode = extra.data.flags.enum_tag_mode, | ||
| 3806 | .enum_tag_type = extra.data.enum_tag_type, | 3812 | .enum_tag_type = extra.data.enum_tag_type, |
| 3807 | .packed_backing_mode = undefined, | 3813 | .packed_backing_mode = undefined, |
| 3808 | .packed_backing_int_type = undefined, | 3814 | .packed_backing_int_type = undefined, |
| 3815 | .reified_field_names = reified_field_names, | ||
| 3809 | .field_types = field_types, | 3816 | .field_types = field_types, |
| 3810 | .field_aligns = field_aligns, | 3817 | .field_aligns = field_aligns, |
| 3811 | .has_no_possible_value = extra.data.flags.has_no_possible_value, | 3818 | .has_no_possible_value = extra.data.flags.has_no_possible_value, |
| 3812 | .has_one_possible_value = extra.data.flags.has_one_possible_value, | 3819 | .has_one_possible_value = extra.data.flags.has_one_possible_value, |
| 3813 | .comptime_only = extra.data.flags.comptime_only, | 3820 | .comptime_only = extra.data.flags.comptime_only, |
| 3821 | .has_runtime_bits = extra.data.flags.has_runtime_bits, | ||
| 3814 | .size = extra.data.size, | 3822 | .size = extra.data.size, |
| 3815 | .padding = extra.data.padding, | 3823 | .padding = extra.data.padding, |
| 3816 | .alignment = extra.data.flags.alignment, | 3824 | .alignment = extra.data.flags.alignment, |
| ... | @@ -3832,6 +3840,12 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { | ... | @@ -3832,6 +3840,12 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { |
| 3832 | }, | 3840 | }, |
| 3833 | }; | 3841 | }; |
| 3834 | extra_index += captures.len; | 3842 | extra_index += captures.len; |
| 3843 | const reified_field_names: NullTerminatedString.Slice = if (extra.data.captures_len == .reified) .{ | ||
| 3844 | .tid = unwrapped_index.tid, | ||
| 3845 | .start = extra_index, | ||
| 3846 | .len = extra.data.fields_len, | ||
| 3847 | } else .empty; | ||
| 3848 | extra_index += reified_field_names.len; | ||
| 3835 | const field_types: Index.Slice = .{ | 3849 | const field_types: Index.Slice = .{ |
| 3836 | .tid = unwrapped_index.tid, | 3850 | .tid = unwrapped_index.tid, |
| 3837 | .start = extra_index, | 3851 | .start = extra_index, |
| ... | @@ -3841,19 +3855,23 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { | ... | @@ -3841,19 +3855,23 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { |
| 3841 | return .{ | 3855 | return .{ |
| 3842 | .zir_index = extra.data.zir_index, | 3856 | .zir_index = extra.data.zir_index, |
| 3843 | .captures = captures, | 3857 | .captures = captures, |
| 3858 | .is_reified = extra.data.captures_len == .reified, | ||
| 3844 | .name = extra.data.name, | 3859 | .name = extra.data.name, |
| 3845 | .name_nav = extra.data.name_nav, | 3860 | .name_nav = extra.data.name_nav, |
| 3846 | .namespace = extra.data.namespace, | 3861 | .namespace = extra.data.namespace, |
| 3847 | .layout = .@"packed", | 3862 | .layout = .@"packed", |
| 3848 | .runtime_tag = .none, | 3863 | .runtime_tag = .none, |
| 3864 | .enum_tag_mode = .auto, | ||
| 3849 | .enum_tag_type = extra.data.enum_tag_type, | 3865 | .enum_tag_type = extra.data.enum_tag_type, |
| 3850 | .packed_backing_mode = backing_mode, | 3866 | .packed_backing_mode = backing_mode, |
| 3851 | .packed_backing_int_type = extra.data.backing_int_type, | 3867 | .packed_backing_int_type = extra.data.backing_int_type, |
| 3868 | .reified_field_names = reified_field_names, | ||
| 3852 | .field_types = field_types, | 3869 | .field_types = field_types, |
| 3853 | .field_aligns = .empty, | 3870 | .field_aligns = .empty, |
| 3854 | .has_no_possible_value = undefined, | 3871 | .has_no_possible_value = undefined, |
| 3855 | .has_one_possible_value = undefined, | 3872 | .has_one_possible_value = undefined, |
| 3856 | .comptime_only = undefined, | 3873 | .comptime_only = undefined, |
| 3874 | .has_runtime_bits = undefined, | ||
| 3857 | .size = undefined, | 3875 | .size = undefined, |
| 3858 | .padding = undefined, | 3876 | .padding = undefined, |
| 3859 | .alignment = undefined, | 3877 | .alignment = undefined, |
| ... | @@ -3917,12 +3935,13 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType { | ... | @@ -3917,12 +3935,13 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType { |
| 3917 | return .{ | 3935 | return .{ |
| 3918 | .zir_index = zir_index, | 3936 | .zir_index = zir_index, |
| 3919 | .captures = captures, | 3937 | .captures = captures, |
| 3938 | .is_reified = extra.data.captures_len == .reified, | ||
| 3920 | .owner_union = owner_union, | 3939 | .owner_union = owner_union, |
| 3921 | .name = extra.data.name, | 3940 | .name = extra.data.name, |
| 3922 | .name_nav = extra.data.name_nav, | 3941 | .name_nav = extra.data.name_nav, |
| 3923 | .namespace = extra.data.namespace, | 3942 | .namespace = extra.data.namespace, |
| 3924 | .int_tag_type = extra.data.int_tag_type, | 3943 | .int_tag_type = extra.data.int_tag_type, |
| 3925 | .int_tag_is_explicit = explicit_int_tag, | 3944 | .int_tag_mode = if (explicit_int_tag) .explicit else .auto, |
| 3926 | .nonexhaustive = nonexhaustive, | 3945 | .nonexhaustive = nonexhaustive, |
| 3927 | .field_name_map = extra.data.field_name_map, | 3946 | .field_name_map = extra.data.field_name_map, |
| 3928 | .field_value_map = field_value_map, | 3947 | .field_value_map = field_value_map, |
| ... | @@ -4160,7 +4179,7 @@ pub const Index = enum(u32) { | ... | @@ -4160,7 +4179,7 @@ pub const Index = enum(u32) { |
| 4160 | }; | 4179 | }; |
| 4161 | 4180 | ||
| 4162 | /// Used for a map of `Index` values to the index within a list of `Index` values. | 4181 | /// Used for a map of `Index` values to the index within a list of `Index` values. |
| 4163 | pub const Adapter = struct { | 4182 | const Adapter = struct { |
| 4164 | indexes: []const Index, | 4183 | indexes: []const Index, |
| 4165 | 4184 | ||
| 4166 | pub fn eql(ctx: @This(), a: Index, b_void: void, b_map_index: usize) bool { | 4185 | pub fn eql(ctx: @This(), a: Index, b_void: void, b_map_index: usize) bool { |
| ... | @@ -4365,7 +4384,7 @@ pub const Index = enum(u32) { | ... | @@ -4365,7 +4384,7 @@ pub const Index = enum(u32) { |
| 4365 | }) void { | 4384 | }) void { |
| 4366 | _ = self; | 4385 | _ = self; |
| 4367 | const map_fields = @typeInfo(@typeInfo(@TypeOf(tag_to_encoding_map)).pointer.child).@"struct".fields; | 4386 | const map_fields = @typeInfo(@typeInfo(@TypeOf(tag_to_encoding_map)).pointer.child).@"struct".fields; |
| 4368 | @setEvalBranchQuota(2_000); | 4387 | @setEvalBranchQuota(3_000); |
| 4369 | inline for (@typeInfo(Tag).@"enum".fields, 0..) |tag, start| { | 4388 | inline for (@typeInfo(Tag).@"enum".fields, 0..) |tag, start| { |
| 4370 | inline for (0..map_fields.len) |offset| { | 4389 | inline for (0..map_fields.len) |offset| { |
| 4371 | if (comptime std.mem.eql(u8, tag.name, map_fields[(start + offset) % map_fields.len].name)) break; | 4390 | if (comptime std.mem.eql(u8, tag.name, map_fields[(start + offset) % map_fields.len].name)) break; |
| ... | @@ -4797,7 +4816,11 @@ pub const static_keys: [static_len]Key = .{ | ... | @@ -4797,7 +4816,11 @@ pub const static_keys: [static_len]Key = .{ |
| 4797 | .{ .simple_value = .null }, | 4816 | .{ .simple_value = .null }, |
| 4798 | .{ .simple_value = .true }, | 4817 | .{ .simple_value = .true }, |
| 4799 | .{ .simple_value = .false }, | 4818 | .{ .simple_value = .false }, |
| 4800 | .{ .simple_value = .empty_tuple }, | 4819 | |
| 4820 | .{ .aggregate = .{ | ||
| 4821 | .ty = .empty_tuple_type, | ||
| 4822 | .storage = .{ .elems = &.{} }, | ||
| 4823 | } }, | ||
| 4801 | }; | 4824 | }; |
| 4802 | 4825 | ||
| 4803 | /// How many items in the InternPool are statically known. | 4826 | /// How many items in the InternPool are statically known. |
| ... | @@ -5601,10 +5624,12 @@ pub const Tag = enum(u8) { | ... | @@ -5601,10 +5624,12 @@ pub const Tag = enum(u8) { |
| 5601 | has_no_possible_value: bool, | 5624 | has_no_possible_value: bool, |
| 5602 | /// Whether the struct is comptime-only. Always `false` until layout resolved. | 5625 | /// Whether the struct is comptime-only. Always `false` until layout resolved. |
| 5603 | comptime_only: bool, | 5626 | comptime_only: bool, |
| 5627 | /// Whether the struct has runtime bits. Always `false` until layout resolved. | ||
| 5628 | has_runtime_bits: bool, | ||
| 5604 | /// Alignment of the whole struct. Always `.none` until layout resolved. | 5629 | /// Alignment of the whole struct. Always `.none` until layout resolved. |
| 5605 | alignment: Alignment, | 5630 | alignment: Alignment, |
| 5606 | 5631 | ||
| 5607 | _: u17 = 0, | 5632 | _: u16 = 0, |
| 5608 | }; | 5633 | }; |
| 5609 | }; | 5634 | }; |
| 5610 | 5635 | ||
| ... | @@ -5625,21 +5650,25 @@ pub const Tag = enum(u8) { | ... | @@ -5625,21 +5650,25 @@ pub const Tag = enum(u8) { |
| 5625 | name_nav: Nav.Index.Optional, | 5650 | name_nav: Nav.Index.Optional, |
| 5626 | namespace: NamespaceIndex, | 5651 | namespace: NamespaceIndex, |
| 5627 | 5652 | ||
| 5628 | /// The corresponding `PackedBackingMode` depends on the item's `Tag`. | 5653 | /// The corresponding `BackingTypeMode` depends on the item's `Tag`. |
| 5629 | backing_int_type: Index, | 5654 | backing_int_type: Index, |
| 5630 | 5655 | ||
| 5631 | fields_len: u32, | 5656 | fields_len: u32, |
| 5632 | field_name_map: MapIndex, | 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 | /// Trailing: | 5665 | /// Trailing: |
| 5638 | /// 0. type_hash: PackedU64 // if `any_captures == .reified` | 5666 | /// 0. type_hash: PackedU64 // if `any_captures == .reified` |
| 5639 | /// 1. captures_len: u32 // if `any_captures == .true` | 5667 | /// 1. captures_len: u32 // if `any_captures == .true` |
| 5640 | /// 2. capture: CaptureValue // if `any_captures == .true`; for each `captures_len` | 5668 | /// 2. capture: CaptureValue // if `any_captures == .true`; for each `captures_len` |
| 5641 | /// 3. field_type: Index // for each `fields_len` | 5669 | /// 3. reified_field_name: NullTerminatedString // if `any_captures == .reified`; for each `fields_len` |
| 5642 | /// 4. field_align: Alignment // for each `fields_len` if `any_field_aligns` | 5670 | /// 4. field_type: Index // for each `fields_len` |
| 5671 | /// 5. field_align: Alignment // for each `fields_len` if `any_field_aligns` | ||
| 5643 | pub const TypeUnion = struct { | 5672 | pub const TypeUnion = struct { |
| 5644 | zir_index: TrackedInst.Index, | 5673 | zir_index: TrackedInst.Index, |
| 5645 | 5674 | ||
| ... | @@ -5652,7 +5681,6 @@ pub const Tag = enum(u8) { | ... | @@ -5652,7 +5681,6 @@ pub const Tag = enum(u8) { |
| 5652 | /// This could be provided through the tag type, but it is more convenient | 5681 | /// This could be provided through the tag type, but it is more convenient |
| 5653 | /// to store it directly. This is also necessary for `dumpStatsFallible` to | 5682 | /// to store it directly. This is also necessary for `dumpStatsFallible` to |
| 5654 | /// work on unresolved types. | 5683 | /// work on unresolved types. |
| 5655 | /// MLUGG TODO: reconsider, because we resolve the tag type eagerly now. | ||
| 5656 | fields_len: u32, | 5684 | fields_len: u32, |
| 5657 | 5685 | ||
| 5658 | /// Always 0 until layout resolved. | 5686 | /// Always 0 until layout resolved. |
| ... | @@ -5669,7 +5697,7 @@ pub const Tag = enum(u8) { | ... | @@ -5669,7 +5697,7 @@ pub const Tag = enum(u8) { |
| 5669 | /// | 5697 | /// |
| 5670 | /// For `union(enum(E))` syntax, this is `false`, but the generated enum tag type is | 5698 | /// For `union(enum(E))` syntax, this is `false`, but the generated enum tag type is |
| 5671 | /// considered to have an explicitly specified integer tag type. | 5699 | /// considered to have an explicitly specified integer tag type. |
| 5672 | explicit_tag_type: bool, | 5700 | enum_tag_mode: BackingTypeMode, |
| 5673 | 5701 | ||
| 5674 | /// `packed` layout is represented separately by `TypeStructPacked`. | 5702 | /// `packed` layout is represented separately by `TypeStructPacked`. |
| 5675 | layout: enum(u1) { auto, @"extern" }, | 5703 | layout: enum(u1) { auto, @"extern" }, |
| ... | @@ -5685,19 +5713,25 @@ pub const Tag = enum(u8) { | ... | @@ -5685,19 +5713,25 @@ pub const Tag = enum(u8) { |
| 5685 | has_no_possible_value: bool, | 5713 | has_no_possible_value: bool, |
| 5686 | /// Whether the union is comptime-only. Always `false` until layout resolved. | 5714 | /// Whether the union is comptime-only. Always `false` until layout resolved. |
| 5687 | comptime_only: bool, | 5715 | comptime_only: bool, |
| 5716 | /// Whether the union has runtime bits. Always `false` until layout resolved. | ||
| 5717 | has_runtime_bits: bool, | ||
| 5688 | /// Alignment of the whole union. Always `.none` until layout resolved. | 5718 | /// Alignment of the whole union. Always `.none` until layout resolved. |
| 5689 | alignment: Alignment, | 5719 | alignment: Alignment, |
| 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 | /// Trailing: | 5730 | /// Trailing: |
| 5698 | /// 0. type_hash: PackedU64 // if `captures_len == .reified` | 5731 | /// 0. type_hash: PackedU64 // if `captures_len == .reified` |
| 5699 | /// 1. capture: CaptureValue // if `captures_len != .reified`; for each `captures_len` | 5732 | /// 1. capture: CaptureValue // if `captures_len != .reified`; for each `captures_len` |
| 5700 | /// 2. field_type: Index // for each `fields_len` | 5733 | /// 2. reified_field_name: NullTerminatedString // if `captures_len == .reified`; for each `fields_len` |
| 5734 | /// 3. field_type: Index // for each `fields_len` | ||
| 5701 | pub const TypeUnionPacked = struct { | 5735 | pub const TypeUnionPacked = struct { |
| 5702 | zir_index: TrackedInst.Index, | 5736 | zir_index: TrackedInst.Index, |
| 5703 | captures_len: enum(u32) { | 5737 | captures_len: enum(u32) { |
| ... | @@ -5709,7 +5743,7 @@ pub const Tag = enum(u8) { | ... | @@ -5709,7 +5743,7 @@ pub const Tag = enum(u8) { |
| 5709 | name_nav: Nav.Index.Optional, | 5743 | name_nav: Nav.Index.Optional, |
| 5710 | namespace: NamespaceIndex, | 5744 | namespace: NamespaceIndex, |
| 5711 | 5745 | ||
| 5712 | /// The corresponding `PackedBackingMode` depends on the item's `Tag`. | 5746 | /// The corresponding `BackingTypeMode` depends on the item's `Tag`. |
| 5713 | backing_int_type: Index, | 5747 | backing_int_type: Index, |
| 5714 | /// Although packed unions do not semantically have a tag type, the compiler still assigns | 5748 | /// Although packed unions do not semantically have a tag type, the compiler still assigns |
| 5715 | /// them a "hypothetical" tag type. | 5749 | /// them a "hypothetical" tag type. |
| ... | @@ -5718,7 +5752,6 @@ pub const Tag = enum(u8) { | ... | @@ -5718,7 +5752,6 @@ pub const Tag = enum(u8) { |
| 5718 | /// This could be provided through the tag type, but it is more convenient | 5752 | /// This could be provided through the tag type, but it is more convenient |
| 5719 | /// to store it directly. This is also necessary for `dumpStatsFallible` to | 5753 | /// to store it directly. This is also necessary for `dumpStatsFallible` to |
| 5720 | /// work on unresolved types. | 5754 | /// work on unresolved types. |
| 5721 | /// MLUGG TODO: reconsider, because we resolve the tag type eagerly now. | ||
| 5722 | fields_len: u32, | 5755 | fields_len: u32, |
| 5723 | }; | 5756 | }; |
| 5724 | 5757 | ||
| ... | @@ -5742,8 +5775,7 @@ pub const Tag = enum(u8) { | ... | @@ -5742,8 +5775,7 @@ pub const Tag = enum(u8) { |
| 5742 | namespace: NamespaceIndex, | 5775 | namespace: NamespaceIndex, |
| 5743 | 5776 | ||
| 5744 | /// An integer type which is used for the numerical value of the enum. Whether this was | 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 | 5778 | /// user-provided or inferred by the compiler depends on the tag. |
| 5746 | /// is populated immediately (i.e. does not require any type resolution). | ||
| 5747 | int_tag_type: Index, | 5779 | int_tag_type: Index, |
| 5748 | 5780 | ||
| 5749 | fields_len: u32, | 5781 | fields_len: u32, |
| ... | @@ -5762,13 +5794,17 @@ pub const Tag = enum(u8) { | ... | @@ -5762,13 +5794,17 @@ pub const Tag = enum(u8) { |
| 5762 | }; | 5794 | }; |
| 5763 | }; | 5795 | }; |
| 5764 | 5796 | ||
| 5765 | /// Differentiates between user-provided and compiler-generated backing types for packed aggregates. | 5797 | /// Differentiates between user-provided and compiler-generated backing types for packed and tagged types. |
| 5766 | pub const PackedBackingMode = enum(u1) { | 5798 | pub const BackingTypeMode = enum(u1) { |
| 5767 | /// The backing type was explicitly provided by the user, i.e. `packed struct(T)` or `packed union(T)`. | 5799 | /// The backing type was explicitly provided by the user. For instance: |
| 5768 | /// Type resolution simply *validates* that type. | 5800 | /// union(T) |
| 5801 | /// enum(T) | ||
| 5802 | /// packed struct(T) | ||
| 5803 | /// packed union(T) | ||
| 5804 | /// Type layout resolution will evaluate the user-provided expression and validate that type. | ||
| 5769 | explicit, | 5805 | explicit, |
| 5770 | /// No backing type was explicitly provided by the user. Type layout resolution will populate the | 5806 | /// No backing type was explicitly provided by the user. Type layout resolution will populate |
| 5771 | /// backing type based on the field types; before then it is invalid (probably `.none`). | 5807 | /// an inferred/generated type. |
| 5772 | auto, | 5808 | auto, |
| 5773 | }; | 5809 | }; |
| 5774 | 5810 | ||
| ... | @@ -5852,8 +5888,6 @@ pub const SimpleValue = enum(u32) { | ... | @@ -5852,8 +5888,6 @@ pub const SimpleValue = enum(u32) { |
| 5852 | void = @intFromEnum(Index.void_value), | 5888 | void = @intFromEnum(Index.void_value), |
| 5853 | /// This is untyped `null`. | 5889 | /// This is untyped `null`. |
| 5854 | null = @intFromEnum(Index.null_value), | 5890 | null = @intFromEnum(Index.null_value), |
| 5855 | /// This is the untyped empty struct/array literal: `.{}` | ||
| 5856 | empty_tuple = @intFromEnum(Index.empty_tuple), | ||
| 5857 | true = @intFromEnum(Index.bool_true), | 5891 | true = @intFromEnum(Index.bool_true), |
| 5858 | false = @intFromEnum(Index.bool_false), | 5892 | false = @intFromEnum(Index.bool_false), |
| 5859 | @"unreachable" = @intFromEnum(Index.unreachable_value), | 5893 | @"unreachable" = @intFromEnum(Index.unreachable_value), |
| ... | @@ -6395,7 +6429,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator, io: Io) void { | ... | @@ -6395,7 +6429,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator, io: Io) void { |
| 6395 | ip.nav_ty_deps.deinit(gpa); | 6429 | ip.nav_ty_deps.deinit(gpa); |
| 6396 | ip.func_ies_deps.deinit(gpa); | 6430 | ip.func_ies_deps.deinit(gpa); |
| 6397 | ip.type_layout_deps.deinit(gpa); | 6431 | ip.type_layout_deps.deinit(gpa); |
| 6398 | ip.type_inits_deps.deinit(gpa); | 6432 | ip.struct_defaults_deps.deinit(gpa); |
| 6399 | ip.zon_file_deps.deinit(gpa); | 6433 | ip.zon_file_deps.deinit(gpa); |
| 6400 | ip.embed_file_deps.deinit(gpa); | 6434 | ip.embed_file_deps.deinit(gpa); |
| 6401 | ip.namespace_deps.deinit(gpa); | 6435 | ip.namespace_deps.deinit(gpa); |
| ... | @@ -6544,12 +6578,10 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { | ... | @@ -6544,12 +6578,10 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 6544 | } }, | 6578 | } }, |
| 6545 | .false => .{ .declared = .{ | 6579 | .false => .{ .declared = .{ |
| 6546 | .zir_index = extra.data.zir_index, | 6580 | .zir_index = extra.data.zir_index, |
| 6547 | .arg_ty = .none, | ||
| 6548 | .captures = .{ .owned = .empty }, | 6581 | .captures = .{ .owned = .empty }, |
| 6549 | } }, | 6582 | } }, |
| 6550 | .true => .{ .declared = .{ | 6583 | .true => .{ .declared = .{ |
| 6551 | .zir_index = extra.data.zir_index, | 6584 | .zir_index = extra.data.zir_index, |
| 6552 | .arg_ty = .none, | ||
| 6553 | .captures = .{ .owned = .{ | 6585 | .captures = .{ .owned = .{ |
| 6554 | .tid = unwrapped_index.tid, | 6586 | .tid = unwrapped_index.tid, |
| 6555 | .start = extra.end + 1, | 6587 | .start = extra.end + 1, |
| ... | @@ -6572,11 +6604,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { | ... | @@ -6572,11 +6604,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 6572 | } }, | 6604 | } }, |
| 6573 | _ => .{ .declared = .{ | 6605 | _ => .{ .declared = .{ |
| 6574 | .zir_index = extra.data.zir_index, | 6606 | .zir_index = extra.data.zir_index, |
| 6575 | .arg_ty = switch (item.tag) { | ||
| 6576 | .type_struct_packed_auto, .type_struct_packed_auto_defaults => .none, | ||
| 6577 | .type_struct_packed_explicit, .type_struct_packed_explicit_defaults => extra.data.backing_int_type, | ||
| 6578 | else => unreachable, | ||
| 6579 | }, | ||
| 6580 | .captures = .{ .owned = .{ | 6607 | .captures = .{ .owned = .{ |
| 6581 | .tid = unwrapped_index.tid, | 6608 | .tid = unwrapped_index.tid, |
| 6582 | .start = extra.end, | 6609 | .start = extra.end, |
| ... | @@ -6595,12 +6622,10 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { | ... | @@ -6595,12 +6622,10 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 6595 | } }, | 6622 | } }, |
| 6596 | .false => .{ .declared = .{ | 6623 | .false => .{ .declared = .{ |
| 6597 | .zir_index = extra.data.zir_index, | 6624 | .zir_index = extra.data.zir_index, |
| 6598 | .arg_ty = if (extra.data.flags.explicit_tag_type) extra.data.enum_tag_type else .none, | ||
| 6599 | .captures = .{ .owned = .empty }, | 6625 | .captures = .{ .owned = .empty }, |
| 6600 | } }, | 6626 | } }, |
| 6601 | .true => .{ .declared = .{ | 6627 | .true => .{ .declared = .{ |
| 6602 | .zir_index = extra.data.zir_index, | 6628 | .zir_index = extra.data.zir_index, |
| 6603 | .arg_ty = if (extra.data.flags.explicit_tag_type) extra.data.enum_tag_type else .none, | ||
| 6604 | .captures = .{ .owned = .{ | 6629 | .captures = .{ .owned = .{ |
| 6605 | .tid = unwrapped_index.tid, | 6630 | .tid = unwrapped_index.tid, |
| 6606 | .start = extra.end + 1, | 6631 | .start = extra.end + 1, |
| ... | @@ -6619,11 +6644,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { | ... | @@ -6619,11 +6644,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 6619 | } }, | 6644 | } }, |
| 6620 | _ => .{ .declared = .{ | 6645 | _ => .{ .declared = .{ |
| 6621 | .zir_index = extra.data.zir_index, | 6646 | .zir_index = extra.data.zir_index, |
| 6622 | .arg_ty = switch (item.tag) { | ||
| 6623 | .type_union_packed_auto => .none, | ||
| 6624 | .type_union_packed_explicit => extra.data.backing_int_type, | ||
| 6625 | else => unreachable, | ||
| 6626 | }, | ||
| 6627 | .captures = .{ .owned = .{ | 6647 | .captures = .{ .owned = .{ |
| 6628 | .tid = unwrapped_index.tid, | 6648 | .tid = unwrapped_index.tid, |
| 6629 | .start = extra.end, | 6649 | .start = extra.end, |
| ... | @@ -6645,11 +6665,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { | ... | @@ -6645,11 +6665,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 6645 | } }, | 6665 | } }, |
| 6646 | _ => .{ .declared = .{ | 6666 | _ => .{ .declared = .{ |
| 6647 | .zir_index = @enumFromInt(extra_list.view().items(.@"0")[extra.end]), | 6667 | .zir_index = @enumFromInt(extra_list.view().items(.@"0")[extra.end]), |
| 6648 | .arg_ty = switch (item.tag) { | ||
| 6649 | .type_enum_auto => .none, | ||
| 6650 | .type_enum_explicit, .type_enum_nonexhaustive => extra.data.int_tag_type, | ||
| 6651 | else => unreachable, | ||
| 6652 | }, | ||
| 6653 | .captures = .{ .owned = .{ | 6668 | .captures = .{ .owned = .{ |
| 6654 | .tid = unwrapped_index.tid, | 6669 | .tid = unwrapped_index.tid, |
| 6655 | .start = extra.end + 1, | 6670 | .start = extra.end + 1, |
| ... | @@ -6662,7 +6677,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { | ... | @@ -6662,7 +6677,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 6662 | const extra = extraDataTrail(unwrapped_index.getExtra(ip), Tag.TypeOpaque, data); | 6677 | const extra = extraDataTrail(unwrapped_index.getExtra(ip), Tag.TypeOpaque, data); |
| 6663 | break :ns .{ .declared = .{ | 6678 | break :ns .{ .declared = .{ |
| 6664 | .zir_index = extra.data.zir_index, | 6679 | .zir_index = extra.data.zir_index, |
| 6665 | .arg_ty = .none, | ||
| 6666 | .captures = .{ .owned = .{ | 6680 | .captures = .{ .owned = .{ |
| 6667 | .tid = unwrapped_index.tid, | 6681 | .tid = unwrapped_index.tid, |
| 6668 | .start = extra.end, | 6682 | .start = extra.end, |
| ... | @@ -6883,7 +6897,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { | ... | @@ -6883,7 +6897,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 6883 | }, | 6897 | }, |
| 6884 | .type_array_small, | 6898 | .type_array_small, |
| 6885 | .type_vector, | 6899 | .type_vector, |
| 6886 | // MLUGG TODO: is this still possible? also, i hate .only_possible_value, it should die in a fire. | ||
| 6887 | .type_struct_packed_auto, | 6900 | .type_struct_packed_auto, |
| 6888 | .type_struct_packed_explicit, | 6901 | .type_struct_packed_explicit, |
| 6889 | => .{ .aggregate = .{ | 6902 | => .{ .aggregate = .{ |
| ... | @@ -6894,7 +6907,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { | ... | @@ -6894,7 +6907,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 6894 | // There is only one possible value precisely due to the | 6907 | // There is only one possible value precisely due to the |
| 6895 | // fact that this values slice is fully populated! | 6908 | // fact that this values slice is fully populated! |
| 6896 | .type_struct, | 6909 | .type_struct, |
| 6897 | // MLUGG TODO: is this still possible? also, i hate .only_possible_value, it should die in a fire. | ||
| 6898 | .type_struct_packed_auto_defaults, | 6910 | .type_struct_packed_auto_defaults, |
| 6899 | .type_struct_packed_explicit_defaults, | 6911 | .type_struct_packed_explicit_defaults, |
| 6900 | => { | 6912 | => { |
| ... | @@ -7445,12 +7457,12 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key: | ... | @@ -7445,12 +7457,12 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key: |
| 7445 | }); | 7457 | }); |
| 7446 | }, | 7458 | }, |
| 7447 | 7459 | ||
| 7448 | .struct_type => unreachable, // use getStructType() instead | 7460 | .struct_type => unreachable, // instead use: getDeclaredStructType, getReifiedStructType |
| 7449 | .tuple_type => unreachable, // use getTupleType() instead | 7461 | .union_type => unreachable, // instead use: getDeclaredUnionType, getReifiedUnionType |
| 7450 | .union_type => unreachable, // use getUnionType() instead | 7462 | .enum_type => unreachable, // instead use: getDeclaredEnumType, getReifiedEnumType, getGeneratedEnumTagType |
| 7451 | .opaque_type => unreachable, // use getOpaqueType() instead | 7463 | .opaque_type => unreachable, // instead use: getDeclaredOpaqueType |
| 7452 | 7464 | ||
| 7453 | .enum_type => unreachable, // use getEnumType() instead | 7465 | .tuple_type => unreachable, // use getTupleType() instead |
| 7454 | .func_type => unreachable, // use getFuncType() instead | 7466 | .func_type => unreachable, // use getFuncType() instead |
| 7455 | .@"extern" => unreachable, // use getExtern() instead | 7467 | .@"extern" => unreachable, // use getExtern() instead |
| 7456 | .func => unreachable, // use getFuncInstance() or getFuncDecl() instead | 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,43 +8084,180 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key: |
| 8072 | return gop.put(); | 8084 | return gop.put(); |
| 8073 | } | 8085 | } |
| 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 | fields_len: u32, | 8249 | fields_len: u32, |
| 8077 | layout: std.builtin.Type.ContainerLayout, | 8250 | layout: std.builtin.Type.ContainerLayout, |
| 8078 | /// The following only applies if `layout == .@"packed"`; this field is ignored otherwise. | ||
| 8079 | /// | ||
| 8080 | /// The explicitly specified backing integer type. `.none` means the backing integer is inferred | ||
| 8081 | /// by the compiler. Asserts that this is an integer type. | ||
| 8082 | explicit_packed_backing_type: Index, | ||
| 8083 | any_comptime_fields: bool, | 8251 | any_comptime_fields: bool, |
| 8084 | any_field_defaults: bool, | 8252 | any_field_defaults: bool, |
| 8085 | any_field_aligns: bool, | 8253 | any_field_aligns: bool, |
| 8086 | key: union(enum) { | 8254 | /// Explicitly specified backing int type. `.none` if not packed or if backing type is inferred. |
| 8087 | declared: struct { | 8255 | packed_backing_int_type: Index, |
| 8088 | zir_index: TrackedInst.Index, | ||
| 8089 | captures: []const CaptureValue, | ||
| 8090 | }, | ||
| 8091 | reified: struct { | ||
| 8092 | zir_index: TrackedInst.Index, | ||
| 8093 | type_hash: u64, | ||
| 8094 | }, | ||
| 8095 | }, | ||
| 8096 | }) Allocator.Error!WipContainerType.Result { | 8256 | }) Allocator.Error!WipContainerType.Result { |
| 8097 | const key: Key = .{ .struct_type = switch (ini.key) { | 8257 | var gop = try ip.getOrPutKey(gpa, io, tid, .{ .struct_type = .{ .reified = .{ |
| 8098 | .declared => |d| .{ .declared = .{ | 8258 | .zir_index = ini.zir_index, |
| 8099 | .zir_index = d.zir_index, | 8259 | .type_hash = ini.type_hash, |
| 8100 | .arg_ty = switch (ini.layout) { | 8260 | } } }); |
| 8101 | .auto, .@"extern" => .none, | ||
| 8102 | .@"packed" => ini.explicit_packed_backing_type, | ||
| 8103 | }, | ||
| 8104 | .captures = .{ .external = d.captures }, | ||
| 8105 | } }, | ||
| 8106 | .reified => |r| .{ .reified = .{ | ||
| 8107 | .zir_index = r.zir_index, | ||
| 8108 | .type_hash = r.type_hash, | ||
| 8109 | } }, | ||
| 8110 | } }; | ||
| 8111 | var gop = try ip.getOrPutKey(gpa, io, tid, key); | ||
| 8112 | defer gop.deinit(); | 8261 | defer gop.deinit(); |
| 8113 | if (gop == .existing) return .{ .existing = gop.existing }; | 8262 | if (gop == .existing) return .{ .existing = gop.existing }; |
| 8114 | 8263 | ||
| ... | @@ -8120,46 +8269,37 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread | ... | @@ -8120,46 +8269,37 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread |
| 8120 | const field_name_map = try ip.addMap(gpa, io, tid, ini.fields_len); | 8269 | const field_name_map = try ip.addMap(gpa, io, tid, ini.fields_len); |
| 8121 | errdefer local.mutate.maps.len -= 1; | 8270 | errdefer local.mutate.maps.len -= 1; |
| 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 | const is_extern = switch (ini.layout) { | 8272 | const is_extern = switch (ini.layout) { |
| 8129 | .auto => false, | 8273 | .auto => false, |
| 8130 | .@"extern" => true, | 8274 | .@"extern" => true, |
| 8131 | .@"packed" => { | 8275 | .@"packed" => { |
| 8132 | try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStructPacked).@"struct".fields.len + | 8276 | try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStructPacked).@"struct".fields.len + |
| 8133 | type_hash_captures_extra_len + | 8277 | 2 + // type_hash |
| 8134 | ini.fields_len + // field_name | 8278 | ini.fields_len + // field_name |
| 8135 | ini.fields_len + // field_type | 8279 | ini.fields_len + // field_type |
| 8136 | (if (ini.any_field_defaults) ini.fields_len else 0)); // field_default | 8280 | (if (ini.any_field_defaults) ini.fields_len else 0)); // field_default |
| 8137 | 8281 | ||
| 8138 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStructPacked{ | 8282 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStructPacked{ |
| 8139 | .zir_index = zir_index, | 8283 | .zir_index = ini.zir_index, |
| 8140 | .captures_len = switch (ini.key) { | 8284 | .captures_len = .reified, |
| 8141 | .declared => |d| @enumFromInt(d.captures.len), | ||
| 8142 | .reified => .reified, | ||
| 8143 | }, | ||
| 8144 | .name = undefined, // set by `finish` | 8285 | .name = undefined, // set by `finish` |
| 8145 | .name_nav = undefined, // set by `finish` | 8286 | .name_nav = undefined, // set by `finish` |
| 8146 | .namespace = undefined, // set by `finish` | 8287 | .namespace = undefined, // set by `finish` |
| 8147 | .backing_int_type = ini.explicit_packed_backing_type, | 8288 | .backing_int_type = ini.packed_backing_int_type, |
| 8148 | .fields_len = ini.fields_len, | 8289 | .fields_len = ini.fields_len, |
| 8149 | .field_name_map = field_name_map, | 8290 | .field_name_map = field_name_map, |
| 8150 | }); | 8291 | }); |
| 8151 | switch (ini.key) { | 8292 | _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); // type_hash |
| 8152 | .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}), | ||
| 8153 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), | ||
| 8154 | } | ||
| 8155 | const field_names_start = extra.mutate.len; | 8293 | const field_names_start = extra.mutate.len; |
| 8156 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name | 8294 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name |
| 8295 | const field_types_start = extra.mutate.len; | ||
| 8157 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type | 8296 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type |
| 8297 | const field_defaults_start = extra.mutate.len; | ||
| 8158 | if (ini.any_field_defaults) { | 8298 | if (ini.any_field_defaults) { |
| 8159 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_default | 8299 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_default |
| 8160 | } | 8300 | } |
| 8161 | items.appendAssumeCapacity(.{ | 8301 | items.appendAssumeCapacity(.{ |
| 8162 | .tag = switch (ini.explicit_packed_backing_type) { | 8302 | .tag = switch (ini.packed_backing_int_type) { |
| 8163 | .none => if (ini.any_field_defaults) .type_struct_packed_auto_defaults else .type_struct_packed_auto, | 8303 | .none => if (ini.any_field_defaults) .type_struct_packed_auto_defaults else .type_struct_packed_auto, |
| 8164 | else => if (ini.any_field_defaults) .type_struct_packed_explicit_defaults else .type_struct_packed_explicit, | 8304 | else => if (ini.any_field_defaults) .type_struct_packed_explicit_defaults else .type_struct_packed_explicit, |
| 8165 | }, | 8305 | }, |
| ... | @@ -8171,17 +8311,20 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread | ... | @@ -8171,17 +8311,20 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread |
| 8171 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?, | 8311 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?, |
| 8172 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name_nav").?, | 8312 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name_nav").?, |
| 8173 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?, | 8313 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?, |
| 8174 | .tag_type_index = null, | 8314 | .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len }, |
| 8175 | .fields_len = ini.fields_len, | 8315 | .field_types = .{ .tid = tid, .start = field_types_start, .len = ini.fields_len }, |
| 8176 | .field_name_map = field_name_map, | 8316 | .field_values = if (ini.any_field_defaults) |
| 8177 | .field_names_start = field_names_start, | 8317 | .{ .tid = tid, .start = field_defaults_start, .len = ini.fields_len } |
| 8178 | .field_comptime_bits_start = null, | 8318 | else |
| 8319 | undefined, | ||
| 8320 | .field_aligns = undefined, | ||
| 8321 | .field_is_comptime_bits = undefined, | ||
| 8179 | } }; | 8322 | } }; |
| 8180 | }, | 8323 | }, |
| 8181 | }; | 8324 | }; |
| 8182 | 8325 | ||
| 8183 | try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStruct).@"struct".fields.len + | 8326 | try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStruct).@"struct".fields.len + |
| 8184 | type_hash_captures_extra_len + | 8327 | 2 + // type_hash |
| 8185 | ini.fields_len + // field_name | 8328 | ini.fields_len + // field_name |
| 8186 | ini.fields_len + // field_type | 8329 | ini.fields_len + // field_type |
| 8187 | (if (ini.any_field_defaults) ini.fields_len else 0) + // field_default | 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,7 +8334,7 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread |
| 8191 | ini.fields_len); // field_offset | 8334 | ini.fields_len); // field_offset |
| 8192 | 8335 | ||
| 8193 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStruct{ | 8336 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStruct{ |
| 8194 | .zir_index = zir_index, | 8337 | .zir_index = ini.zir_index, |
| 8195 | .name = undefined, // set by `finish` | 8338 | .name = undefined, // set by `finish` |
| 8196 | .name_nav = undefined, // set by `finish` | 8339 | .name_nav = undefined, // set by `finish` |
| 8197 | .namespace = undefined, // set by `finish` | 8340 | .namespace = undefined, // set by `finish` |
| ... | @@ -8199,10 +8342,7 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread | ... | @@ -8199,10 +8342,7 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread |
| 8199 | .field_name_map = field_name_map, | 8342 | .field_name_map = field_name_map, |
| 8200 | .size = 0, | 8343 | .size = 0, |
| 8201 | .flags = .{ | 8344 | .flags = .{ |
| 8202 | .any_captures = switch (ini.key) { | 8345 | .any_captures = .reified, |
| 8203 | .declared => |d| if (d.captures.len != 0) .true else .false, | ||
| 8204 | .reified => .reified, | ||
| 8205 | }, | ||
| 8206 | .layout = if (is_extern) .@"extern" else .auto, | 8346 | .layout = if (is_extern) .@"extern" else .auto, |
| 8207 | .any_comptime_fields = ini.any_comptime_fields, | 8347 | .any_comptime_fields = ini.any_comptime_fields, |
| 8208 | .any_field_defaults = ini.any_field_defaults, | 8348 | .any_field_defaults = ini.any_field_defaults, |
| ... | @@ -8210,30 +8350,27 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread | ... | @@ -8210,30 +8350,27 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread |
| 8210 | .has_one_possible_value = false, | 8350 | .has_one_possible_value = false, |
| 8211 | .has_no_possible_value = false, | 8351 | .has_no_possible_value = false, |
| 8212 | .comptime_only = false, | 8352 | .comptime_only = false, |
| 8353 | .has_runtime_bits = false, | ||
| 8213 | .alignment = .none, | 8354 | .alignment = .none, |
| 8214 | }, | 8355 | }, |
| 8215 | }); | 8356 | }); |
| 8216 | switch (ini.key) { | 8357 | _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); // type_hash |
| 8217 | .declared => |d| if (d.captures.len != 0) { | ||
| 8218 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); | ||
| 8219 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}); | ||
| 8220 | }, | ||
| 8221 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), | ||
| 8222 | } | ||
| 8223 | const field_names_start = extra.mutate.len; | 8358 | const field_names_start = extra.mutate.len; |
| 8224 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name | 8359 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name |
| 8360 | const field_types_start = extra.mutate.len; | ||
| 8225 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type | 8361 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type |
| 8362 | const field_defaults_start = extra.mutate.len; | ||
| 8226 | if (ini.any_field_defaults) { | 8363 | if (ini.any_field_defaults) { |
| 8227 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_default | 8364 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_default |
| 8228 | } | 8365 | } |
| 8366 | const field_aligns_start = extra.mutate.len; | ||
| 8229 | if (ini.any_field_aligns) { | 8367 | if (ini.any_field_aligns) { |
| 8230 | extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 3) / 4); // field_align | 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: { | 8370 | const field_is_comptime_bits_start = extra.mutate.len; |
| 8233 | const start = extra.mutate.len; | 8371 | if (ini.any_comptime_fields) { |
| 8234 | extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 31) / 32); // field_is_comptime_bits | 8372 | extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 31) / 32); // field_is_comptime_bits |
| 8235 | break :start start; | 8373 | } |
| 8236 | } else null; | ||
| 8237 | if (!is_extern) { | 8374 | if (!is_extern) { |
| 8238 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(LoadedStructType.RuntimeOrder.unresolved)}, ini.fields_len); // field_runtime_order | 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,58 +8385,174 @@ pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread |
| 8248 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name").?, | 8385 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name").?, |
| 8249 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name_nav").?, | 8386 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name_nav").?, |
| 8250 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?, | 8387 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?, |
| 8251 | .tag_type_index = null, | 8388 | .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len }, |
| 8389 | .field_types = .{ .tid = tid, .start = field_types_start, .len = ini.fields_len }, | ||
| 8390 | .field_values = if (ini.any_field_defaults) | ||
| 8391 | .{ .tid = tid, .start = field_defaults_start, .len = ini.fields_len } | ||
| 8392 | else | ||
| 8393 | undefined, | ||
| 8394 | .field_aligns = if (ini.any_field_aligns) | ||
| 8395 | .{ .tid = tid, .start = field_aligns_start, .len = ini.fields_len } | ||
| 8396 | else | ||
| 8397 | undefined, | ||
| 8398 | .field_is_comptime_bits = if (ini.any_comptime_fields) | ||
| 8399 | .{ .tid = tid, .start = field_is_comptime_bits_start, .len = (ini.fields_len + 31) / 32 } | ||
| 8400 | else | ||
| 8401 | undefined, | ||
| 8402 | } }; | ||
| 8403 | } | ||
| 8404 | |||
| 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 | .fields_len = ini.fields_len, | 8498 | .fields_len = ini.fields_len, |
| 8253 | .field_name_map = field_name_map, | 8499 | .size = 0, |
| 8254 | .field_names_start = field_names_start, | 8500 | .padding = 0, |
| 8255 | .field_comptime_bits_start = field_comptime_bits_start, | 8501 | .flags = .{ |
| 8502 | .any_captures = if (ini.captures.len != 0) .true else .false, | ||
| 8503 | .enum_tag_mode = ini.enum_tag_mode, | ||
| 8504 | .layout = if (is_extern) .@"extern" else .auto, | ||
| 8505 | .any_field_aligns = ini.any_field_aligns, | ||
| 8506 | .runtime_tag = ini.runtime_tag, | ||
| 8507 | .has_one_possible_value = false, | ||
| 8508 | .has_no_possible_value = false, | ||
| 8509 | .comptime_only = false, | ||
| 8510 | .has_runtime_bits = false, | ||
| 8511 | .alignment = .none, | ||
| 8512 | }, | ||
| 8513 | }); | ||
| 8514 | if (ini.captures.len > 0) { | ||
| 8515 | extra.appendAssumeCapacity(.{@intCast(ini.captures.len)}); // captures_len | ||
| 8516 | extra.appendSliceAssumeCapacity(.{@ptrCast(ini.captures)}); // capture | ||
| 8517 | } | ||
| 8518 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type | ||
| 8519 | if (ini.any_field_aligns) { | ||
| 8520 | extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 3) / 4); // field_align | ||
| 8521 | } | ||
| 8522 | items.appendAssumeCapacity(.{ | ||
| 8523 | .tag = .type_union, | ||
| 8524 | .data = extra_index, | ||
| 8525 | }); | ||
| 8526 | return .{ .wip = .{ | ||
| 8527 | .index = gop.put(), | ||
| 8528 | .tid = tid, | ||
| 8529 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?, | ||
| 8530 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name_nav").?, | ||
| 8531 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?, | ||
| 8532 | .field_names = undefined, | ||
| 8533 | .field_types = undefined, | ||
| 8534 | .field_values = undefined, | ||
| 8535 | .field_aligns = undefined, | ||
| 8536 | .field_is_comptime_bits = undefined, | ||
| 8256 | } }; | 8537 | } }; |
| 8257 | } | 8538 | } |
| 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 | fields_len: u32, | 8543 | fields_len: u32, |
| 8261 | layout: std.builtin.Type.ContainerLayout, | 8544 | layout: std.builtin.Type.ContainerLayout, |
| 8262 | /// The explicitly specified backing integer type for a `packed union`. | ||
| 8263 | /// `.none` means the backing integer is inferred by the compiler. If set, | ||
| 8264 | /// must be an integer type. If the union is not packed, must be `.none`. | ||
| 8265 | explicit_packed_backing_type: Index, | ||
| 8266 | runtime_tag: LoadedUnionType.RuntimeTag, | ||
| 8267 | /// `true` for `union(T)`, but `false` for anything else, including `union(enum(T))`. | ||
| 8268 | have_explicit_enum_tag: bool, | ||
| 8269 | any_field_aligns: bool, | 8545 | any_field_aligns: bool, |
| 8270 | key: union(enum) { | 8546 | runtime_tag: LoadedUnionType.RuntimeTag, |
| 8271 | declared: struct { | 8547 | /// Explicitly specified enum tag type. `.none` if `runtime_tag != .tagged`. |
| 8272 | zir_index: TrackedInst.Index, | 8548 | enum_tag_type: Index, |
| 8273 | captures: []const CaptureValue, | 8549 | /// Explicitly specified backing int type. `.none` if not packed or if backing type is inferred. |
| 8274 | /// This is the `T` in one of the following: | 8550 | packed_backing_int_type: Index, |
| 8275 | /// * `union(T)` (enum tag type) | ||
| 8276 | /// * `union(enum(T))` (int tag type) | ||
| 8277 | /// * `packed union(T)` (int backing type) | ||
| 8278 | /// Or `.none` otherwise. | ||
| 8279 | arg_ty: InternPool.Index, | ||
| 8280 | }, | ||
| 8281 | reified: struct { | ||
| 8282 | zir_index: TrackedInst.Index, | ||
| 8283 | type_hash: u64, | ||
| 8284 | }, | ||
| 8285 | }, | ||
| 8286 | }) Allocator.Error!WipContainerType.Result { | 8551 | }) Allocator.Error!WipContainerType.Result { |
| 8287 | if (ini.explicit_packed_backing_type != .none) { | 8552 | var gop = try ip.getOrPutKey(gpa, io, tid, .{ .union_type = .{ .reified = .{ |
| 8288 | assert(ip.zigTypeTag(ini.explicit_packed_backing_type) == .int); | 8553 | .zir_index = ini.zir_index, |
| 8289 | if (ini.key == .declared) assert(ini.key.declared.arg_ty == ini.explicit_packed_backing_type); | 8554 | .type_hash = ini.type_hash, |
| 8290 | } | 8555 | } } }); |
| 8291 | const key: Key = .{ .union_type = switch (ini.key) { | ||
| 8292 | .declared => |d| .{ .declared = .{ | ||
| 8293 | .zir_index = d.zir_index, | ||
| 8294 | .arg_ty = d.arg_ty, | ||
| 8295 | .captures = .{ .external = d.captures }, | ||
| 8296 | } }, | ||
| 8297 | .reified => |r| .{ .reified = .{ | ||
| 8298 | .zir_index = r.zir_index, | ||
| 8299 | .type_hash = r.type_hash, | ||
| 8300 | } }, | ||
| 8301 | } }; | ||
| 8302 | var gop = try ip.getOrPutKey(gpa, io, tid, key); | ||
| 8303 | defer gop.deinit(); | 8556 | defer gop.deinit(); |
| 8304 | if (gop == .existing) return .{ .existing = gop.existing }; | 8557 | if (gop == .existing) return .{ .existing = gop.existing }; |
| 8305 | 8558 | ||
| ... | @@ -8308,98 +8561,86 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread. | ... | @@ -8308,98 +8561,86 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread. |
| 8308 | const extra = local.getMutableExtra(gpa, io); | 8561 | const extra = local.getMutableExtra(gpa, io); |
| 8309 | try items.ensureUnusedCapacity(1); | 8562 | try items.ensureUnusedCapacity(1); |
| 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 | const is_extern = switch (ini.layout) { | 8564 | const is_extern = switch (ini.layout) { |
| 8317 | .auto => false, | 8565 | .auto => false, |
| 8318 | .@"extern" => true, | 8566 | .@"extern" => true, |
| 8319 | .@"packed" => { | 8567 | .@"packed" => { |
| 8320 | try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeUnionPacked).@"struct".fields.len + | 8568 | try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeUnionPacked).@"struct".fields.len + |
| 8321 | type_hash_captures_extra_len + | 8569 | 2 + // type_hash |
| 8570 | ini.fields_len + // reified_field_name | ||
| 8322 | ini.fields_len); // field_type | 8571 | ini.fields_len); // field_type |
| 8323 | 8572 | ||
| 8324 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnionPacked{ | 8573 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnionPacked{ |
| 8325 | .zir_index = zir_index, | 8574 | .zir_index = ini.zir_index, |
| 8326 | .captures_len = switch (ini.key) { | 8575 | .captures_len = .reified, |
| 8327 | .declared => |d| @enumFromInt(d.captures.len), | ||
| 8328 | .reified => .reified, | ||
| 8329 | }, | ||
| 8330 | .name = undefined, // set by `finish` | 8576 | .name = undefined, // set by `finish` |
| 8331 | .name_nav = undefined, // set by `finish` | 8577 | .name_nav = undefined, // set by `finish` |
| 8332 | .namespace = undefined, // set by `finish` | 8578 | .namespace = undefined, // set by `finish` |
| 8333 | .backing_int_type = ini.explicit_packed_backing_type, | 8579 | .backing_int_type = ini.packed_backing_int_type, |
| 8334 | .enum_tag_type = .none, // set by `setTagType` | 8580 | .enum_tag_type = .none, |
| 8335 | .fields_len = ini.fields_len, | 8581 | .fields_len = ini.fields_len, |
| 8336 | }); | 8582 | }); |
| 8337 | switch (ini.key) { | 8583 | _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); // type_hash |
| 8338 | .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}), | 8584 | const field_names_start = extra.mutate.len; |
| 8339 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), | 8585 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // reified_field_name |
| 8340 | } | 8586 | const field_types_start = extra.mutate.len; |
| 8341 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type | 8587 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type |
| 8342 | items.appendAssumeCapacity(.{ | 8588 | items.appendAssumeCapacity(.{ |
| 8343 | .tag = switch (ini.explicit_packed_backing_type) { | 8589 | .tag = switch (ini.packed_backing_int_type) { |
| 8344 | .none => .type_union_packed_auto, | 8590 | .none => .type_union_packed_auto, |
| 8345 | else => .type_union_packed_explicit, | 8591 | else => .type_union_packed_explicit, |
| 8346 | }, | 8592 | }, |
| 8347 | .data = extra_index, | 8593 | .data = extra_index, |
| 8348 | }); | 8594 | }); |
| 8349 | return .{ | 8595 | return .{ .wip = .{ |
| 8350 | .wip = .{ | 8596 | .index = gop.put(), |
| 8351 | .index = gop.put(), | 8597 | .tid = tid, |
| 8352 | .tid = tid, | 8598 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name").?, |
| 8353 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name").?, | 8599 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name_nav").?, |
| 8354 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name_nav").?, | 8600 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "namespace").?, |
| 8355 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "namespace").?, | 8601 | .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len }, |
| 8356 | .tag_type_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "enum_tag_type").?, | 8602 | .field_types = .{ .tid = tid, .start = field_types_start, .len = ini.fields_len }, |
| 8357 | .fields_len = 0, // the fields come from the enum, so nothing to set | 8603 | .field_values = undefined, |
| 8358 | .field_name_map = undefined, | 8604 | .field_aligns = undefined, |
| 8359 | .field_names_start = undefined, | 8605 | .field_is_comptime_bits = undefined, |
| 8360 | .field_comptime_bits_start = undefined, | 8606 | } }; |
| 8361 | }, | ||
| 8362 | }; | ||
| 8363 | }, | 8607 | }, |
| 8364 | }; | 8608 | }; |
| 8365 | 8609 | ||
| 8366 | try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeUnion).@"struct".fields.len + | 8610 | try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeUnion).@"struct".fields.len + |
| 8367 | type_hash_captures_extra_len + | 8611 | 2 + // type_hash |
| 8612 | ini.fields_len + // reified_field_name | ||
| 8368 | ini.fields_len + // field_type | 8613 | ini.fields_len + // field_type |
| 8369 | (if (ini.any_field_aligns) (ini.fields_len + 3) / 4 else 0)); // field_align | 8614 | (if (ini.any_field_aligns) (ini.fields_len + 3) / 4 else 0)); // field_align |
| 8370 | 8615 | ||
| 8371 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{ | 8616 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{ |
| 8372 | .zir_index = zir_index, | 8617 | .zir_index = ini.zir_index, |
| 8373 | .name = undefined, // set by `finish` | 8618 | .name = undefined, // set by `finish` |
| 8374 | .name_nav = undefined, // set by `finish` | 8619 | .name_nav = undefined, // set by `finish` |
| 8375 | .namespace = undefined, // set by `finish` | 8620 | .namespace = undefined, // set by `finish` |
| 8376 | .enum_tag_type = .none, // set by `setTagType` | 8621 | .enum_tag_type = ini.enum_tag_type, |
| 8377 | .fields_len = ini.fields_len, | 8622 | .fields_len = ini.fields_len, |
| 8378 | .size = 0, | 8623 | .size = 0, |
| 8379 | .padding = 0, | 8624 | .padding = 0, |
| 8380 | .flags = .{ | 8625 | .flags = .{ |
| 8381 | .any_captures = switch (ini.key) { | 8626 | .any_captures = .reified, |
| 8382 | .declared => |d| if (d.captures.len != 0) .true else .false, | 8627 | .enum_tag_mode = if (ini.enum_tag_type == .none) .auto else .explicit, |
| 8383 | .reified => .reified, | ||
| 8384 | }, | ||
| 8385 | .explicit_tag_type = ini.have_explicit_enum_tag, | ||
| 8386 | .layout = if (is_extern) .@"extern" else .auto, | 8628 | .layout = if (is_extern) .@"extern" else .auto, |
| 8387 | .any_field_aligns = ini.any_field_aligns, | 8629 | .any_field_aligns = ini.any_field_aligns, |
| 8388 | .runtime_tag = ini.runtime_tag, | 8630 | .runtime_tag = ini.runtime_tag, |
| 8389 | .has_one_possible_value = false, | 8631 | .has_one_possible_value = false, |
| 8390 | .has_no_possible_value = false, | 8632 | .has_no_possible_value = false, |
| 8391 | .comptime_only = false, | 8633 | .comptime_only = false, |
| 8634 | .has_runtime_bits = false, | ||
| 8392 | .alignment = .none, | 8635 | .alignment = .none, |
| 8393 | }, | 8636 | }, |
| 8394 | }); | 8637 | }); |
| 8395 | switch (ini.key) { | 8638 | _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); |
| 8396 | .declared => |d| if (d.captures.len != 0) { | 8639 | const field_names_start = extra.mutate.len; |
| 8397 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); | 8640 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // reified_field_name |
| 8398 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}); | 8641 | const field_types_start = extra.mutate.len; |
| 8399 | }, | ||
| 8400 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), | ||
| 8401 | } | ||
| 8402 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type | 8642 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type |
| 8643 | const field_aligns_start = extra.mutate.len; | ||
| 8403 | if (ini.any_field_aligns) { | 8644 | if (ini.any_field_aligns) { |
| 8404 | extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 3) / 4); // field_align | 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,53 +8648,124 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread. |
| 8407 | .tag = .type_union, | 8648 | .tag = .type_union, |
| 8408 | .data = extra_index, | 8649 | .data = extra_index, |
| 8409 | }); | 8650 | }); |
| 8410 | return .{ | 8651 | return .{ .wip = .{ |
| 8411 | .wip = .{ | 8652 | .index = gop.put(), |
| 8412 | .index = gop.put(), | 8653 | .tid = tid, |
| 8413 | .tid = tid, | 8654 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?, |
| 8414 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?, | 8655 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name_nav").?, |
| 8415 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name_nav").?, | 8656 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?, |
| 8416 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?, | 8657 | .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len }, |
| 8417 | .tag_type_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "enum_tag_type").?, | 8658 | .field_types = .{ .tid = tid, .start = field_types_start, .len = ini.fields_len }, |
| 8418 | .fields_len = 0, // the fields come from the enum, so nothing to set | 8659 | .field_values = undefined, |
| 8419 | .field_name_map = undefined, | 8660 | .field_aligns = if (ini.any_field_aligns) |
| 8420 | .field_names_start = undefined, | 8661 | .{ .tid = tid, .start = field_aligns_start, .len = ini.fields_len } |
| 8421 | .field_comptime_bits_start = undefined, | 8662 | else |
| 8422 | }, | 8663 | undefined, |
| 8423 | }; | 8664 | .field_is_comptime_bits = undefined, |
| 8665 | } }; | ||
| 8424 | } | 8666 | } |
| 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 | fields_len: u32, | 8760 | fields_len: u32, |
| 8428 | /// For `enum(T)` or `union(enum(T))`, this is `T`. Asserts `T` is an integer type. | ||
| 8429 | /// Otherwise, `.none`. | ||
| 8430 | explicit_int_tag_type: Index, | ||
| 8431 | nonexhaustive: bool, | 8761 | nonexhaustive: bool, |
| 8432 | key: union(enum) { | 8762 | /// Explicitly specified int tag type, or `.none` if the int tag type is inferred. |
| 8433 | declared: struct { | 8763 | int_tag_type: Index, |
| 8434 | zir_index: TrackedInst.Index, | ||
| 8435 | captures: []const CaptureValue, | ||
| 8436 | }, | ||
| 8437 | reified: struct { | ||
| 8438 | zir_index: TrackedInst.Index, | ||
| 8439 | type_hash: u64, | ||
| 8440 | }, | ||
| 8441 | generated_union_tag: Index, | ||
| 8442 | }, | ||
| 8443 | }) Allocator.Error!WipContainerType.Result { | 8764 | }) Allocator.Error!WipContainerType.Result { |
| 8444 | const key: Key = .{ .enum_type = switch (ini.key) { | 8765 | var gop = try ip.getOrPutKey(gpa, io, tid, .{ .enum_type = .{ .reified = .{ |
| 8445 | .declared => |d| .{ .declared = .{ | 8766 | .zir_index = ini.zir_index, |
| 8446 | .zir_index = d.zir_index, | 8767 | .type_hash = ini.type_hash, |
| 8447 | .arg_ty = ini.explicit_int_tag_type, | 8768 | } } }); |
| 8448 | .captures = .{ .external = d.captures }, | ||
| 8449 | } }, | ||
| 8450 | .reified => |r| .{ .reified = .{ | ||
| 8451 | .zir_index = r.zir_index, | ||
| 8452 | .type_hash = r.type_hash, | ||
| 8453 | } }, | ||
| 8454 | .generated_union_tag => |u| .{ .generated_union_tag = u }, | ||
| 8455 | } }; | ||
| 8456 | var gop = try ip.getOrPutKey(gpa, io, tid, key); | ||
| 8457 | defer gop.deinit(); | 8769 | defer gop.deinit(); |
| 8458 | if (gop == .existing) return .{ .existing = gop.existing }; | 8770 | if (gop == .existing) return .{ .existing = gop.existing }; |
| 8459 | 8771 | ||
| ... | @@ -8464,7 +8776,7 @@ pub fn getEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.I | ... | @@ -8464,7 +8776,7 @@ pub fn getEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.I |
| 8464 | 8776 | ||
| 8465 | const tag: Tag, const have_values: bool = if (ini.nonexhaustive) | 8777 | const tag: Tag, const have_values: bool = if (ini.nonexhaustive) |
| 8466 | .{ .type_enum_nonexhaustive, true } | 8778 | .{ .type_enum_nonexhaustive, true } |
| 8467 | else if (ini.explicit_int_tag_type != .none) | 8779 | else if (ini.int_tag_type != .none) |
| 8468 | .{ .type_enum_explicit, true } | 8780 | .{ .type_enum_explicit, true } |
| 8469 | else | 8781 | else |
| 8470 | .{ .type_enum_auto, false }; | 8782 | .{ .type_enum_auto, false }; |
| ... | @@ -8476,44 +8788,27 @@ pub fn getEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.I | ... | @@ -8476,44 +8788,27 @@ pub fn getEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.I |
| 8476 | errdefer local.mutate.maps.len -= @intFromBool(have_values); | 8788 | errdefer local.mutate.maps.len -= @intFromBool(have_values); |
| 8477 | 8789 | ||
| 8478 | try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeEnum).@"struct".fields.len + | 8790 | try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeEnum).@"struct".fields.len + |
| 8479 | switch (ini.key) { | 8791 | 1 + // zir_index |
| 8480 | .declared => |d| 1 + d.captures.len, // `zir_index` and `capture` | 8792 | 2 + // type_hash |
| 8481 | .reified => 3, // `zir_index` and `type_hash` | ||
| 8482 | .generated_union_tag => 1, // owner_union | ||
| 8483 | } + | ||
| 8484 | @intFromBool(have_values) + // field_value_map | 8793 | @intFromBool(have_values) + // field_value_map |
| 8485 | ini.fields_len + // field_name | 8794 | ini.fields_len + // field_name |
| 8486 | (if (have_values) ini.fields_len else 0)); // field_value | 8795 | (if (have_values) ini.fields_len else 0)); // field_value |
| 8487 | 8796 | ||
| 8488 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeEnum{ | 8797 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeEnum{ |
| 8489 | .captures_len = switch (ini.key) { | 8798 | .captures_len = .reified, |
| 8490 | .declared => |d| @enumFromInt(d.captures.len), | ||
| 8491 | .reified => .reified, | ||
| 8492 | .generated_union_tag => .generated_union_tag, | ||
| 8493 | }, | ||
| 8494 | .name = undefined, // set by `finish` | 8799 | .name = undefined, // set by `finish` |
| 8495 | .name_nav = undefined, // set by `finish` | 8800 | .name_nav = undefined, // set by `finish` |
| 8496 | .namespace = undefined, // set by `finish` | 8801 | .namespace = undefined, // set by `finish` |
| 8497 | .int_tag_type = ini.explicit_int_tag_type, | 8802 | .int_tag_type = ini.int_tag_type, |
| 8498 | .fields_len = ini.fields_len, | 8803 | .fields_len = ini.fields_len, |
| 8499 | .field_name_map = field_name_map, | 8804 | .field_name_map = field_name_map, |
| 8500 | }); | 8805 | }); |
| 8501 | switch (ini.key) { | 8806 | extra.appendAssumeCapacity(.{@intFromEnum(ini.zir_index)}); // zir_index |
| 8502 | .declared => |d| { | 8807 | _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); // type_hash |
| 8503 | extra.appendAssumeCapacity(.{@intFromEnum(d.zir_index)}); // zir_index | 8808 | if (have_values) extra.appendAssumeCapacity(.{@intFromEnum(field_value_map)}); // field_value_map |
| 8504 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}); // capture | ||
| 8505 | }, | ||
| 8506 | .reified => |r| { | ||
| 8507 | extra.appendAssumeCapacity(.{@intFromEnum(r.zir_index)}); // zir_index | ||
| 8508 | _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)); // type_hash | ||
| 8509 | }, | ||
| 8510 | .generated_union_tag => |owner_union| { | ||
| 8511 | extra.appendAssumeCapacity(.{@intFromEnum(owner_union)}); // owner_union | ||
| 8512 | }, | ||
| 8513 | } | ||
| 8514 | if (have_values) extra.appendAssumeCapacity(.{@intFromEnum(field_value_map)}); | ||
| 8515 | const field_names_start = extra.mutate.len; | 8809 | const field_names_start = extra.mutate.len; |
| 8516 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name | 8810 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name |
| 8811 | const field_values_start = extra.mutate.len; | ||
| 8517 | if (have_values) extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_value | 8812 | if (have_values) extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_value |
| 8518 | items.appendAssumeCapacity(.{ | 8813 | items.appendAssumeCapacity(.{ |
| 8519 | .tag = tag, | 8814 | .tag = tag, |
| ... | @@ -8525,22 +8820,91 @@ pub fn getEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.I | ... | @@ -8525,22 +8820,91 @@ pub fn getEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.I |
| 8525 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name").?, | 8820 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name").?, |
| 8526 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name_nav").?, | 8821 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name_nav").?, |
| 8527 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "namespace").?, | 8822 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "namespace").?, |
| 8528 | .tag_type_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "int_tag_type").?, | 8823 | .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len }, |
| 8824 | .field_types = undefined, | ||
| 8825 | .field_values = if (have_values) | ||
| 8826 | .{ .tid = tid, .start = field_values_start, .len = ini.fields_len } | ||
| 8827 | else | ||
| 8828 | undefined, | ||
| 8829 | .field_aligns = undefined, | ||
| 8830 | .field_is_comptime_bits = undefined, | ||
| 8831 | } }; | ||
| 8832 | } | ||
| 8833 | |||
| 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 | .fields_len = ini.fields_len, | 8873 | .fields_len = ini.fields_len, |
| 8530 | .field_name_map = field_name_map, | 8874 | .field_name_map = field_name_map, |
| 8531 | .field_names_start = field_names_start, | 8875 | }); |
| 8532 | .field_comptime_bits_start = null, | 8876 | extra.appendAssumeCapacity(.{@intFromEnum(ini.union_type)}); // owner_union |
| 8877 | if (have_values) extra.appendAssumeCapacity(.{@intFromEnum(field_value_map)}); | ||
| 8878 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name | ||
| 8879 | if (have_values) extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_value | ||
| 8880 | items.appendAssumeCapacity(.{ | ||
| 8881 | .tag = switch (ini.int_tag_mode) { | ||
| 8882 | .auto => .type_enum_auto, | ||
| 8883 | .explicit => .type_enum_explicit, | ||
| 8884 | }, | ||
| 8885 | .data = extra_index, | ||
| 8886 | }); | ||
| 8887 | return .{ .wip = .{ | ||
| 8888 | .index = gop.put(), | ||
| 8889 | .tid = tid, | ||
| 8890 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name").?, | ||
| 8891 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name_nav").?, | ||
| 8892 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "namespace").?, | ||
| 8893 | .field_names = undefined, | ||
| 8894 | .field_types = undefined, | ||
| 8895 | .field_values = undefined, | ||
| 8896 | .field_aligns = undefined, | ||
| 8897 | .field_is_comptime_bits = undefined, | ||
| 8533 | } }; | 8898 | } }; |
| 8534 | } | 8899 | } |
| 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 | zir_index: TrackedInst.Index, | 8902 | zir_index: TrackedInst.Index, |
| 8538 | captures: []const CaptureValue, | 8903 | captures: []const CaptureValue, |
| 8539 | }) Allocator.Error!WipContainerType.Result { | 8904 | }) Allocator.Error!WipContainerType.Result { |
| 8540 | var gop = try ip.getOrPutKey(gpa, io, tid, .{ .opaque_type = .{ .declared = .{ | 8905 | var gop = try ip.getOrPutKey(gpa, io, tid, .{ .opaque_type = .{ .declared = .{ |
| 8541 | .zir_index = ini.zir_index, | 8906 | .zir_index = ini.zir_index, |
| 8542 | .captures = .{ .external = ini.captures }, | 8907 | .captures = .{ .external = ini.captures }, |
| 8543 | .arg_ty = .none, | ||
| 8544 | } } }); | 8908 | } } }); |
| 8545 | defer gop.deinit(); | 8909 | defer gop.deinit(); |
| 8546 | if (gop == .existing) return .{ .existing = gop.existing }; | 8910 | if (gop == .existing) return .{ .existing = gop.existing }; |
| ... | @@ -8569,11 +8933,11 @@ pub fn getOpaqueType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread | ... | @@ -8569,11 +8933,11 @@ pub fn getOpaqueType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread |
| 8569 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name").?, | 8933 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name").?, |
| 8570 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name_nav").?, | 8934 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name_nav").?, |
| 8571 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "namespace").?, | 8935 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "namespace").?, |
| 8572 | .tag_type_index = null, | 8936 | .field_names = undefined, |
| 8573 | .fields_len = 0, | 8937 | .field_types = undefined, |
| 8574 | .field_name_map = undefined, | 8938 | .field_values = undefined, |
| 8575 | .field_names_start = undefined, | 8939 | .field_aligns = undefined, |
| 8576 | .field_comptime_bits_start = undefined, | 8940 | .field_is_comptime_bits = undefined, |
| 8577 | } }; | 8941 | } }; |
| 8578 | } | 8942 | } |
| 8579 | 8943 | ||
| ... | @@ -8584,12 +8948,15 @@ pub const WipContainerType = struct { | ... | @@ -8584,12 +8948,15 @@ pub const WipContainerType = struct { |
| 8584 | name_nav_index: u32, | 8948 | name_nav_index: u32, |
| 8585 | namespace_index: u32, | 8949 | namespace_index: u32, |
| 8586 | 8950 | ||
| 8587 | tag_type_index: ?u32, | 8951 | // These fields are only populated when creating reified types, because reified types populate |
| 8588 | 8952 | // field information immediately, with type resolution only handling validation. This is in | |
| 8589 | fields_len: u32, | 8953 | // contrast to declared types, where field information is populated by the type resolution |
| 8590 | field_name_map: MapIndex, | 8954 | // process evaluating ZIR expressions. |
| 8591 | field_names_start: u32, | 8955 | field_names: NullTerminatedString.Slice, |
| 8592 | field_comptime_bits_start: ?u32, | 8956 | field_types: Index.Slice, |
| 8957 | field_values: Index.Slice, | ||
| 8958 | field_aligns: Alignment.Slice, | ||
| 8959 | field_is_comptime_bits: LoadedStructType.ComptimeBits, | ||
| 8593 | 8960 | ||
| 8594 | pub fn setName( | 8961 | pub fn setName( |
| 8595 | wip: WipContainerType, | 8962 | wip: WipContainerType, |
| ... | @@ -8605,48 +8972,6 @@ pub const WipContainerType = struct { | ... | @@ -8605,48 +8972,6 @@ pub const WipContainerType = struct { |
| 8605 | extra_items[wip.name_nav_index] = @intFromEnum(name_nav); | 8972 | extra_items[wip.name_nav_index] = @intFromEnum(name_nav); |
| 8606 | } | 8973 | } |
| 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 | pub fn finish( | 8975 | pub fn finish( |
| 8651 | wip: WipContainerType, | 8976 | wip: WipContainerType, |
| 8652 | ip: *InternPool, | 8977 | ip: *InternPool, |
| ... | @@ -8657,14 +8982,6 @@ pub const WipContainerType = struct { | ... | @@ -8657,14 +8982,6 @@ pub const WipContainerType = struct { |
| 8657 | 8982 | ||
| 8658 | extra_items[wip.namespace_index] = @intFromEnum(namespace); | 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 | return wip.index; | 8985 | return wip.index; |
| 8669 | } | 8986 | } |
| 8670 | 8987 | ||
| ... | @@ -9504,19 +9821,6 @@ fn addStringsToMap( | ... | @@ -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 | fn addMap(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, cap: usize) Allocator.Error!MapIndex { | 9824 | fn addMap(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, cap: usize) Allocator.Error!MapIndex { |
| 9521 | const maps = ip.getLocal(tid).getMutableMaps(gpa, io); | 9825 | const maps = ip.getLocal(tid).getMutableMaps(gpa, io); |
| 9522 | const unwrapped: MapIndex.Unwrapped = .{ .tid = tid, .index = maps.mutate.len }; | 9826 | const unwrapped: MapIndex.Unwrapped = .{ .tid = tid, .index = maps.mutate.len }; |
| ... | @@ -10260,10 +10564,78 @@ pub fn dump(ip: *const InternPool) void { | ... | @@ -10260,10 +10564,78 @@ pub fn dump(ip: *const InternPool) void { |
| 10260 | const stderr = std.debug.lockStderr(&buffer); | 10564 | const stderr = std.debug.lockStderr(&buffer); |
| 10261 | defer std.debug.unlockStderr(); | 10565 | defer std.debug.unlockStderr(); |
| 10262 | const w = &stderr.file_writer.interface; | 10566 | const w = &stderr.file_writer.interface; |
| 10567 | dumpDependencyStatsFallible(ip, w) catch return; | ||
| 10263 | dumpStatsFallible(ip, w, std.heap.page_allocator) catch return; | 10568 | dumpStatsFallible(ip, w, std.heap.page_allocator) catch return; |
| 10264 | dumpAllFallible(ip, w) catch return; | 10569 | dumpAllFallible(ip, w) catch return; |
| 10265 | } | 10570 | } |
| 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 | fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !void { | 10639 | fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !void { |
| 10268 | var items_len: usize = 0; | 10640 | var items_len: usize = 0; |
| 10269 | var extra_len: usize = 0; | 10641 | var extra_len: usize = 0; |
| ... | @@ -10278,10 +10650,10 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo | ... | @@ -10278,10 +10650,10 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo |
| 10278 | const limbs_size = 8 * limbs_len; | 10650 | const limbs_size = 8 * limbs_len; |
| 10279 | 10651 | ||
| 10280 | // TODO: map overhead size is not taken into account | 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( | 10655 | try w.print( |
| 10284 | \\InternPool size: {d} bytes | 10656 | \\InternPool values: {d} bytes |
| 10285 | \\ {d} items: {d} bytes | 10657 | \\ {d} items: {d} bytes |
| 10286 | \\ {d} extra: {d} bytes | 10658 | \\ {d} extra: {d} bytes |
| 10287 | \\ {d} limbs: {d} bytes | 10659 | \\ {d} limbs: {d} bytes |
| ... | @@ -10302,6 +10674,8 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo | ... | @@ -10302,6 +10674,8 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo |
| 10302 | }; | 10674 | }; |
| 10303 | var counts = std.AutoArrayHashMap(Tag, TagStats).init(arena); | 10675 | var counts = std.AutoArrayHashMap(Tag, TagStats).init(arena); |
| 10304 | for (ip.locals) |*local| { | 10676 | for (ip.locals) |*local| { |
| 10677 | // Early check for length 0, because `view()` is invalid if capacity is 0 | ||
| 10678 | if (local.mutate.items.len == 0) continue; | ||
| 10305 | const items = local.shared.items.view().slice(); | 10679 | const items = local.shared.items.view().slice(); |
| 10306 | const extra_list = local.shared.extra; | 10680 | const extra_list = local.shared.extra; |
| 10307 | const extra_items = extra_list.view().items(.@"0"); | 10681 | const extra_items = extra_list.view().items(.@"0"); |
| ... | @@ -10562,6 +10936,8 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo | ... | @@ -10562,6 +10936,8 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo |
| 10562 | 10936 | ||
| 10563 | fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void { | 10937 | fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void { |
| 10564 | for (ip.locals, 0..) |*local, tid| { | 10938 | for (ip.locals, 0..) |*local, tid| { |
| 10939 | // Early check for length 0, because `view()` is invalid if capacity is 0 | ||
| 10940 | if (local.mutate.items.len == 0) continue; | ||
| 10565 | const items = local.shared.items.view(); | 10941 | const items = local.shared.items.view(); |
| 10566 | for ( | 10942 | for ( |
| 10567 | items.items(.tag)[0..local.mutate.items.len], | 10943 | items.items(.tag)[0..local.mutate.items.len], |
| ... | @@ -11981,22 +12357,42 @@ pub fn unwrapCoercedFunc(ip: *const InternPool, index: Index) Index { | ... | @@ -11981,22 +12357,42 @@ pub fn unwrapCoercedFunc(ip: *const InternPool, index: Index) Index { |
| 11981 | }; | 12357 | }; |
| 11982 | } | 12358 | } |
| 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 | pub fn addFieldName( | 12363 | pub fn addFieldName( |
| 11986 | ip: *InternPool, | 12364 | ip: *InternPool, |
| 11987 | extra: Local.Extra, | 12365 | names: NullTerminatedString.Slice, |
| 11988 | names_map: MapIndex, | 12366 | map: MapIndex, |
| 11989 | names_start: u32, | ||
| 11990 | name: NullTerminatedString, | 12367 | name: NullTerminatedString, |
| 11991 | ) ?u32 { | 12368 | ) ?u32 { |
| 11992 | const extra_items = extra.view().items(.@"0"); | 12369 | const m = map.get(ip); |
| 11993 | const map = names_map.get(ip); | 12370 | const field_idx = m.count(); |
| 11994 | const field_index = map.count(); | 12371 | const names_slice = names.get(ip); |
| 11995 | const strings = extra_items[names_start..][0..field_index]; | 12372 | names_slice[field_idx] = name; |
| 11996 | const adapter: NullTerminatedString.Adapter = .{ .strings = @ptrCast(strings) }; | 12373 | const adapter: NullTerminatedString.Adapter = .{ .strings = names_slice[0..field_idx] }; |
| 11997 | const gop = map.getOrPutAssumeCapacityAdapted(name, adapter); | 12374 | const gop = m.getOrPutAssumeCapacityAdapted(name, adapter); |
| 11998 | if (gop.found_existing) return @intCast(gop.index); | 12375 | if (gop.found_existing) return @intCast(gop.index); |
| 11999 | extra_items[names_start + field_index] = @intFromEnum(name); | 12376 | assert(gop.index == field_idx); |
| 12377 | return null; | ||
| 12378 | } | ||
| 12379 | |||
| 12380 | /// Like `addFieldName`, but instead of adding a field name to a struct, union, or enum, adds a | ||
| 12381 | /// field tag value for an enum. | ||
| 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 | return null; | 12396 | return null; |
| 12001 | } | 12397 | } |
| 12002 | 12398 | ||
| ... | @@ -12295,6 +12691,7 @@ pub fn resolveStructLayout( | ... | @@ -12295,6 +12691,7 @@ pub fn resolveStructLayout( |
| 12295 | has_no_possible_value: bool, | 12691 | has_no_possible_value: bool, |
| 12296 | has_one_possible_value: bool, | 12692 | has_one_possible_value: bool, |
| 12297 | comptime_only: bool, | 12693 | comptime_only: bool, |
| 12694 | has_runtime_bits: bool, | ||
| 12298 | ) void { | 12695 | ) void { |
| 12299 | const unwrapped_index = struct_type.unwrap(ip); | 12696 | const unwrapped_index = struct_type.unwrap(ip); |
| 12300 | 12697 | ||
| ... | @@ -12311,6 +12708,7 @@ pub fn resolveStructLayout( | ... | @@ -12311,6 +12708,7 @@ pub fn resolveStructLayout( |
| 12311 | flags.has_no_possible_value = has_no_possible_value; | 12708 | flags.has_no_possible_value = has_no_possible_value; |
| 12312 | flags.has_one_possible_value = has_one_possible_value; | 12709 | flags.has_one_possible_value = has_one_possible_value; |
| 12313 | flags.comptime_only = comptime_only; | 12710 | flags.comptime_only = comptime_only; |
| 12711 | flags.has_runtime_bits = has_runtime_bits; | ||
| 12314 | flags.alignment = alignment; | 12712 | flags.alignment = alignment; |
| 12315 | } | 12713 | } |
| 12316 | 12714 | ||
| ... | @@ -12322,12 +12720,14 @@ pub fn resolveUnionLayout( | ... | @@ -12322,12 +12720,14 @@ pub fn resolveUnionLayout( |
| 12322 | ip: *InternPool, | 12720 | ip: *InternPool, |
| 12323 | io: Io, | 12721 | io: Io, |
| 12324 | union_type: Index, | 12722 | union_type: Index, |
| 12723 | enum_tag_type: Index, | ||
| 12325 | size: u32, | 12724 | size: u32, |
| 12326 | padding: u32, | 12725 | padding: u32, |
| 12327 | alignment: Alignment, | 12726 | alignment: Alignment, |
| 12328 | has_no_possible_value: bool, | 12727 | has_no_possible_value: bool, |
| 12329 | has_one_possible_value: bool, | 12728 | has_one_possible_value: bool, |
| 12330 | comptime_only: bool, | 12729 | comptime_only: bool, |
| 12730 | has_runtime_bits: bool, | ||
| 12331 | ) void { | 12731 | ) void { |
| 12332 | const unwrapped_index = union_type.unwrap(ip); | 12732 | const unwrapped_index = union_type.unwrap(ip); |
| 12333 | 12733 | ||
| ... | @@ -12339,17 +12739,24 @@ pub fn resolveUnionLayout( | ... | @@ -12339,17 +12739,24 @@ pub fn resolveUnionLayout( |
| 12339 | const item = unwrapped_index.getItem(ip); | 12739 | const item = unwrapped_index.getItem(ip); |
| 12340 | assert(item.tag == .type_union); | 12740 | assert(item.tag == .type_union); |
| 12341 | 12741 | ||
| 12742 | extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "enum_tag_type").?] = @intFromEnum(enum_tag_type); | ||
| 12342 | extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "size").?] = size; | 12743 | extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "size").?] = size; |
| 12343 | extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "padding").?] = padding; | 12744 | extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "padding").?] = padding; |
| 12344 | const flags: *Tag.TypeUnion.Flags = @ptrCast(&extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "flags").?]); | 12745 | const flags: *Tag.TypeUnion.Flags = @ptrCast(&extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "flags").?]); |
| 12345 | flags.has_no_possible_value = has_no_possible_value; | 12746 | flags.has_no_possible_value = has_no_possible_value; |
| 12346 | flags.has_one_possible_value = has_one_possible_value; | 12747 | flags.has_one_possible_value = has_one_possible_value; |
| 12347 | flags.comptime_only = comptime_only; | 12748 | flags.comptime_only = comptime_only; |
| 12749 | flags.has_runtime_bits = has_runtime_bits; | ||
| 12348 | flags.alignment = alignment; | 12750 | flags.alignment = alignment; |
| 12349 | } | 12751 | } |
| 12350 | 12752 | ||
| 12351 | /// Asserts that `struct_type` is a packed struct type. | 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 | const unwrapped_index = struct_type.unwrap(ip); | 12760 | const unwrapped_index = struct_type.unwrap(ip); |
| 12354 | 12761 | ||
| 12355 | const local = ip.getLocal(unwrapped_index.tid); | 12762 | const local = ip.getLocal(unwrapped_index.tid); |
| ... | @@ -12371,7 +12778,13 @@ pub fn resolvePackedStructBackingInt(ip: *InternPool, io: Io, struct_type: Index | ... | @@ -12371,7 +12778,13 @@ pub fn resolvePackedStructBackingInt(ip: *InternPool, io: Io, struct_type: Index |
| 12371 | } | 12778 | } |
| 12372 | 12779 | ||
| 12373 | /// Asserts that `union_type` is a packed union type. | 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 | const unwrapped_index = union_type.unwrap(ip); | 12788 | const unwrapped_index = union_type.unwrap(ip); |
| 12376 | 12789 | ||
| 12377 | const local = ip.getLocal(unwrapped_index.tid); | 12790 | const local = ip.getLocal(unwrapped_index.tid); |
| ... | @@ -12387,5 +12800,32 @@ pub fn resolvePackedUnionBackingInt(ip: *InternPool, io: Io, union_type: Index, | ... | @@ -12387,5 +12800,32 @@ pub fn resolvePackedUnionBackingInt(ip: *InternPool, io: Io, union_type: Index, |
| 12387 | else => unreachable, | 12800 | else => unreachable, |
| 12388 | } | 12801 | } |
| 12389 | 12802 | ||
| 12803 | extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnionPacked, "enum_tag_type").?] = @intFromEnum(enum_tag_type); | ||
| 12390 | extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnionPacked, "backing_int_type").?] = @intFromEnum(backing_int_type); | 12804 | extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnionPacked, "backing_int_type").?] = @intFromEnum(backing_int_type); |
| 12391 | } | 12805 | } |
| 12806 | |||
| 12807 | /// Asserts that `enum_type` is an enum type. | ||
| 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,7 +397,7 @@ pub const Block = struct { |
| 397 | /// The name of the current "context" for naming namespace types. | 397 | /// The name of the current "context" for naming namespace types. |
| 398 | /// The interpretation of this depends on the name strategy in ZIR, but the name | 398 | /// The interpretation of this depends on the name strategy in ZIR, but the name |
| 399 | /// is always incorporated into the type name somehow. | 399 | /// is always incorporated into the type name somehow. |
| 400 | /// See `Sema.createTypeName`. | 400 | /// See `Sema.setTypeName`. |
| 401 | type_name_ctx: InternPool.NullTerminatedString, | 401 | type_name_ctx: InternPool.NullTerminatedString, |
| 402 | 402 | ||
| 403 | /// Create a `LazySrcLoc` based on an `Offset` from the code being analyzed in this block. | 403 | /// Create a `LazySrcLoc` based on an `Offset` from the code being analyzed in this block. |
| ... | @@ -1158,7 +1158,7 @@ fn analyzeBodyInner( | ... | @@ -1158,7 +1158,7 @@ fn analyzeBodyInner( |
| 1158 | }, inst }); | 1158 | }, inst }); |
| 1159 | } | 1159 | } |
| 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 | // zig fmt: off | 1162 | // zig fmt: off |
| 1163 | .alloc => try sema.zirAlloc(block, inst), | 1163 | .alloc => try sema.zirAlloc(block, inst), |
| 1164 | .alloc_inferred => try sema.zirAllocInferred(block, true), | 1164 | .alloc_inferred => try sema.zirAllocInferred(block, true), |
| ... | @@ -1991,31 +1991,33 @@ fn analyzeBodyInner( | ... | @@ -1991,31 +1991,33 @@ fn analyzeBodyInner( |
| 1991 | break :blk .void_value; | 1991 | break :blk .void_value; |
| 1992 | }, | 1992 | }, |
| 1993 | }; | 1993 | }; |
| 1994 | if (sema.isNoReturn(air_inst)) { | 1994 | if (sema.isNoReturn(air_ref)) { |
| 1995 | // We're going to assume that the body itself is noreturn, so let's ensure that now | 1995 | // We're going to assume that the body itself is noreturn, so let's ensure that now |
| 1996 | assert(block.instructions.items.len > 0); | 1996 | assert(block.instructions.items.len > 0); |
| 1997 | assert(sema.isNoReturn(block.instructions.items[block.instructions.items.len - 1].toRef())); | 1997 | assert(sema.isNoReturn(block.instructions.items[block.instructions.items.len - 1].toRef())); |
| 1998 | break; | 1998 | break; |
| 1999 | } | 1999 | } |
| 2000 | // <MLUGG TODO REMOVE THIS BLOCK, SILLY OPV CHECK> | 2000 | |
| 2001 | if (air_inst.toIndex()) |air_inst_index| { | 2001 | // We must resolve the layout of a type before creating a value of that type. Therefore, |
| 2002 | switch (sema.air_instructions.items(.tag)[@intFromEnum(air_inst_index)]) { | 2002 | // the layout of the type of `air_ref` must already be resolved. |
| 2003 | .inferred_alloc, .inferred_alloc_comptime => {}, | 2003 | check_type: { |
| 2004 | else => { | 2004 | if (air_ref.toIndex()) |air_inst| switch (sema.air_instructions.items(.tag)[@intFromEnum(air_inst)]) { |
| 2005 | assert(sema.typeOf(air_inst).onePossibleValue(pt) catch @panic("") == null); | 2005 | .inferred_alloc, .inferred_alloc_comptime => break :check_type, |
| 2006 | sema.typeOf(air_inst).assertHasLayout(zcu); | 2006 | else => {}, |
| 2007 | }, | 2007 | }; |
| 2008 | } | 2008 | sema.typeOf(air_ref).assertHasLayout(zcu); |
| 2009 | } else { | 2009 | // If the type has an OPV, `air_ref` must be that OPV: there is no other interned value |
| 2010 | switch (tags[@intFromEnum(inst)]) { | 2010 | // it could be, and it would be a bug for the value to not be comptime-known when it has |
| 2011 | // MLUGG TODO: do we actually *want* this exception? we could arguably simplify things without it | 2011 | // an OPV. Behind a `std.debug.runtime_safety` check because `onePossibleValue` mutates |
| 2012 | // e.g. analyzeNavVal could stop doing ensureLayoutResolved in most cases (`extern` is an exception) and instead do `assertHasLayout` | 2012 | // the InternPool so cannot be optimized out. |
| 2013 | .func, .func_inferred, .func_fancy => {}, // exception: we're in a func decl, layout will get resolved in a bit by `analyzeNavVal` | 2013 | if (std.debug.runtime_safety) { |
| 2014 | else => sema.typeOf(air_inst).assertHasLayout(zcu), | 2014 | if (try sema.typeOf(air_ref).onePossibleValue(pt)) |opv| { |
| 2015 | assert(air_ref == Air.Inst.Ref.fromValue(opv)); | ||
| 2016 | } | ||
| 2015 | } | 2017 | } |
| 2016 | } | 2018 | } |
| 2017 | // </MLUGG TODO REMOVE THIS BLOCK, SILLY OPV CHECK> | 2019 | |
| 2018 | map.putAssumeCapacity(inst, air_inst); | 2020 | map.putAssumeCapacity(inst, air_ref); |
| 2019 | i += 1; | 2021 | i += 1; |
| 2020 | } | 2022 | } |
| 2021 | } | 2023 | } |
| ... | @@ -2097,7 +2099,7 @@ pub fn resolveConstStringIntern( | ... | @@ -2097,7 +2099,7 @@ pub fn resolveConstStringIntern( |
| 2097 | 2099 | ||
| 2098 | fn resolveTypeOrPoison(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) !?Type { | 2100 | fn resolveTypeOrPoison(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) !?Type { |
| 2099 | const air_inst = try sema.resolveInst(zir_ref); | 2101 | const air_inst = try sema.resolveInst(zir_ref); |
| 2100 | const ty = try sema.analyzeAsType(block, src, air_inst); | 2102 | const ty = try sema.analyzeAsType(block, src, .type, air_inst); |
| 2101 | if (ty.isGenericPoison()) return null; | 2103 | if (ty.isGenericPoison()) return null; |
| 2102 | return ty; | 2104 | return ty; |
| 2103 | } | 2105 | } |
| ... | @@ -2216,11 +2218,12 @@ pub fn analyzeAsType( | ... | @@ -2216,11 +2218,12 @@ pub fn analyzeAsType( |
| 2216 | sema: *Sema, | 2218 | sema: *Sema, |
| 2217 | block: *Block, | 2219 | block: *Block, |
| 2218 | src: LazySrcLoc, | 2220 | src: LazySrcLoc, |
| 2221 | reason: std.zig.SimpleComptimeReason, | ||
| 2219 | air_inst: Air.Inst.Ref, | 2222 | air_inst: Air.Inst.Ref, |
| 2220 | ) !Type { | 2223 | ) !Type { |
| 2221 | const wanted_type: Type = .type; | 2224 | const wanted_type: Type = .type; |
| 2222 | const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); | 2225 | const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); |
| 2223 | const val = try sema.resolveConstDefinedValue(block, src, coerced_inst, .{ .simple = .type }); | 2226 | const val = try sema.resolveConstDefinedValue(block, src, coerced_inst, .{ .simple = reason }); |
| 2224 | return val.toType(); | 2227 | return val.toType(); |
| 2225 | } | 2228 | } |
| 2226 | 2229 | ||
| ... | @@ -4112,9 +4115,11 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -4112,9 +4115,11 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 4112 | /// or error union pointed to, initializing these pointers along the way. | 4115 | /// or error union pointed to, initializing these pointers along the way. |
| 4113 | /// Given a `*E!?T`, returns a (valid) `*T`. | 4116 | /// Given a `*E!?T`, returns a (valid) `*T`. |
| 4114 | /// May invalidate already-stored payload data. | 4117 | /// May invalidate already-stored payload data. |
| 4118 | /// Asserts that the layout of the pointer child type is already resolved. | ||
| 4115 | fn optEuBasePtrInit(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, src: LazySrcLoc) CompileError!Air.Inst.Ref { | 4119 | fn optEuBasePtrInit(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, src: LazySrcLoc) CompileError!Air.Inst.Ref { |
| 4116 | const pt = sema.pt; | 4120 | const pt = sema.pt; |
| 4117 | const zcu = pt.zcu; | 4121 | const zcu = pt.zcu; |
| 4122 | sema.typeOf(ptr).childType(zcu).assertHasLayout(zcu); | ||
| 4118 | var base_ptr = ptr; | 4123 | var base_ptr = ptr; |
| 4119 | while (true) switch (sema.typeOf(base_ptr).childType(zcu).zigTypeTag(zcu)) { | 4124 | while (true) switch (sema.typeOf(base_ptr).childType(zcu).zigTypeTag(zcu)) { |
| 4120 | .error_union => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true), | 4125 | .error_union => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true), |
| ... | @@ -4128,6 +4133,7 @@ fn optEuBasePtrInit(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, src: LazySrcL | ... | @@ -4128,6 +4133,7 @@ fn optEuBasePtrInit(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, src: LazySrcL |
| 4128 | fn zirOptEuBasePtrInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 4133 | fn zirOptEuBasePtrInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 4129 | const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; | 4134 | const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; |
| 4130 | const ptr = try sema.resolveInst(un_node.operand); | 4135 | const ptr = try sema.resolveInst(un_node.operand); |
| 4136 | try sema.ensureLayoutResolved(sema.typeOf(ptr).childType(sema.pt.zcu)); | ||
| 4131 | return sema.optEuBasePtrInit(block, ptr, block.nodeOffset(un_node.src_node)); | 4137 | return sema.optEuBasePtrInit(block, ptr, block.nodeOffset(un_node.src_node)); |
| 4132 | } | 4138 | } |
| 4133 | 4139 | ||
| ... | @@ -4513,7 +4519,7 @@ fn validateStructInit( | ... | @@ -4513,7 +4519,7 @@ fn validateStructInit( |
| 4513 | if (struct_ty.structFieldIsComptime(i, zcu)) continue; | 4519 | if (struct_ty.structFieldIsComptime(i, zcu)) continue; |
| 4514 | 4520 | ||
| 4515 | if (!struct_ty.isTuple(zcu)) { | 4521 | if (!struct_ty.isTuple(zcu)) { |
| 4516 | try sema.ensureFieldInitsResolved(struct_ty); | 4522 | try sema.ensureStructDefaultsResolved(struct_ty); |
| 4517 | } | 4523 | } |
| 4518 | 4524 | ||
| 4519 | const default_val = struct_ty.structFieldDefaultValue(i, zcu) orelse { | 4525 | const default_val = struct_ty.structFieldDefaultValue(i, zcu) orelse { |
| ... | @@ -5737,7 +5743,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void | ... | @@ -5737,7 +5743,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 5737 | } | 5743 | } |
| 5738 | if (zcu.llvm_object != null and options.linkage == .internal) return; | 5744 | if (zcu.llvm_object != null and options.linkage == .internal) return; |
| 5739 | const export_ty = Value.fromInterned(uav.val).typeOf(zcu); | 5745 | const export_ty = Value.fromInterned(uav.val).typeOf(zcu); |
| 5740 | if (!try sema.validateExternType(export_ty, .other)) { | 5746 | if (!export_ty.validateExtern(.other, zcu)) { |
| 5741 | return sema.failWithOwnedErrorMsg(block, msg: { | 5747 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 5742 | const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)}); | 5748 | const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)}); |
| 5743 | errdefer msg.destroy(sema.gpa); | 5749 | errdefer msg.destroy(sema.gpa); |
| ... | @@ -5789,7 +5795,7 @@ pub fn analyzeExport( | ... | @@ -5789,7 +5795,7 @@ pub fn analyzeExport( |
| 5789 | const exported_nav = ip.getNav(exported_nav_index); | 5795 | const exported_nav = ip.getNav(exported_nav_index); |
| 5790 | const export_ty: Type = .fromInterned(exported_nav.typeOf(ip)); | 5796 | const export_ty: Type = .fromInterned(exported_nav.typeOf(ip)); |
| 5791 | 5797 | ||
| 5792 | if (!try sema.validateExternType(export_ty, .other)) { | 5798 | if (!export_ty.validateExtern(.other, zcu)) { |
| 5793 | return sema.failWithOwnedErrorMsg(block, msg: { | 5799 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 5794 | const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)}); | 5800 | const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)}); |
| 5795 | errdefer msg.destroy(gpa); | 5801 | errdefer msg.destroy(gpa); |
| ... | @@ -5827,7 +5833,7 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void { | ... | @@ -5827,7 +5833,7 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void { |
| 5827 | .nav_val, | 5833 | .nav_val, |
| 5828 | .nav_ty, | 5834 | .nav_ty, |
| 5829 | .type_layout, | 5835 | .type_layout, |
| 5830 | .type_inits, | 5836 | .struct_defaults, |
| 5831 | .memoized_state, | 5837 | .memoized_state, |
| 5832 | => return, // does nothing outside a function | 5838 | => return, // does nothing outside a function |
| 5833 | }; | 5839 | }; |
| ... | @@ -5846,7 +5852,7 @@ fn zirDisableIntrinsics(sema: *Sema) CompileError!void { | ... | @@ -5846,7 +5852,7 @@ fn zirDisableIntrinsics(sema: *Sema) CompileError!void { |
| 5846 | .nav_val, | 5852 | .nav_val, |
| 5847 | .nav_ty, | 5853 | .nav_ty, |
| 5848 | .type_layout, | 5854 | .type_layout, |
| 5849 | .type_inits, | 5855 | .struct_defaults, |
| 5850 | .memoized_state, | 5856 | .memoized_state, |
| 5851 | => return, // does nothing outside a function | 5857 | => return, // does nothing outside a function |
| 5852 | }; | 5858 | }; |
| ... | @@ -6729,8 +6735,28 @@ fn analyzeCall( | ... | @@ -6729,8 +6735,28 @@ fn analyzeCall( |
| 6729 | } else func_src; | 6735 | } else func_src; |
| 6730 | 6736 | ||
| 6731 | const func_ty_info = zcu.typeToFunc(func_ty).?; | 6737 | const func_ty_info = zcu.typeToFunc(func_ty).?; |
| 6732 | // MLUGG TODO: this isn't quite the check i want. this includes inline functions, which aren't *generic*... | 6738 | const any_comptime_params = func_ty_info.comptime_bits != 0 or ct: { |
| 6733 | const func_is_generic = !func_ty.fnHasRuntimeBits(zcu); | 6739 | for (func_ty_info.param_types.get(ip)) |param_ty| { |
| 6740 | if (Type.fromInterned(param_ty).comptimeOnly(zcu)) break :ct true; | ||
| 6741 | } | ||
| 6742 | break :ct Type.fromInterned(func_ty_info.return_type).comptimeOnly(zcu); | ||
| 6743 | }; | ||
| 6744 | const any_generic_types = generic: { | ||
| 6745 | for (func_ty_info.param_types.get(ip)) |param_ty| { | ||
| 6746 | if (param_ty == .generic_poison_type) break :generic true; | ||
| 6747 | } | ||
| 6748 | const ret_ty: Type = .fromInterned(func_ty_info.return_type); | ||
| 6749 | if (ret_ty.toIntern() == .generic_poison_type) { | ||
| 6750 | break :generic true; | ||
| 6751 | } | ||
| 6752 | if (ret_ty.zigTypeTag(zcu) == .error_union and | ||
| 6753 | ret_ty.errorUnionPayload(zcu).toIntern() == .generic_poison_type) | ||
| 6754 | { | ||
| 6755 | break :generic true; | ||
| 6756 | } | ||
| 6757 | break :generic false; | ||
| 6758 | }; | ||
| 6759 | |||
| 6734 | if (!callConvIsCallable(func_ty_info.cc)) { | 6760 | if (!callConvIsCallable(func_ty_info.cc)) { |
| 6735 | return sema.failWithOwnedErrorMsg(block, msg: { | 6761 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 6736 | const msg = try sema.errMsg( | 6762 | const msg = try sema.errMsg( |
| ... | @@ -6766,7 +6792,7 @@ fn analyzeCall( | ... | @@ -6766,7 +6792,7 @@ fn analyzeCall( |
| 6766 | else => unreachable, | 6792 | else => unreachable, |
| 6767 | } else .{ null, false }; | 6793 | } else .{ null, false }; |
| 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 | return sema.failWithNeededComptime(block, func_src, .{ .simple = .generic_call_target }); | 6796 | return sema.failWithNeededComptime(block, func_src, .{ .simple = .generic_call_target }); |
| 6771 | } | 6797 | } |
| 6772 | 6798 | ||
| ... | @@ -6815,13 +6841,13 @@ fn analyzeCall( | ... | @@ -6815,13 +6841,13 @@ fn analyzeCall( |
| 6815 | // This is the `inst_map` used when evaluating generic parameters and return types. | 6841 | // This is the `inst_map` used when evaluating generic parameters and return types. |
| 6816 | var generic_inst_map: InstMap = .{}; | 6842 | var generic_inst_map: InstMap = .{}; |
| 6817 | defer generic_inst_map.deinit(gpa); | 6843 | defer generic_inst_map.deinit(gpa); |
| 6818 | if (func_is_generic) { | 6844 | if (any_generic_types) { |
| 6819 | try generic_inst_map.ensureSpaceForInstructions(gpa, fn_zir_info.param_body); | 6845 | try generic_inst_map.ensureSpaceForInstructions(gpa, fn_zir_info.param_body); |
| 6820 | } | 6846 | } |
| 6821 | 6847 | ||
| 6822 | // This exists so that `generic_block` below can include a "called from here" note back to this | 6848 | // This exists so that `generic_block` below can include a "called from here" note back to this |
| 6823 | // call site when analyzing generic parameter/return types. | 6849 | // call site when analyzing generic parameter/return types. |
| 6824 | var generic_inlining: Block.Inlining = if (func_is_generic) .{ | 6850 | var generic_inlining: Block.Inlining = if (any_generic_types) .{ |
| 6825 | .call_block = block, | 6851 | .call_block = block, |
| 6826 | .call_src = call_src, | 6852 | .call_src = call_src, |
| 6827 | .func = func_val.?.toIntern(), | 6853 | .func = func_val.?.toIntern(), |
| ... | @@ -6834,7 +6860,7 @@ fn analyzeCall( | ... | @@ -6834,7 +6860,7 @@ fn analyzeCall( |
| 6834 | // This is the block in which we evaluate generic function components: that is, generic parameter | 6860 | // This is the block in which we evaluate generic function components: that is, generic parameter |
| 6835 | // types and the generic return type. This must not be used if the function is not generic. | 6861 | // types and the generic return type. This must not be used if the function is not generic. |
| 6836 | // `comptime_reason` is set as needed. | 6862 | // `comptime_reason` is set as needed. |
| 6837 | var generic_block: Block = if (func_is_generic) .{ | 6863 | var generic_block: Block = if (any_generic_types) .{ |
| 6838 | .parent = null, | 6864 | .parent = null, |
| 6839 | .sema = sema, | 6865 | .sema = sema, |
| 6840 | .namespace = fn_nav.analysis.?.namespace, | 6866 | .namespace = fn_nav.analysis.?.namespace, |
| ... | @@ -6843,9 +6869,9 @@ fn analyzeCall( | ... | @@ -6843,9 +6869,9 @@ fn analyzeCall( |
| 6843 | .src_base_inst = fn_nav.analysis.?.zir_index, | 6869 | .src_base_inst = fn_nav.analysis.?.zir_index, |
| 6844 | .type_name_ctx = fn_nav.fqn, | 6870 | .type_name_ctx = fn_nav.fqn, |
| 6845 | } else undefined; | 6871 | } else undefined; |
| 6846 | defer if (func_is_generic) generic_block.instructions.deinit(gpa); | 6872 | defer if (any_generic_types) generic_block.instructions.deinit(gpa); |
| 6847 | 6873 | ||
| 6848 | if (func_is_generic) { | 6874 | if (any_generic_types) { |
| 6849 | // We certainly depend on the generic owner's signature! | 6875 | // We certainly depend on the generic owner's signature! |
| 6850 | try sema.declareDependency(.{ .src_hash = fn_tracked_inst }); | 6876 | try sema.declareDependency(.{ .src_hash = fn_tracked_inst }); |
| 6851 | } | 6877 | } |
| ... | @@ -6857,7 +6883,7 @@ fn analyzeCall( | ... | @@ -6857,7 +6883,7 @@ fn analyzeCall( |
| 6857 | if (raw != .generic_poison_type) break :ty .fromInterned(raw); | 6883 | if (raw != .generic_poison_type) break :ty .fromInterned(raw); |
| 6858 | 6884 | ||
| 6859 | // We must discover the generic parameter type. | 6885 | // We must discover the generic parameter type. |
| 6860 | assert(func_is_generic); | 6886 | assert(any_generic_types); |
| 6861 | const param_inst_idx = fn_zir_info.param_body[arg_idx]; | 6887 | const param_inst_idx = fn_zir_info.param_body[arg_idx]; |
| 6862 | const param_inst = fn_zir.instructions.get(@intFromEnum(param_inst_idx)); | 6888 | const param_inst = fn_zir.instructions.get(@intFromEnum(param_inst_idx)); |
| 6863 | switch (param_inst.tag) { | 6889 | switch (param_inst.tag) { |
| ... | @@ -6888,7 +6914,7 @@ fn analyzeCall( | ... | @@ -6888,7 +6914,7 @@ fn analyzeCall( |
| 6888 | } }; | 6914 | } }; |
| 6889 | 6915 | ||
| 6890 | const ty_ref = try sema.resolveInlineBody(&generic_block, body, param_inst_idx); | 6916 | const ty_ref = try sema.resolveInlineBody(&generic_block, body, param_inst_idx); |
| 6891 | const param_ty = try sema.analyzeAsType(&generic_block, param_src, ty_ref); | 6917 | const param_ty = try sema.analyzeAsType(&generic_block, param_src, .fn_param_types, ty_ref); |
| 6892 | 6918 | ||
| 6893 | if (!param_ty.isValidParamType(zcu)) { | 6919 | if (!param_ty.isValidParamType(zcu)) { |
| 6894 | const opaque_str = if (param_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else ""; | 6920 | const opaque_str = if (param_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else ""; |
| ... | @@ -6906,7 +6932,7 @@ fn analyzeCall( | ... | @@ -6906,7 +6932,7 @@ fn analyzeCall( |
| 6906 | return arg.*; // terminate analysis here | 6932 | return arg.*; // terminate analysis here |
| 6907 | } | 6933 | } |
| 6908 | 6934 | ||
| 6909 | if (func_is_generic) { | 6935 | if (any_generic_types) { |
| 6910 | // We need to put the argument into `generic_inst_map` so that other parameters can refer to it. | 6936 | // We need to put the argument into `generic_inst_map` so that other parameters can refer to it. |
| 6911 | const param_inst_idx = fn_zir_info.param_body[arg_idx]; | 6937 | const param_inst_idx = fn_zir_info.param_body[arg_idx]; |
| 6912 | const declared_comptime = if (std.math.cast(u5, arg_idx)) |i| func_ty_info.paramIsComptime(i) else false; | 6938 | const declared_comptime = if (std.math.cast(u5, arg_idx)) |i| func_ty_info.paramIsComptime(i) else false; |
| ... | @@ -6948,7 +6974,7 @@ fn analyzeCall( | ... | @@ -6948,7 +6974,7 @@ fn analyzeCall( |
| 6948 | // calls (where it should be the IES of the instantiation). However, it's how we print this | 6974 | // calls (where it should be the IES of the instantiation). However, it's how we print this |
| 6949 | // in error messages. | 6975 | // in error messages. |
| 6950 | const resolved_ret_ty: Type = ret_ty: { | 6976 | const resolved_ret_ty: Type = ret_ty: { |
| 6951 | if (!func_is_generic) break :ret_ty .fromInterned(func_ty_info.return_type); | 6977 | if (!any_generic_types) break :ret_ty .fromInterned(func_ty_info.return_type); |
| 6952 | 6978 | ||
| 6953 | const maybe_poison_bare = if (fn_zir_info.inferred_error_set) maybe_poison: { | 6979 | const maybe_poison_bare = if (fn_zir_info.inferred_error_set) maybe_poison: { |
| 6954 | break :maybe_poison ip.errorUnionPayload(func_ty_info.return_type); | 6980 | break :maybe_poison ip.errorUnionPayload(func_ty_info.return_type); |
| ... | @@ -6958,7 +6984,7 @@ fn analyzeCall( | ... | @@ -6958,7 +6984,7 @@ fn analyzeCall( |
| 6958 | 6984 | ||
| 6959 | // Evaluate the generic return type. As with generic parameters, we switch out `sema.code` and `sema.inst_map`. | 6985 | // Evaluate the generic return type. As with generic parameters, we switch out `sema.code` and `sema.inst_map`. |
| 6960 | 6986 | ||
| 6961 | assert(func_is_generic); | 6987 | assert(any_generic_types); |
| 6962 | 6988 | ||
| 6963 | const old_code = sema.code; | 6989 | const old_code = sema.code; |
| 6964 | const old_inst_map = sema.inst_map; | 6990 | const old_inst_map = sema.inst_map; |
| ... | @@ -6981,7 +7007,7 @@ fn analyzeCall( | ... | @@ -6981,7 +7007,7 @@ fn analyzeCall( |
| 6981 | } else bare: { | 7007 | } else bare: { |
| 6982 | assert(fn_zir_info.ret_ty_body.len != 0); | 7008 | assert(fn_zir_info.ret_ty_body.len != 0); |
| 6983 | const ty_ref = try sema.resolveInlineBody(&generic_block, fn_zir_info.ret_ty_body, fn_zir_inst); | 7009 | const ty_ref = try sema.resolveInlineBody(&generic_block, fn_zir_info.ret_ty_body, fn_zir_inst); |
| 6984 | break :bare try sema.analyzeAsType(&generic_block, func_ret_ty_src, ty_ref); | 7010 | break :bare try sema.analyzeAsType(&generic_block, func_ret_ty_src, .fn_ret_ty, ty_ref); |
| 6985 | }; | 7011 | }; |
| 6986 | assert(bare_ty.toIntern() != .generic_poison_type); | 7012 | assert(bare_ty.toIntern() != .generic_poison_type); |
| 6987 | 7013 | ||
| ... | @@ -7035,7 +7061,7 @@ fn analyzeCall( | ... | @@ -7035,7 +7061,7 @@ fn analyzeCall( |
| 7035 | }); | 7061 | }); |
| 7036 | if (func_ty_info.cc == .auto) { | 7062 | if (func_ty_info.cc == .auto) { |
| 7037 | switch (sema.owner.unwrap()) { | 7063 | switch (sema.owner.unwrap()) { |
| 7038 | .@"comptime", .nav_ty, .nav_val, .type_layout, .type_inits, .memoized_state => {}, | 7064 | .@"comptime", .nav_ty, .nav_val, .type_layout, .struct_defaults, .memoized_state => {}, |
| 7039 | .func => |owner_func| ip.funcSetHasErrorTrace(io, owner_func, true), | 7065 | .func => |owner_func| ip.funcSetHasErrorTrace(io, owner_func, true), |
| 7040 | } | 7066 | } |
| 7041 | } | 7067 | } |
| ... | @@ -7043,7 +7069,7 @@ fn analyzeCall( | ... | @@ -7043,7 +7069,7 @@ fn analyzeCall( |
| 7043 | try sema.validateRuntimeValue(block, args_info.argSrc(block, arg_idx), arg); | 7069 | try sema.validateRuntimeValue(block, args_info.argSrc(block, arg_idx), arg); |
| 7044 | } | 7070 | } |
| 7045 | const runtime_func: Air.Inst.Ref, const runtime_args: []const Air.Inst.Ref = func: { | 7071 | const runtime_func: Air.Inst.Ref, const runtime_args: []const Air.Inst.Ref = func: { |
| 7046 | if (!func_is_generic) break :func .{ callee, args }; | 7072 | if (!any_generic_types and !any_comptime_params) break :func .{ callee, args }; |
| 7047 | 7073 | ||
| 7048 | // Instantiate the generic function! | 7074 | // Instantiate the generic function! |
| 7049 | 7075 | ||
| ... | @@ -7512,9 +7538,7 @@ fn zirArrayInitElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil | ... | @@ -7512,9 +7538,7 @@ fn zirArrayInitElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil |
| 7512 | assert(indexable_ty.isIndexable(zcu)); // validated by a previous instruction | 7538 | assert(indexable_ty.isIndexable(zcu)); // validated by a previous instruction |
| 7513 | const elem_ty = switch (indexable_ty.zigTypeTag(zcu)) { | 7539 | const elem_ty = switch (indexable_ty.zigTypeTag(zcu)) { |
| 7514 | .@"struct" => indexable_ty.fieldType(@intFromEnum(bin.rhs), zcu), | 7540 | .@"struct" => indexable_ty.fieldType(@intFromEnum(bin.rhs), zcu), |
| 7515 | .array, .vector => indexable_ty.childType(zcu), | 7541 | else => indexable_ty.indexableElem(zcu), |
| 7516 | .pointer => indexable_ty.indexablePtrElem(zcu), | ||
| 7517 | else => unreachable, | ||
| 7518 | }; | 7542 | }; |
| 7519 | return .fromType(elem_ty); | 7543 | return .fromType(elem_ty); |
| 7520 | } | 7544 | } |
| ... | @@ -7835,8 +7859,8 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr | ... | @@ -7835,8 +7859,8 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr |
| 7835 | }; | 7859 | }; |
| 7836 | return sema.failWithOwnedErrorMsg(block, msg); | 7860 | return sema.failWithOwnedErrorMsg(block, msg); |
| 7837 | } | 7861 | } |
| 7838 | const lhs_ty = try sema.analyzeAsType(block, lhs_src, lhs); | 7862 | const lhs_ty = try sema.analyzeAsType(block, lhs_src, .type, lhs); |
| 7839 | const rhs_ty = try sema.analyzeAsType(block, rhs_src, rhs); | 7863 | const rhs_ty = try sema.analyzeAsType(block, rhs_src, .type, rhs); |
| 7840 | if (lhs_ty.zigTypeTag(zcu) != .error_set) | 7864 | if (lhs_ty.zigTypeTag(zcu) != .error_set) |
| 7841 | return sema.fail(block, lhs_src, "expected error set type, found '{f}'", .{lhs_ty.fmt(pt)}); | 7865 | return sema.fail(block, lhs_src, "expected error set type, found '{f}'", .{lhs_ty.fmt(pt)}); |
| 7842 | if (rhs_ty.zigTypeTag(zcu) != .error_set) | 7866 | if (rhs_ty.zigTypeTag(zcu) != .error_set) |
| ... | @@ -8017,12 +8041,13 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -8017,12 +8041,13 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 8017 | if (dest_ty.zigTypeTag(zcu) != .@"enum") { | 8041 | if (dest_ty.zigTypeTag(zcu) != .@"enum") { |
| 8018 | return sema.fail(block, src, "expected enum, found '{f}'", .{dest_ty.fmt(pt)}); | 8042 | return sema.fail(block, src, "expected enum, found '{f}'", .{dest_ty.fmt(pt)}); |
| 8019 | } | 8043 | } |
| 8044 | try sema.ensureLayoutResolved(dest_ty); | ||
| 8020 | _ = try sema.checkIntType(block, operand_src, operand_ty); | 8045 | _ = try sema.checkIntType(block, operand_src, operand_ty); |
| 8021 | 8046 | ||
| 8022 | if (try sema.resolveValue(operand)) |int_val| { | 8047 | if (try sema.resolveValue(operand)) |int_val| { |
| 8023 | if (dest_ty.isNonexhaustiveEnum(zcu)) { | 8048 | if (dest_ty.isNonexhaustiveEnum(zcu)) { |
| 8024 | const int_tag_ty = dest_ty.intTagType(zcu); | 8049 | const int_tag_ty = dest_ty.intTagType(zcu); |
| 8025 | if (try sema.intFitsInType(int_val, int_tag_ty, null)) { | 8050 | if (int_val.intFitsInType(int_tag_ty, null, zcu)) { |
| 8026 | return Air.internedToRef((try pt.getCoerced(int_val, dest_ty)).toIntern()); | 8051 | return Air.internedToRef((try pt.getCoerced(int_val, dest_ty)).toIntern()); |
| 8027 | } | 8052 | } |
| 8028 | return sema.fail(block, src, "int value '{f}' out of range of non-exhaustive enum '{f}'", .{ | 8053 | return sema.fail(block, src, "int value '{f}' out of range of non-exhaustive enum '{f}'", .{ |
| ... | @@ -8077,10 +8102,14 @@ fn zirOptionalPayloadPtr( | ... | @@ -8077,10 +8102,14 @@ fn zirOptionalPayloadPtr( |
| 8077 | const optional_ptr = try sema.resolveInst(inst_data.operand); | 8102 | const optional_ptr = try sema.resolveInst(inst_data.operand); |
| 8078 | const src = block.nodeOffset(inst_data.src_node); | 8103 | const src = block.nodeOffset(inst_data.src_node); |
| 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 | return sema.analyzeOptionalPayloadPtr(block, src, optional_ptr, safety_check, false); | 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 | fn analyzeOptionalPayloadPtr( | 8113 | fn analyzeOptionalPayloadPtr( |
| 8085 | sema: *Sema, | 8114 | sema: *Sema, |
| 8086 | block: *Block, | 8115 | block: *Block, |
| ... | @@ -8095,12 +8124,12 @@ fn analyzeOptionalPayloadPtr( | ... | @@ -8095,12 +8124,12 @@ fn analyzeOptionalPayloadPtr( |
| 8095 | assert(optional_ptr_ty.zigTypeTag(zcu) == .pointer); | 8124 | assert(optional_ptr_ty.zigTypeTag(zcu) == .pointer); |
| 8096 | 8125 | ||
| 8097 | const opt_type = optional_ptr_ty.childType(zcu); | 8126 | const opt_type = optional_ptr_ty.childType(zcu); |
| 8127 | opt_type.assertHasLayout(zcu); | ||
| 8098 | if (opt_type.zigTypeTag(zcu) != .optional) { | 8128 | if (opt_type.zigTypeTag(zcu) != .optional) { |
| 8099 | return sema.failWithExpectedOptionalType(block, src, opt_type); | 8129 | return sema.failWithExpectedOptionalType(block, src, opt_type); |
| 8100 | } | 8130 | } |
| 8101 | 8131 | ||
| 8102 | const child_type = opt_type.optionalChild(zcu); | 8132 | const child_type = opt_type.optionalChild(zcu); |
| 8103 | try sema.ensureLayoutResolved(child_type); | ||
| 8104 | const child_pointer = try pt.ptrType(.{ | 8133 | const child_pointer = try pt.ptrType(.{ |
| 8105 | .child = child_type.toIntern(), | 8134 | .child = child_type.toIntern(), |
| 8106 | .flags = .{ | 8135 | .flags = .{ |
| ... | @@ -8283,10 +8312,14 @@ fn zirErrUnionPayloadPtr( | ... | @@ -8283,10 +8312,14 @@ fn zirErrUnionPayloadPtr( |
| 8283 | const operand = try sema.resolveInst(inst_data.operand); | 8312 | const operand = try sema.resolveInst(inst_data.operand); |
| 8284 | const src = block.nodeOffset(inst_data.src_node); | 8313 | const src = block.nodeOffset(inst_data.src_node); |
| 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 | return sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false); | 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 | fn analyzeErrUnionPayloadPtr( | 8323 | fn analyzeErrUnionPayloadPtr( |
| 8291 | sema: *Sema, | 8324 | sema: *Sema, |
| 8292 | block: *Block, | 8325 | block: *Block, |
| ... | @@ -8307,8 +8340,8 @@ fn analyzeErrUnionPayloadPtr( | ... | @@ -8307,8 +8340,8 @@ fn analyzeErrUnionPayloadPtr( |
| 8307 | } | 8340 | } |
| 8308 | 8341 | ||
| 8309 | const err_union_ty = operand_ty.childType(zcu); | 8342 | const err_union_ty = operand_ty.childType(zcu); |
| 8343 | err_union_ty.assertHasLayout(zcu); | ||
| 8310 | const payload_ty = err_union_ty.errorUnionPayload(zcu); | 8344 | const payload_ty = err_union_ty.errorUnionPayload(zcu); |
| 8311 | try sema.ensureLayoutResolved(payload_ty); | ||
| 8312 | const operand_pointer_ty = try pt.ptrType(.{ | 8345 | const operand_pointer_ty = try pt.ptrType(.{ |
| 8313 | .child = payload_ty.toIntern(), | 8346 | .child = payload_ty.toIntern(), |
| 8314 | .flags = .{ | 8347 | .flags = .{ |
| ... | @@ -8744,7 +8777,7 @@ fn checkParamTypeCommon( | ... | @@ -8744,7 +8777,7 @@ fn checkParamTypeCommon( |
| 8744 | } | 8777 | } |
| 8745 | if (!param_ty.isGenericPoison() and | 8778 | if (!param_ty.isGenericPoison() and |
| 8746 | !target_util.fnCallConvAllowsZigTypes(cc) and | 8779 | !target_util.fnCallConvAllowsZigTypes(cc) and |
| 8747 | !try sema.validateExternType(param_ty, .param_ty)) | 8780 | !param_ty.validateExtern(.param_ty, zcu)) |
| 8748 | { | 8781 | { |
| 8749 | return sema.failWithOwnedErrorMsg(block, msg: { | 8782 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 8750 | const msg = try sema.errMsg(param_src, "parameter of type '{f}' not allowed in function with calling convention '{s}'", .{ | 8783 | const msg = try sema.errMsg(param_src, "parameter of type '{f}' not allowed in function with calling convention '{s}'", .{ |
| ... | @@ -8818,7 +8851,7 @@ fn checkReturnTypeAndCallConvCommon( | ... | @@ -8818,7 +8851,7 @@ fn checkReturnTypeAndCallConvCommon( |
| 8818 | } | 8851 | } |
| 8819 | if (!bare_ret_ty.isGenericPoison() and | 8852 | if (!bare_ret_ty.isGenericPoison() and |
| 8820 | !target_util.fnCallConvAllowsZigTypes(@"callconv") and | 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 | return sema.failWithOwnedErrorMsg(block, msg: { | 8856 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 8824 | const msg = try sema.errMsg(ret_ty_src, "return type '{s}{f}' not allowed in function with calling convention '{s}'", .{ | 8857 | const msg = try sema.errMsg(ret_ty_src, "return type '{s}{f}' not allowed in function with calling convention '{s}'", .{ |
| ... | @@ -9042,7 +9075,7 @@ fn funcCommon( | ... | @@ -9042,7 +9075,7 @@ fn funcCommon( |
| 9042 | 9075 | ||
| 9043 | if (inferred_error_set) { | 9076 | if (inferred_error_set) { |
| 9044 | assert(has_body); | 9077 | assert(has_body); |
| 9045 | return .fromIntern(try ip.getFuncDeclIes(gpa, io, pt.tid, .{ | 9078 | const func_val: Value = .fromInterned(try ip.getFuncDeclIes(gpa, io, pt.tid, .{ |
| 9046 | .owner_nav = sema.owner.unwrap().nav_val, | 9079 | .owner_nav = sema.owner.unwrap().nav_val, |
| 9047 | 9080 | ||
| 9048 | .param_types = param_types, | 9081 | .param_types = param_types, |
| ... | @@ -9059,6 +9092,8 @@ fn funcCommon( | ... | @@ -9059,6 +9092,8 @@ fn funcCommon( |
| 9059 | .lbrace_column = @as(u16, @truncate(src_locs.columns)), | 9092 | .lbrace_column = @as(u16, @truncate(src_locs.columns)), |
| 9060 | .rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)), | 9093 | .rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)), |
| 9061 | })); | 9094 | })); |
| 9095 | try sema.ensureLayoutResolved(func_val.typeOf(zcu)); | ||
| 9096 | return .fromValue(func_val); | ||
| 9062 | } | 9097 | } |
| 9063 | 9098 | ||
| 9064 | const func_ty = try ip.getFuncType(gpa, io, pt.tid, .{ | 9099 | const func_ty = try ip.getFuncType(gpa, io, pt.tid, .{ |
| ... | @@ -9072,6 +9107,7 @@ fn funcCommon( | ... | @@ -9072,6 +9107,7 @@ fn funcCommon( |
| 9072 | }); | 9107 | }); |
| 9073 | 9108 | ||
| 9074 | if (has_body) { | 9109 | if (has_body) { |
| 9110 | try sema.ensureLayoutResolved(.fromInterned(func_ty)); | ||
| 9075 | return .fromIntern(try ip.getFuncDecl(gpa, io, pt.tid, .{ | 9111 | return .fromIntern(try ip.getFuncDecl(gpa, io, pt.tid, .{ |
| 9076 | .owner_nav = sema.owner.unwrap().nav_val, | 9112 | .owner_nav = sema.owner.unwrap().nav_val, |
| 9077 | .ty = func_ty, | 9113 | .ty = func_ty, |
| ... | @@ -9109,7 +9145,7 @@ fn zirParam( | ... | @@ -9109,7 +9145,7 @@ fn zirParam( |
| 9109 | } | 9145 | } |
| 9110 | 9146 | ||
| 9111 | const param_ty_inst = try sema.resolveInlineBody(block, body, inst); | 9147 | const param_ty_inst = try sema.resolveInlineBody(block, body, inst); |
| 9112 | break :ty try sema.analyzeAsType(block, src, param_ty_inst); | 9148 | break :ty try sema.analyzeAsType(block, src, .fn_param_types, param_ty_inst); |
| 9113 | }; | 9149 | }; |
| 9114 | 9150 | ||
| 9115 | try block.params.append(sema.arena, .{ | 9151 | try block.params.append(sema.arena, .{ |
| ... | @@ -9948,6 +9984,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp | ... | @@ -9948,6 +9984,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp |
| 9948 | err_union_ty.fmt(pt), | 9984 | err_union_ty.fmt(pt), |
| 9949 | }); | 9985 | }); |
| 9950 | } | 9986 | } |
| 9987 | try sema.ensureLayoutResolved(err_union_ty); | ||
| 9951 | 9988 | ||
| 9952 | const non_err_cond = if (non_err_case.operand_is_ref) | 9989 | const non_err_cond = if (non_err_case.operand_is_ref) |
| 9953 | try sema.analyzePtrIsNonErr(block, operand_src, eu_maybe_ptr) | 9990 | try sema.analyzePtrIsNonErr(block, operand_src, eu_maybe_ptr) |
| ... | @@ -12924,7 +12961,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -12924,7 +12961,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 12924 | const res_ty: InternPool.Index = b: { | 12961 | const res_ty: InternPool.Index = b: { |
| 12925 | if (extra.res_ty == .none) break :b .none; | 12962 | if (extra.res_ty == .none) break :b .none; |
| 12926 | const res_ty_inst = try sema.resolveInst(extra.res_ty); | 12963 | const res_ty_inst = try sema.resolveInst(extra.res_ty); |
| 12927 | const res_ty = try sema.analyzeAsType(block, operand_src, res_ty_inst); | 12964 | const res_ty = try sema.analyzeAsType(block, operand_src, .type, res_ty_inst); |
| 12928 | if (res_ty.isGenericPoison()) break :b .none; | 12965 | if (res_ty.isGenericPoison()) break :b .none; |
| 12929 | break :b res_ty.toIntern(); | 12966 | break :b res_ty.toIntern(); |
| 12930 | }; | 12967 | }; |
| ... | @@ -15683,8 +15720,8 @@ fn zirCmpEq( | ... | @@ -15683,8 +15720,8 @@ fn zirCmpEq( |
| 15683 | return block.addBinOp(air_tag, lhs, rhs); | 15720 | return block.addBinOp(air_tag, lhs, rhs); |
| 15684 | } | 15721 | } |
| 15685 | if (lhs_ty_tag == .type and rhs_ty_tag == .type) { | 15722 | if (lhs_ty_tag == .type and rhs_ty_tag == .type) { |
| 15686 | const lhs_as_type = try sema.analyzeAsType(block, lhs_src, lhs); | 15723 | const lhs_as_type = try sema.analyzeAsType(block, lhs_src, .type, lhs); |
| 15687 | const rhs_as_type = try sema.analyzeAsType(block, rhs_src, rhs); | 15724 | const rhs_as_type = try sema.analyzeAsType(block, rhs_src, .type, rhs); |
| 15688 | return if (lhs_as_type.eql(rhs_as_type, zcu) == (op == .eq)) .bool_true else .bool_false; | 15725 | return if (lhs_as_type.eql(rhs_as_type, zcu) == (op == .eq)) .bool_true else .bool_false; |
| 15689 | } | 15726 | } |
| 15690 | return sema.analyzeCmp(block, src, lhs, rhs, op, lhs_src, rhs_src, true); | 15727 | return sema.analyzeCmp(block, src, lhs, rhs, op, lhs_src, rhs_src, true); |
| ... | @@ -15979,16 +16016,7 @@ fn zirThis( | ... | @@ -15979,16 +16016,7 @@ fn zirThis( |
| 15979 | extended: Zir.Inst.Extended.InstData, | 16016 | extended: Zir.Inst.Extended.InstData, |
| 15980 | ) CompileError!Air.Inst.Ref { | 16017 | ) CompileError!Air.Inst.Ref { |
| 15981 | _ = extended; | 16018 | _ = extended; |
| 15982 | const zcu = sema.pt.zcu; | 16019 | return .fromIntern(sema.pt.zcu.namespacePtr(block.namespace).owner_type); |
| 15983 | const namespace = zcu.namespacePtr(block.namespace); | ||
| 15984 | |||
| 15985 | switch (zcu.intern_pool.indexToKey(namespace.owner_type)) { | ||
| 15986 | .opaque_type, .struct_type, .union_type => {}, | ||
| 15987 | // Enum inits are resolved eagerly. TODO MLUGG: honestly i don't think they SHOULD be lol | ||
| 15988 | .enum_type => try sema.ensureFieldInitsResolved(.fromInterned(namespace.owner_type)), | ||
| 15989 | else => unreachable, | ||
| 15990 | } | ||
| 15991 | return .fromIntern(namespace.owner_type); | ||
| 15992 | } | 16020 | } |
| 15993 | 16021 | ||
| 15994 | fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { | 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,12 +16252,12 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16224 | const type_info_ty = try sema.getBuiltinType(src, .Type); | 16252 | const type_info_ty = try sema.getBuiltinType(src, .Type); |
| 16225 | const type_info_tag_ty = type_info_ty.unionTagType(zcu).?; | 16253 | const type_info_tag_ty = type_info_ty.unionTagType(zcu).?; |
| 16226 | 16254 | ||
| 16255 | try sema.ensureLayoutResolved(ty); | ||
| 16256 | |||
| 16227 | if (ty.typeDeclInst(zcu)) |type_decl_inst| { | 16257 | if (ty.typeDeclInst(zcu)) |type_decl_inst| { |
| 16228 | try sema.declareDependency(.{ .namespace = type_decl_inst }); | 16258 | try sema.declareDependency(.{ .namespace = type_decl_inst }); |
| 16229 | } | 16259 | } |
| 16230 | 16260 | ||
| 16231 | try sema.ensureLayoutResolved(ty); | ||
| 16232 | |||
| 16233 | switch (ty.zigTypeTag(zcu)) { | 16261 | switch (ty.zigTypeTag(zcu)) { |
| 16234 | .type, | 16262 | .type, |
| 16235 | .void, | 16263 | .void, |
| ... | @@ -16240,7 +16268,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -16240,7 +16268,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16240 | .undefined, | 16268 | .undefined, |
| 16241 | .null, | 16269 | .null, |
| 16242 | .enum_literal, | 16270 | .enum_literal, |
| 16243 | => |type_info_tag| return unionInitFromEnumTag(sema, block, src, type_info_ty, @intFromEnum(type_info_tag), .void_value), | 16271 | => |type_info_tag| return .fromValue(try pt.unionValue( |
| 16272 | type_info_ty, | ||
| 16273 | Value.uninterpret(type_info_tag, type_info_tag_ty, pt) catch |err| switch (err) { | ||
| 16274 | error.TypeMismatch => @panic("std.builtin is corrupt"), | ||
| 16275 | error.OutOfMemory => |e| return e, | ||
| 16276 | }, | ||
| 16277 | .void, | ||
| 16278 | )), | ||
| 16244 | 16279 | ||
| 16245 | .@"fn" => { | 16280 | .@"fn" => { |
| 16246 | const fn_info_ty = try sema.getBuiltinType(src, .@"Type.Fn"); | 16281 | const fn_info_ty = try sema.getBuiltinType(src, .@"Type.Fn"); |
| ... | @@ -16248,9 +16283,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -16248,9 +16283,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16248 | 16283 | ||
| 16249 | const func_ty_info = zcu.typeToFunc(ty).?; | 16284 | const func_ty_info = zcu.typeToFunc(ty).?; |
| 16250 | const param_vals = try sema.arena.alloc(InternPool.Index, func_ty_info.param_types.len); | 16285 | const param_vals = try sema.arena.alloc(InternPool.Index, func_ty_info.param_types.len); |
| 16286 | var func_is_generic = false; | ||
| 16251 | for (param_vals, 0..) |*param_val, i| { | 16287 | for (param_vals, 0..) |*param_val, i| { |
| 16252 | const param_ty = func_ty_info.param_types.get(ip)[i]; | 16288 | const param_ty = func_ty_info.param_types.get(ip)[i]; |
| 16253 | const is_generic = param_ty == .generic_poison_type; | 16289 | const is_generic = param_ty == .generic_poison_type; |
| 16290 | if (is_generic or Type.fromInterned(param_ty).comptimeOnly(zcu)) func_is_generic = true; | ||
| 16254 | const param_ty_val = try pt.intern(.{ .opt = .{ | 16291 | const param_ty_val = try pt.intern(.{ .opt = .{ |
| 16255 | .ty = try pt.intern(.{ .opt_type = .type_type }), | 16292 | .ty = try pt.intern(.{ .opt_type = .type_type }), |
| 16256 | .val = if (is_generic) .none else param_ty, | 16293 | .val = if (is_generic) .none else param_ty, |
| ... | @@ -16300,18 +16337,21 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -16300,18 +16337,21 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16300 | } }); | 16337 | } }); |
| 16301 | }; | 16338 | }; |
| 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 | const ret_ty_opt = try pt.intern(.{ .opt = .{ | 16352 | const ret_ty_opt = try pt.intern(.{ .opt = .{ |
| 16304 | .ty = try pt.intern(.{ .opt_type = .type_type }), | 16353 | .ty = try pt.intern(.{ .opt_type = .type_type }), |
| 16305 | .val = opt_val: { | 16354 | .val = if (ret_ty_is_generic) .none else func_ty_info.return_type, |
| 16306 | const ret_ty: Type = .fromInterned(func_ty_info.return_type); | ||
| 16307 | if (ret_ty.toIntern() == .generic_poison_type) break :opt_val .none; | ||
| 16308 | if (ret_ty.zigTypeTag(zcu) == .error_union) { | ||
| 16309 | if (ret_ty.errorUnionPayload(zcu).toIntern() == .generic_poison_type) { | ||
| 16310 | break :opt_val .none; | ||
| 16311 | } | ||
| 16312 | } | ||
| 16313 | break :opt_val ret_ty.toIntern(); | ||
| 16314 | }, | ||
| 16315 | } }); | 16355 | } }); |
| 16316 | 16356 | ||
| 16317 | const callconv_ty = try sema.getBuiltinType(src, .CallingConvention); | 16357 | const callconv_ty = try sema.getBuiltinType(src, .CallingConvention); |
| ... | @@ -16320,9 +16360,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -16320,9 +16360,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16320 | error.OutOfMemory => |e| return e, | 16360 | error.OutOfMemory => |e| return e, |
| 16321 | }; | 16361 | }; |
| 16322 | 16362 | ||
| 16323 | // MLUGG TODO | ||
| 16324 | const func_is_generic = false; | ||
| 16325 | |||
| 16326 | const field_values: [5]InternPool.Index = .{ | 16363 | const field_values: [5]InternPool.Index = .{ |
| 16327 | // calling_convention: CallingConvention, | 16364 | // calling_convention: CallingConvention, |
| 16328 | callconv_val.toIntern(), | 16365 | callconv_val.toIntern(), |
| ... | @@ -16837,7 +16874,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -16837,7 +16874,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16837 | .struct_type => ip.loadStructType(ty.toIntern()), | 16874 | .struct_type => ip.loadStructType(ty.toIntern()), |
| 16838 | else => unreachable, | 16875 | else => unreachable, |
| 16839 | }; | 16876 | }; |
| 16840 | try sema.ensureFieldInitsResolved(ty); // can't do this sooner, since it's not allowed on tuples | 16877 | try sema.ensureStructDefaultsResolved(ty); // can't do this sooner, since it's not allowed on tuples |
| 16841 | struct_field_vals = try gpa.alloc(InternPool.Index, struct_type.field_types.len); | 16878 | struct_field_vals = try gpa.alloc(InternPool.Index, struct_type.field_types.len); |
| 16842 | 16879 | ||
| 16843 | for (struct_field_vals, 0..) |*field_val, field_index| { | 16880 | for (struct_field_vals, 0..) |*field_val, field_index| { |
| ... | @@ -18193,7 +18230,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -18193,7 +18230,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 18193 | 18230 | ||
| 18194 | const elem_ty = blk: { | 18231 | const elem_ty = blk: { |
| 18195 | const air_inst = try sema.resolveInst(extra.data.elem_type); | 18232 | const air_inst = try sema.resolveInst(extra.data.elem_type); |
| 18196 | const ty = sema.analyzeAsType(block, elem_ty_src, air_inst) catch |err| { | 18233 | const ty = sema.analyzeAsType(block, elem_ty_src, .type, air_inst) catch |err| { |
| 18197 | if (err == error.AnalysisFail and sema.err != null and sema.typeOf(air_inst).isSinglePointer(zcu)) { | 18234 | if (err == error.AnalysisFail and sema.err != null and sema.typeOf(air_inst).isSinglePointer(zcu)) { |
| 18198 | try sema.errNote(elem_ty_src, sema.err.?, "use '.*' to dereference pointer", .{}); | 18235 | try sema.errNote(elem_ty_src, sema.err.?, "use '.*' to dereference pointer", .{}); |
| 18199 | } | 18236 | } |
| ... | @@ -18274,7 +18311,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -18274,7 +18311,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 18274 | } else if (inst_data.size != .one and elem_ty.zigTypeTag(zcu) == .@"opaque") { | 18311 | } else if (inst_data.size != .one and elem_ty.zigTypeTag(zcu) == .@"opaque") { |
| 18275 | return sema.fail(block, elem_ty_src, "indexable pointer to opaque type '{f}' not allowed", .{elem_ty.fmt(pt)}); | 18312 | return sema.fail(block, elem_ty_src, "indexable pointer to opaque type '{f}' not allowed", .{elem_ty.fmt(pt)}); |
| 18276 | } else if (inst_data.size == .c) { | 18313 | } else if (inst_data.size == .c) { |
| 18277 | if (!try sema.validateExternType(elem_ty, .other)) { | 18314 | if (!elem_ty.validateExtern(.other, zcu)) { |
| 18278 | const msg = msg: { | 18315 | const msg = msg: { |
| 18279 | const msg = try sema.errMsg(elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)}); | 18316 | const msg = try sema.errMsg(elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)}); |
| 18280 | errdefer msg.destroy(sema.gpa); | 18317 | errdefer msg.destroy(sema.gpa); |
| ... | @@ -18288,11 +18325,11 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -18288,11 +18325,11 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 18288 | } | 18325 | } |
| 18289 | } | 18326 | } |
| 18290 | 18327 | ||
| 18291 | if (host_size != 0 and !elem_ty.packable(zcu)) { | 18328 | if (host_size != 0) { |
| 18292 | return sema.failWithOwnedErrorMsg(block, msg: { | 18329 | if (elem_ty.unpackable(zcu)) |reason| return sema.failWithOwnedErrorMsg(block, msg: { |
| 18293 | const msg = try sema.errMsg(elem_ty_src, "bit-pointer cannot refer to value of type '{f}'", .{elem_ty.fmt(pt)}); | 18330 | const msg = try sema.errMsg(elem_ty_src, "bit-pointer cannot refer to value of type '{f}'", .{elem_ty.fmt(pt)}); |
| 18294 | errdefer msg.destroy(sema.gpa); | 18331 | errdefer msg.destroy(sema.gpa); |
| 18295 | try sema.explainWhyTypeIsNotPackable(msg, elem_ty_src, elem_ty); | 18332 | try sema.explainWhyTypeIsUnpackable(msg, elem_ty_src, reason); |
| 18296 | break :msg msg; | 18333 | break :msg msg; |
| 18297 | }); | 18334 | }); |
| 18298 | } | 18335 | } |
| ... | @@ -18455,63 +18492,32 @@ fn arrayInitEmpty(sema: *Sema, block: *Block, src: LazySrcLoc, obj_ty: Type) Com | ... | @@ -18455,63 +18492,32 @@ fn arrayInitEmpty(sema: *Sema, block: *Block, src: LazySrcLoc, obj_ty: Type) Com |
| 18455 | 18492 | ||
| 18456 | fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 18493 | fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 18457 | const pt = sema.pt; | 18494 | const pt = sema.pt; |
| 18495 | const zcu = pt.zcu; | ||
| 18496 | const ip = &zcu.intern_pool; | ||
| 18458 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; | 18497 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; |
| 18459 | const ty_src = block.builtinCallArgSrc(inst_data.src_node, 0); | 18498 | const ty_src = block.builtinCallArgSrc(inst_data.src_node, 0); |
| 18460 | const field_src = block.builtinCallArgSrc(inst_data.src_node, 1); | 18499 | const field_src = block.builtinCallArgSrc(inst_data.src_node, 1); |
| 18461 | const init_src = block.builtinCallArgSrc(inst_data.src_node, 2); | 18500 | const payload_src = block.builtinCallArgSrc(inst_data.src_node, 2); |
| 18462 | const extra = sema.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data; | 18501 | const extra = sema.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data; |
| 18463 | const union_ty = try sema.resolveType(block, ty_src, extra.union_type); | 18502 | const union_ty = try sema.resolveType(block, ty_src, extra.union_type); |
| 18464 | if (union_ty.zigTypeTag(pt.zcu) != .@"union") { | 18503 | if (union_ty.zigTypeTag(pt.zcu) != .@"union") { |
| 18465 | return sema.fail(block, ty_src, "expected union type, found '{f}'", .{union_ty.fmt(pt)}); | 18504 | return sema.fail(block, ty_src, "expected union type, found '{f}'", .{union_ty.fmt(pt)}); |
| 18466 | } | 18505 | } |
| 18506 | union_ty.assertHasLayout(zcu); // from a previous `field_type_ref` instruction | ||
| 18467 | const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, .{ .simple = .union_field_names }); | 18507 | const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, .{ .simple = .union_field_names }); |
| 18468 | const init = try sema.resolveInst(extra.init); | ||
| 18469 | return sema.unionInit(block, init, init_src, union_ty, ty_src, field_name, field_src); | ||
| 18470 | } | ||
| 18471 | |||
| 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 | const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src); | 18508 | const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src); |
| 18486 | const field_ty: Type = .fromInterned(zcu.typeToUnion(union_ty).?.field_types.get(ip)[field_index]); | 18509 | const field_ty: Type = .fromInterned(zcu.typeToUnion(union_ty).?.field_types.get(ip)[field_index]); |
| 18487 | const init = try sema.coerce(block, field_ty, uncasted_init, init_src); | ||
| 18488 | _ = union_ty_src; | ||
| 18489 | return unionInitFromEnumTag(sema, block, init_src, union_ty, field_index, init); | ||
| 18490 | } | ||
| 18491 | 18510 | ||
| 18492 | fn unionInitFromEnumTag( | 18511 | const payload = try sema.coerce(block, field_ty, try sema.resolveInst(extra.init), payload_src); |
| 18493 | sema: *Sema, | ||
| 18494 | block: *Block, | ||
| 18495 | init_src: LazySrcLoc, | ||
| 18496 | union_ty: Type, | ||
| 18497 | field_index: u32, | ||
| 18498 | init: Air.Inst.Ref, | ||
| 18499 | ) !Air.Inst.Ref { | ||
| 18500 | const pt = sema.pt; | ||
| 18501 | const zcu = pt.zcu; | ||
| 18502 | 18512 | ||
| 18503 | if (try sema.resolveValue(init)) |init_val| { | 18513 | if (try sema.resolveValue(payload)) |payload_val| { |
| 18504 | const tag_ty = union_ty.unionTagTypeHypothetical(zcu); | 18514 | const tag_ty = union_ty.unionTagTypeHypothetical(zcu); |
| 18505 | const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index); | 18515 | const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index); |
| 18506 | return Air.internedToRef((try pt.internUnion(.{ | 18516 | return .fromValue(try pt.unionValue(union_ty, tag_val, payload_val)); |
| 18507 | .ty = union_ty.toIntern(), | ||
| 18508 | .tag = tag_val.toIntern(), | ||
| 18509 | .val = init_val.toIntern(), | ||
| 18510 | }))); | ||
| 18511 | } | 18517 | } |
| 18512 | 18518 | ||
| 18513 | try sema.requireRuntimeBlock(block, init_src, null); | 18519 | try sema.requireRuntimeBlock(block, payload_src, null); |
| 18514 | return block.addUnionInit(union_ty, field_index, init); | 18520 | return block.addUnionInit(union_ty, field_index, payload); |
| 18515 | } | 18521 | } |
| 18516 | 18522 | ||
| 18517 | fn zirStructInit( | 18523 | fn zirStructInit( |
| ... | @@ -18588,9 +18594,6 @@ fn zirStructInit( | ... | @@ -18588,9 +18594,6 @@ fn zirStructInit( |
| 18588 | const field_ty = resolved_ty.fieldType(field_index, zcu); | 18594 | const field_ty = resolved_ty.fieldType(field_index, zcu); |
| 18589 | field_inits[field_index] = try sema.coerce(block, field_ty, uncoerced_init, field_src); | 18595 | field_inits[field_index] = try sema.coerce(block, field_ty, uncoerced_init, field_src); |
| 18590 | if (resolved_ty.structFieldIsComptime(field_index, zcu)) { | 18596 | if (resolved_ty.structFieldIsComptime(field_index, zcu)) { |
| 18591 | if (!resolved_ty.isTuple(zcu)) { | ||
| 18592 | try sema.ensureFieldInitsResolved(resolved_ty); | ||
| 18593 | } | ||
| 18594 | const default_value = (try resolved_ty.structFieldValueComptime(pt, field_index)).?; | 18597 | const default_value = (try resolved_ty.structFieldValueComptime(pt, field_index)).?; |
| 18595 | const init_val = (try sema.resolveValue(field_inits[field_index])) orelse { | 18598 | const init_val = (try sema.resolveValue(field_inits[field_index])) orelse { |
| 18596 | return sema.failWithNeededComptime(block, field_src, .{ .simple = .stored_to_comptime_field }); | 18599 | return sema.failWithNeededComptime(block, field_src, .{ .simple = .stored_to_comptime_field }); |
| ... | @@ -18744,7 +18747,12 @@ fn finishStructInit( | ... | @@ -18744,7 +18747,12 @@ fn finishStructInit( |
| 18744 | continue; | 18747 | continue; |
| 18745 | } | 18748 | } |
| 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 | const field_default: InternPool.Index = d: { | 18757 | const field_default: InternPool.Index = d: { |
| 18750 | if (struct_type.field_defaults.len == 0) break :d .none; | 18758 | if (struct_type.field_defaults.len == 0) break :d .none; |
| ... | @@ -18935,55 +18943,54 @@ fn structInitAnon( | ... | @@ -18935,55 +18943,54 @@ fn structInitAnon( |
| 18935 | break :hash hasher.final(); | 18943 | break :hash hasher.final(); |
| 18936 | }; | 18944 | }; |
| 18937 | const tracked_inst = try block.trackZir(inst); | 18945 | const tracked_inst = try block.trackZir(inst); |
| 18938 | const struct_ty: Type = switch (try ip.getStructType(gpa, io, pt.tid, .{ | 18946 | const struct_ty: Type = switch (try ip.getReifiedStructType(gpa, io, pt.tid, .{ |
| 18947 | .zir_index = tracked_inst, | ||
| 18948 | .type_hash = type_hash, | ||
| 18939 | .fields_len = extra_data.fields_len, | 18949 | .fields_len = extra_data.fields_len, |
| 18940 | .layout = .auto, | 18950 | .layout = .auto, |
| 18941 | .explicit_packed_backing_type = .none, | ||
| 18942 | .any_comptime_fields = any_values, | 18951 | .any_comptime_fields = any_values, |
| 18943 | .any_field_defaults = any_values, | 18952 | .any_field_defaults = any_values, |
| 18944 | .any_field_aligns = false, | 18953 | .any_field_aligns = false, |
| 18945 | .key = .{ .reified = .{ | 18954 | .packed_backing_int_type = .none, |
| 18946 | .zir_index = tracked_inst, | ||
| 18947 | .type_hash = type_hash, | ||
| 18948 | } }, | ||
| 18949 | })) { | 18955 | })) { |
| 18956 | .existing => |ty| .fromInterned(ty), | ||
| 18950 | .wip => |wip| ty: { | 18957 | .wip => |wip| ty: { |
| 18951 | errdefer wip.cancel(ip, pt.tid); | 18958 | errdefer wip.cancel(ip, pt.tid); |
| 18952 | // MLUGG TODO obvs this sux | 18959 | try sema.setTypeName(block, &wip, .anon, "struct", inst); |
| 18953 | const anon_prefix = (try sema.createTypeName(block, .anon, "struct", inst)).anon_prefix; | 18960 | |
| 18954 | wip.setName(ip, try ip.getOrPutStringFmt(gpa, io, pt.tid, "{s}_{d}", .{ anon_prefix, @intFromEnum(wip.index) }, .no_embedded_nulls), .none); | 18961 | // Reified structs have field information populated immediately. |
| 18955 | 18962 | @memcpy(wip.field_names.get(ip), names); | |
| 18956 | const struct_type = ip.loadStructType(wip.index); | 18963 | @memcpy(wip.field_types.get(ip), types); |
| 18957 | 18964 | if (any_values) { | |
| 18958 | for (names, values) |name, init_val| { | 18965 | @memcpy(wip.field_values.get(ip), values); |
| 18959 | assert(wip.nextField(ip, name, init_val != .none) == null); // AstGen validated no duplicates for us | 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 | const new_namespace_index = try pt.createNamespace(.{ | 18975 | const new_namespace_index = try pt.createNamespace(.{ |
| 18970 | .parent = block.namespace.toOptional(), | 18976 | .parent = block.namespace.toOptional(), |
| 18971 | .owner_type = wip.index, | 18977 | .owner_type = wip.index, |
| 18972 | .file_scope = block.getFileScopeIndex(zcu), | 18978 | .file_scope = block.getFileScopeIndex(zcu), |
| 18973 | .generation = zcu.generation, | 18979 | .generation = zcu.generation, |
| 18974 | }); | 18980 | }); |
| 18975 | codegen_type: { | ||
| 18976 | if (zcu.comp.config.use_llvm) break :codegen_type; | ||
| 18977 | if (block.ownerModule().strip) break :codegen_type; | ||
| 18978 | zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); | ||
| 18979 | try zcu.comp.queueJob(.{ .link_type = wip.index }); | ||
| 18980 | } | ||
| 18981 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); | 18981 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); |
| 18982 | |||
| 18983 | try zcu.outdated.ensureUnusedCapacity(gpa, 1); | ||
| 18984 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); | ||
| 18985 | errdefer comptime unreachable; // because we don't remove the `outdated` entries | ||
| 18986 | zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); | ||
| 18987 | zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); | ||
| 18988 | |||
| 18982 | break :ty .fromInterned(wip.finish(ip, new_namespace_index)); | 18989 | break :ty .fromInterned(wip.finish(ip, new_namespace_index)); |
| 18983 | }, | 18990 | }, |
| 18984 | .existing => |ty| .fromInterned(ty), | ||
| 18985 | }; | 18991 | }; |
| 18986 | try sema.addTypeReferenceEntry(src, struct_ty); | 18992 | try sema.addTypeReferenceEntry(src, struct_ty); |
| 18993 | try sema.ensureLayoutResolved(struct_ty); | ||
| 18987 | 18994 | ||
| 18988 | _ = opt_runtime_index orelse { | 18995 | _ = opt_runtime_index orelse { |
| 18989 | const struct_val = try pt.aggregateValue(struct_ty, values); | 18996 | const struct_val = try pt.aggregateValue(struct_ty, values); |
| ... | @@ -19338,6 +19345,7 @@ fn fieldType( | ... | @@ -19338,6 +19345,7 @@ fn fieldType( |
| 19338 | const pt = sema.pt; | 19345 | const pt = sema.pt; |
| 19339 | const zcu = pt.zcu; | 19346 | const zcu = pt.zcu; |
| 19340 | const ip = &zcu.intern_pool; | 19347 | const ip = &zcu.intern_pool; |
| 19348 | aggregate_ty.assertHasLayout(zcu); | ||
| 19341 | var cur_ty = aggregate_ty; | 19349 | var cur_ty = aggregate_ty; |
| 19342 | while (true) { | 19350 | while (true) { |
| 19343 | switch (cur_ty.zigTypeTag(zcu)) { | 19351 | switch (cur_ty.zigTypeTag(zcu)) { |
| ... | @@ -19397,7 +19405,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { | ... | @@ -19397,7 +19405,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { |
| 19397 | .func => |func| if (ip.funcAnalysisUnordered(func).has_error_trace and block.ownerModule().error_tracing) { | 19405 | .func => |func| if (ip.funcAnalysisUnordered(func).has_error_trace and block.ownerModule().error_tracing) { |
| 19398 | return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty); | 19406 | return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty); |
| 19399 | }, | 19407 | }, |
| 19400 | .@"comptime", .nav_ty, .nav_val, .type_layout, .type_inits, .memoized_state => {}, | 19408 | .@"comptime", .nav_ty, .nav_val, .type_layout, .struct_defaults, .memoized_state => {}, |
| 19401 | } | 19409 | } |
| 19402 | return Air.internedToRef(try pt.intern(.{ .opt = .{ | 19410 | return Air.internedToRef(try pt.intern(.{ .opt = .{ |
| 19403 | .ty = opt_ptr_stack_trace_ty.toIntern(), | 19411 | .ty = opt_ptr_stack_trace_ty.toIntern(), |
| ... | @@ -19823,7 +19831,7 @@ fn zirReifyPointer( | ... | @@ -19823,7 +19831,7 @@ fn zirReifyPointer( |
| 19823 | else => {}, | 19831 | else => {}, |
| 19824 | } | 19832 | } |
| 19825 | 19833 | ||
| 19826 | if (size == .c and !try sema.validateExternType(elem_ty, .other)) { | 19834 | if (size == .c and !elem_ty.validateExtern(.other, zcu)) { |
| 19827 | return sema.failWithOwnedErrorMsg(block, msg: { | 19835 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 19828 | const msg = try sema.errMsg(src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)}); | 19836 | const msg = try sema.errMsg(src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)}); |
| 19829 | errdefer msg.destroy(gpa); | 19837 | errdefer msg.destroy(gpa); |
| ... | @@ -19988,6 +19996,7 @@ fn zirReifyStruct( | ... | @@ -19988,6 +19996,7 @@ fn zirReifyStruct( |
| 19988 | const name_strategy: Zir.Inst.NameStrategy = @enumFromInt(extended.small); | 19996 | const name_strategy: Zir.Inst.NameStrategy = @enumFromInt(extended.small); |
| 19989 | const extra = sema.code.extraData(Zir.Inst.ReifyStruct, extended.operand).data; | 19997 | const extra = sema.code.extraData(Zir.Inst.ReifyStruct, extended.operand).data; |
| 19990 | const tracked_inst = try block.trackZir(inst); | 19998 | const tracked_inst = try block.trackZir(inst); |
| 19999 | |||
| 19991 | const src: LazySrcLoc = .{ | 20000 | const src: LazySrcLoc = .{ |
| 19992 | .base_node_inst = tracked_inst, | 20001 | .base_node_inst = tracked_inst, |
| 19993 | .offset = .nodeOffset(.zero), | 20002 | .offset = .nodeOffset(.zero), |
| ... | @@ -20039,7 +20048,7 @@ fn zirReifyStruct( | ... | @@ -20039,7 +20048,7 @@ fn zirReifyStruct( |
| 20039 | 20048 | ||
| 20040 | const backing_int_ty_uncoerced = try sema.resolveInst(extra.backing_ty); | 20049 | const backing_int_ty_uncoerced = try sema.resolveInst(extra.backing_ty); |
| 20041 | const backing_int_ty_coerced = try sema.coerce(block, .optional_type, backing_int_ty_uncoerced, backing_ty_src); | 20050 | const backing_int_ty_coerced = try sema.coerce(block, .optional_type, backing_int_ty_uncoerced, backing_ty_src); |
| 20042 | const backing_int_ty_val = try sema.resolveConstDefinedValue(block, backing_ty_src, backing_int_ty_coerced, .{ .simple = .type }); | 20051 | const backing_int_ty_val = try sema.resolveConstDefinedValue(block, backing_ty_src, backing_int_ty_coerced, .{ .simple = .packed_struct_backing_int_type }); |
| 20043 | 20052 | ||
| 20044 | const field_names_uncoerced = try sema.resolveInst(extra.field_names); | 20053 | const field_names_uncoerced = try sema.resolveInst(extra.field_names); |
| 20045 | const field_names_coerced = try sema.coerce(block, .slice_const_slice_const_u8, field_names_uncoerced, field_names_src); | 20054 | const field_names_coerced = try sema.coerce(block, .slice_const_slice_const_u8, field_names_uncoerced, field_names_src); |
| ... | @@ -20079,19 +20088,30 @@ fn zirReifyStruct( | ... | @@ -20079,19 +20088,30 @@ fn zirReifyStruct( |
| 20079 | return sema.failWithUseOfUndef(block, backing_ty_src, null); | 20088 | return sema.failWithUseOfUndef(block, backing_ty_src, null); |
| 20080 | } | 20089 | } |
| 20081 | 20090 | ||
| 20082 | // The validation work here is non-trivial, and it's possible the type already exists. | 20091 | // Most validation of this type happens during type resolution. We basically need to do the work |
| 20083 | // So in this first pass, let's just construct a hash to optimize for this case. If the | 20092 | // which AstGen would normally do. An exception is checking for duplicate field names, which is |
| 20084 | // inputs turn out to be invalid, we can cancel the WIP type later. | 20093 | // handled by type resolution---it just simplifies some logic a little. |
| 20094 | |||
| 20095 | // As well as validation, we're going to gather some information about the fields, and construct | ||
| 20096 | // a hash representing the inputs for deduplication purposes. | ||
| 20085 | 20097 | ||
| 20086 | var any_comptime_fields = false; | 20098 | var any_comptime_fields = false; |
| 20087 | var any_default_inits = false; | 20099 | var any_field_defaults = false; |
| 20088 | var any_aligned_fields = false; | 20100 | var any_field_aligns = false; |
| 20089 | 20101 | ||
| 20090 | // For deduplication purposes, we must create a hash including all details of this type. | ||
| 20091 | // TODO: use a longer hash! | 20102 | // TODO: use a longer hash! |
| 20092 | var hasher = std.hash.Wyhash.init(0); | 20103 | var hasher = std.hash.Wyhash.init(0); |
| 20093 | std.hash.autoHash(&hasher, layout); | 20104 | std.hash.autoHash(&hasher, layout); |
| 20094 | std.hash.autoHash(&hasher, backing_int_ty_val); | 20105 | std.hash.autoHash(&hasher, backing_int_ty_val); |
| 20106 | |||
| 20107 | const backing_int_ty: ?Type = if (backing_int_ty_val.optionalValue(zcu)) |backing| ty: { | ||
| 20108 | switch (layout) { | ||
| 20109 | .auto, .@"extern" => return sema.fail(block, backing_ty_src, "non-packed struct does not support backing integer type", .{}), | ||
| 20110 | .@"packed" => {}, | ||
| 20111 | } | ||
| 20112 | break :ty backing.toType(); | ||
| 20113 | } else null; | ||
| 20114 | |||
| 20095 | // The field *type* array has already been deduplicated for us thanks to the InternPool! | 20115 | // The field *type* array has already been deduplicated for us thanks to the InternPool! |
| 20096 | std.hash.autoHash(&hasher, field_types_arr); | 20116 | std.hash.autoHash(&hasher, field_types_arr); |
| 20097 | // However, for field names and attributes, we need to actually iterate the individual fields, | 20117 | // However, for field names and attributes, we need to actually iterate the individual fields, |
| ... | @@ -20126,201 +20146,126 @@ fn zirReifyStruct( | ... | @@ -20126,201 +20146,126 @@ fn zirReifyStruct( |
| 20126 | field_attrs_src, | 20146 | field_attrs_src, |
| 20127 | .{ .simple = .struct_field_default_value }, | 20147 | .{ .simple = .struct_field_default_value }, |
| 20128 | ); | 20148 | ); |
| 20149 | if (deref_val.canMutateComptimeVarState(zcu)) { | ||
| 20150 | return sema.failWithContainsReferenceToComptimeVar(block, field_attrs_src, field_name, "field default value", deref_val); | ||
| 20151 | } | ||
| 20152 | any_field_defaults = true; | ||
| 20129 | break :d deref_val.toIntern(); | 20153 | break :d deref_val.toIntern(); |
| 20130 | }; | 20154 | }; |
| 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 | std.hash.autoHash(&hasher, .{ | 20175 | std.hash.autoHash(&hasher, .{ |
| 20133 | field_name, | 20176 | field_name, |
| 20134 | field_attr_comptime, | 20177 | field_attr_comptime, |
| 20135 | field_attr_align, | 20178 | field_attr_align, |
| 20136 | field_default, | 20179 | field_default, |
| 20137 | }); | 20180 | }); |
| 20138 | |||
| 20139 | if (field_attr_comptime.toBool()) any_comptime_fields = true; | ||
| 20140 | if (field_attr_align.optionalValue(zcu)) |_| any_aligned_fields = true; | ||
| 20141 | if (field_default != .none) any_default_inits = true; | ||
| 20142 | } | ||
| 20143 | |||
| 20144 | // Some basic validation to avoid a bogus `getStructType` call... | ||
| 20145 | const backing_int_ty: ?Type = if (backing_int_ty_val.optionalValue(zcu)) |backing| ty: { | ||
| 20146 | switch (layout) { | ||
| 20147 | .auto, .@"extern" => return sema.fail(block, backing_ty_src, "non-packed struct does not support backing integer type", .{}), | ||
| 20148 | .@"packed" => {}, | ||
| 20149 | } | ||
| 20150 | break :ty backing.toType(); | ||
| 20151 | } else null; | ||
| 20152 | if (any_aligned_fields and layout == .@"packed") { | ||
| 20153 | return sema.fail(block, field_attrs_src, "packed struct fields cannot be aligned", .{}); | ||
| 20154 | } | ||
| 20155 | if (any_comptime_fields and layout != .auto) { | ||
| 20156 | return sema.fail(block, field_attrs_src, "{t} struct fields cannot be marked comptime", .{layout}); | ||
| 20157 | } | 20181 | } |
| 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 | .fields_len = @intCast(fields_len), | 20186 | .fields_len = @intCast(fields_len), |
| 20161 | .layout = layout, | 20187 | .layout = layout, |
| 20162 | .explicit_packed_backing_type = if (backing_int_ty) |t| t.toIntern() else .none, | ||
| 20163 | .any_comptime_fields = any_comptime_fields, | 20188 | .any_comptime_fields = any_comptime_fields, |
| 20164 | .any_field_defaults = any_default_inits, | 20189 | .any_field_defaults = any_field_defaults, |
| 20165 | .any_field_aligns = any_aligned_fields, | 20190 | .any_field_aligns = any_field_aligns, |
| 20166 | .key = .{ .reified = .{ | 20191 | .packed_backing_int_type = if (backing_int_ty) |ty| ty.toIntern() else .none, |
| 20167 | .zir_index = tracked_inst, | ||
| 20168 | .type_hash = hasher.final(), | ||
| 20169 | } }, | ||
| 20170 | })) { | 20192 | })) { |
| 20171 | .wip => |wip| wip, | ||
| 20172 | .existing => |ty| { | 20193 | .existing => |ty| { |
| 20173 | try sema.addTypeReferenceEntry(src, .fromInterned(ty)); | 20194 | try sema.addTypeReferenceEntry(src, .fromInterned(ty)); |
| 20174 | return .fromIntern(ty); | 20195 | return .fromIntern(ty); |
| 20175 | }, | 20196 | }, |
| 20176 | }; | 20197 | .wip => |wip| { |
| 20177 | errdefer wip_ty.cancel(ip, pt.tid); | 20198 | errdefer wip.cancel(ip, pt.tid); |
| 20178 | 20199 | try sema.setTypeName(block, &wip, name_strategy, "struct", inst); | |
| 20179 | _ = try (try sema.createTypeName( | 20200 | for (0..fields_len) |field_idx| { |
| 20180 | block, | 20201 | const field_name_val = try field_names_arr.elemValue(pt, field_idx); |
| 20181 | name_strategy, | 20202 | const field_attrs_val = try field_attrs_arr.elemValue(pt, field_idx); |
| 20182 | "struct", | 20203 | |
| 20183 | inst, | 20204 | // No source location or reason; first loop checked this is valid. |
| 20184 | )).apply(&wip_ty, pt); | 20205 | const field_name = try sema.sliceToIpString(block, .unneeded, field_name_val, undefined); |
| 20185 | 20206 | wip.field_names.get(ip)[field_idx] = field_name; | |
| 20186 | const wip_struct_type = ip.loadStructType(wip_ty.index); | 20207 | |
| 20187 | 20208 | const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType(); | |
| 20188 | for (0..fields_len) |field_idx| { | 20209 | wip.field_types.get(ip)[field_idx] = field_ty.toIntern(); |
| 20189 | const field_name_val = try field_names_arr.elemValue(pt, field_idx); | 20210 | |
| 20190 | const field_attrs_val = try field_attrs_arr.elemValue(pt, field_idx); | 20211 | const field_attr_comptime = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex( |
| 20191 | 20212 | std.builtin.Type.StructField.Attributes, | |
| 20192 | // Don't pass a reason; first loop acts as a check that this is valid. | 20213 | "comptime", |
| 20193 | const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined); | 20214 | ).?); |
| 20194 | const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType(); | 20215 | const field_attr_align = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex( |
| 20195 | const field_attr_comptime = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex( | 20216 | std.builtin.Type.StructField.Attributes, |
| 20196 | std.builtin.Type.StructField.Attributes, | 20217 | "align", |
| 20197 | "comptime", | 20218 | ).?); |
| 20198 | ).?); | 20219 | const field_attr_default_value_ptr = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex( |
| 20199 | const field_attr_align = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex( | 20220 | std.builtin.Type.StructField.Attributes, |
| 20200 | std.builtin.Type.StructField.Attributes, | 20221 | "default_value_ptr", |
| 20201 | "align", | 20222 | ).?); |
| 20202 | ).?); | 20223 | |
| 20203 | const field_attr_default_value_ptr = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex( | 20224 | if (field_attr_comptime.toBool()) { |
| 20204 | std.builtin.Type.StructField.Attributes, | 20225 | const bit_bag_index = field_idx / 32; |
| 20205 | "default_value_ptr", | 20226 | const mask = @as(u32, 1) << @intCast(field_idx % 32); |
| 20206 | ).?); | 20227 | wip.field_is_comptime_bits.getAll(ip)[bit_bag_index] |= mask; |
| 20228 | } | ||
| 20207 | 20229 | ||
| 20208 | if (wip_ty.nextField(ip, field_name, field_attr_comptime.toBool())) |prev_index| { | 20230 | if (field_attr_default_value_ptr.optionalValue(zcu)) |ptr_val| { |
| 20209 | _ = prev_index; // TODO: better source location | 20231 | const ptr_ty = try pt.singleConstPtrType(field_ty); |
| 20210 | return sema.fail(block, field_names_src, "duplicate struct field name {f}", .{field_name.fmt(ip)}); | 20232 | // No source location; first loop checked this is valid. |
| 20211 | } | 20233 | const deref_val = (try sema.pointerDeref(block, .unneeded, ptr_val, ptr_ty)).?; |
| 20234 | wip.field_values.get(ip)[field_idx] = deref_val.toIntern(); | ||
| 20235 | } else if (any_field_defaults) { | ||
| 20236 | wip.field_values.get(ip)[field_idx] = .none; | ||
| 20237 | } | ||
| 20212 | 20238 | ||
| 20213 | const field_default: InternPool.Index = d: { | 20239 | if (field_attr_align.optionalValue(zcu)) |field_align_val| { |
| 20214 | const ptr_val = field_attr_default_value_ptr.optionalValue(zcu) orelse break :d .none; | 20240 | const bytes = field_align_val.toUnsignedInt(zcu); |
| 20215 | assert(any_default_inits); | 20241 | // No source location; first loop checked this is valid. |
| 20216 | const ptr_ty = try pt.singleConstPtrType(field_ty); | 20242 | const a = try sema.validateAlign(block, .unneeded, bytes); |
| 20217 | // The first loop checked that this is comptime-dereferencable. | 20243 | wip.field_aligns.get(ip)[field_idx] = a; |
| 20218 | const deref_val = (try sema.pointerDeref(block, field_attrs_src, ptr_val, ptr_ty)).?; | 20244 | } else if (any_field_aligns) { |
| 20219 | // ...but we've not checked this yet! | 20245 | wip.field_aligns.get(ip)[field_idx] = .none; |
| 20220 | if (deref_val.canMutateComptimeVarState(zcu)) { | 20246 | } |
| 20221 | return sema.failWithContainsReferenceToComptimeVar(block, field_attrs_src, field_name, "field default value", deref_val); | ||
| 20222 | } | 20247 | } |
| 20223 | break :d deref_val.toIntern(); | ||
| 20224 | }; | ||
| 20225 | |||
| 20226 | if (field_attr_comptime.toBool() and field_default == .none) { | ||
| 20227 | return sema.fail(block, field_attrs_src, "comptime field without default initialization value", .{}); | ||
| 20228 | } | ||
| 20229 | |||
| 20230 | switch (field_ty.zigTypeTag(zcu)) { | ||
| 20231 | .@"opaque" => return sema.failWithOwnedErrorMsg(block, msg: { | ||
| 20232 | const msg = try sema.errMsg(field_types_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); | ||
| 20233 | errdefer msg.destroy(gpa); | ||
| 20234 | try sema.addDeclaredHereNote(msg, field_ty); | ||
| 20235 | break :msg msg; | ||
| 20236 | }), | ||
| 20237 | .noreturn => return sema.failWithOwnedErrorMsg(block, msg: { | ||
| 20238 | const msg = try sema.errMsg(field_types_src, "struct fields cannot be 'noreturn'", .{}); | ||
| 20239 | errdefer msg.destroy(gpa); | ||
| 20240 | try sema.addDeclaredHereNote(msg, field_ty); | ||
| 20241 | break :msg msg; | ||
| 20242 | }), | ||
| 20243 | else => {}, | ||
| 20244 | } | ||
| 20245 | |||
| 20246 | switch (layout) { | ||
| 20247 | .auto => {}, | ||
| 20248 | .@"extern" => if (!try sema.validateExternType(field_ty, .struct_field)) { | ||
| 20249 | return sema.failWithOwnedErrorMsg(block, msg: { | ||
| 20250 | const msg = try sema.errMsg(field_types_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | ||
| 20251 | errdefer msg.destroy(gpa); | ||
| 20252 | try sema.explainWhyTypeIsNotExtern(msg, field_types_src, field_ty, .struct_field); | ||
| 20253 | try sema.addDeclaredHereNote(msg, field_ty); | ||
| 20254 | break :msg msg; | ||
| 20255 | }); | ||
| 20256 | }, | ||
| 20257 | .@"packed" => if (!field_ty.packable(zcu)) { | ||
| 20258 | return sema.failWithOwnedErrorMsg(block, msg: { | ||
| 20259 | const msg = try sema.errMsg(field_types_src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | ||
| 20260 | errdefer msg.destroy(gpa); | ||
| 20261 | try sema.explainWhyTypeIsNotPackable(msg, field_types_src, field_ty); | ||
| 20262 | try sema.addDeclaredHereNote(msg, field_ty); | ||
| 20263 | break :msg msg; | ||
| 20264 | }); | ||
| 20265 | }, | ||
| 20266 | } | ||
| 20267 | |||
| 20268 | wip_struct_type.field_types.get(ip)[field_idx] = field_ty.toIntern(); | ||
| 20269 | if (field_default != .none) { | ||
| 20270 | wip_struct_type.field_defaults.get(ip)[field_idx] = field_default; | ||
| 20271 | } | ||
| 20272 | |||
| 20273 | if (field_attr_align.optionalValue(zcu)) |field_align_val| { | ||
| 20274 | assert(layout != .@"packed"); | ||
| 20275 | const bytes = field_align_val.toUnsignedInt(zcu); | ||
| 20276 | const a = try sema.validateAlign(block, field_attrs_src, bytes); | ||
| 20277 | wip_struct_type.field_aligns.get(ip)[field_idx] = a; | ||
| 20278 | } else if (any_aligned_fields) { | ||
| 20279 | assert(layout != .@"packed"); | ||
| 20280 | wip_struct_type.field_aligns.get(ip)[field_idx] = .none; | ||
| 20281 | } | ||
| 20282 | } | ||
| 20283 | 20248 | ||
| 20284 | if (layout == .@"packed") { | 20249 | const new_namespace_index = try pt.createNamespace(.{ |
| 20285 | var field_bits: u64 = 0; | 20250 | .parent = block.namespace.toOptional(), |
| 20286 | for (0..fields_len) |field_idx| { | 20251 | .owner_type = wip.index, |
| 20287 | const field_ty: Type = .fromInterned(wip_struct_type.field_types.get(ip)[field_idx]); | 20252 | .file_scope = block.getFileScopeIndex(zcu), |
| 20288 | try sema.ensureLayoutResolved(field_ty); | 20253 | .generation = zcu.generation, |
| 20289 | field_bits += field_ty.bitSize(zcu); | 20254 | }); |
| 20290 | } | 20255 | try sema.addTypeReferenceEntry(src, .fromInterned(wip.index)); |
| 20291 | try type_resolution.resolvePackedStructBackingInt( | 20256 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); |
| 20292 | sema, | 20257 | // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind |
| 20293 | block, | 20258 | try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) }); |
| 20294 | field_bits, | ||
| 20295 | .fromInterned(wip_ty.index), | ||
| 20296 | &wip_struct_type, | ||
| 20297 | ); | ||
| 20298 | } else { | ||
| 20299 | try type_resolution.finishStructLayout( | ||
| 20300 | sema, | ||
| 20301 | block, | ||
| 20302 | src, | ||
| 20303 | wip_ty.index, | ||
| 20304 | &wip_struct_type, | ||
| 20305 | ); | ||
| 20306 | } | ||
| 20307 | 20259 | ||
| 20308 | const new_namespace_index = try pt.createNamespace(.{ | 20260 | try zcu.outdated.ensureUnusedCapacity(gpa, 1); |
| 20309 | .parent = block.namespace.toOptional(), | 20261 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); |
| 20310 | .owner_type = wip_ty.index, | 20262 | errdefer comptime unreachable; // because we don't remove the `outdated` entries |
| 20311 | .file_scope = block.getFileScopeIndex(zcu), | 20263 | zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); |
| 20312 | .generation = zcu.generation, | 20264 | zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); |
| 20313 | }); | ||
| 20314 | 20265 | ||
| 20315 | codegen_type: { | 20266 | return .fromIntern(wip.finish(ip, new_namespace_index)); |
| 20316 | if (zcu.comp.config.use_llvm) break :codegen_type; | 20267 | }, |
| 20317 | if (block.ownerModule().strip) break :codegen_type; | ||
| 20318 | zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); | ||
| 20319 | try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); | ||
| 20320 | } | 20268 | } |
| 20321 | try sema.addTypeReferenceEntry(src, .fromInterned(wip_ty.index)); | ||
| 20322 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index); | ||
| 20323 | return .fromIntern(wip_ty.finish(ip, new_namespace_index)); | ||
| 20324 | } | 20269 | } |
| 20325 | 20270 | ||
| 20326 | fn zirReifyUnion( | 20271 | fn zirReifyUnion( |
| ... | @@ -20390,7 +20335,10 @@ fn zirReifyUnion( | ... | @@ -20390,7 +20335,10 @@ fn zirReifyUnion( |
| 20390 | 20335 | ||
| 20391 | const arg_ty_uncoerced = try sema.resolveInst(extra.arg_ty); | 20336 | const arg_ty_uncoerced = try sema.resolveInst(extra.arg_ty); |
| 20392 | const arg_ty_coerced = try sema.coerce(block, .optional_type, arg_ty_uncoerced, arg_ty_src); | 20337 | const arg_ty_coerced = try sema.coerce(block, .optional_type, arg_ty_uncoerced, arg_ty_src); |
| 20393 | const arg_ty_val = try sema.resolveConstDefinedValue(block, arg_ty_src, arg_ty_coerced, .{ .simple = .type }); | 20338 | const arg_ty_val = try sema.resolveConstDefinedValue(block, arg_ty_src, arg_ty_coerced, switch (layout) { |
| 20339 | .@"packed" => .{ .simple = .packed_union_backing_int_type }, | ||
| 20340 | .auto, .@"extern" => .{ .simple = .union_enum_tag_type }, | ||
| 20341 | }); | ||
| 20394 | 20342 | ||
| 20395 | const field_names_uncoerced = try sema.resolveInst(extra.field_names); | 20343 | const field_names_uncoerced = try sema.resolveInst(extra.field_names); |
| 20396 | const field_names_coerced = try sema.coerce(block, .slice_const_slice_const_u8, field_names_uncoerced, field_names_src); | 20344 | const field_names_coerced = try sema.coerce(block, .slice_const_slice_const_u8, field_names_uncoerced, field_names_src); |
| ... | @@ -20430,17 +20378,29 @@ fn zirReifyUnion( | ... | @@ -20430,17 +20378,29 @@ fn zirReifyUnion( |
| 20430 | return sema.failWithUseOfUndef(block, arg_ty_src, null); | 20378 | return sema.failWithUseOfUndef(block, arg_ty_src, null); |
| 20431 | } | 20379 | } |
| 20432 | 20380 | ||
| 20433 | // The validation work here is non-trivial, and it's possible the type already exists. | 20381 | // Most validation of this type happens during type resolution. We basically need to do the work |
| 20434 | // So in this first pass, let's just construct a hash to optimize for this case. If the | 20382 | // which AstGen would normally do. An exception is checking for duplicate field names, which is |
| 20435 | // inputs turn out to be invalid, we can cancel the WIP type later. | 20383 | // handled by type resolution---it just simplifies some logic a little. |
| 20384 | |||
| 20385 | // As well as validation, we're going to gather some information about the fields, and construct | ||
| 20386 | // a hash representing the inputs for deduplication purposes. | ||
| 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 | // TODO: use a longer hash! | 20390 | // TODO: use a longer hash! |
| 20441 | var hasher = std.hash.Wyhash.init(0); | 20391 | var hasher = std.hash.Wyhash.init(0); |
| 20442 | std.hash.autoHash(&hasher, layout); | 20392 | std.hash.autoHash(&hasher, layout); |
| 20443 | std.hash.autoHash(&hasher, arg_ty_val); | 20393 | std.hash.autoHash(&hasher, arg_ty_val); |
| 20394 | |||
| 20395 | const explicit_tag_ty: ?Type, const explicit_packed_backing_type: ?Type = ty: { | ||
| 20396 | const arg_ty = arg_ty_val.optionalValue(zcu) orelse break :ty .{ null, null }; | ||
| 20397 | switch (layout) { | ||
| 20398 | .@"extern" => return sema.fail(block, arg_ty_src, "extern union does not support enum tag type", .{}), | ||
| 20399 | .@"packed" => break :ty .{ null, arg_ty.toType() }, | ||
| 20400 | .auto => break :ty .{ arg_ty.toType(), null }, | ||
| 20401 | } | ||
| 20402 | }; | ||
| 20403 | |||
| 20444 | // `field_types_arr` and `field_attrs_arr` are already deduplicated by the InternPool! | 20404 | // `field_types_arr` and `field_attrs_arr` are already deduplicated by the InternPool! |
| 20445 | std.hash.autoHash(&hasher, field_types_arr); | 20405 | std.hash.autoHash(&hasher, field_types_arr); |
| 20446 | std.hash.autoHash(&hasher, field_attrs_arr); | 20406 | std.hash.autoHash(&hasher, field_attrs_arr); |
| ... | @@ -20457,249 +20417,84 @@ fn zirReifyUnion( | ... | @@ -20457,249 +20417,84 @@ fn zirReifyUnion( |
| 20457 | try field_attrs_arr.elemValue(pt, field_idx), | 20417 | try field_attrs_arr.elemValue(pt, field_idx), |
| 20458 | std.builtin.Type.UnionField.Attributes, | 20418 | std.builtin.Type.UnionField.Attributes, |
| 20459 | ); | 20419 | ); |
| 20460 | if (field_attrs.@"align" != null) { | 20420 | if (field_attrs.@"align") |bytes| { |
| 20461 | any_aligned_fields = true; | 20421 | if (layout == .@"packed") { |
| 20462 | } | 20422 | return sema.fail(block, field_attrs_src, "packed union fields cannot be aligned", .{}); |
| 20463 | } | 20423 | } |
| 20464 | 20424 | // Trigger a compile error if the alignment is invalid. | |
| 20465 | // Some basic validation to avoid a bogus `getUnionType` call... | 20425 | _ = try sema.validateAlign(block, field_attrs_src, bytes); |
| 20466 | const explicit_tag_ty: ?Type, const explicit_packed_backing_type: ?Type = ty: { | 20426 | any_field_aligns = true; |
| 20467 | const arg_ty = arg_ty_val.optionalValue(zcu) orelse break :ty .{ null, null }; | ||
| 20468 | switch (layout) { | ||
| 20469 | .@"extern" => return sema.fail(block, arg_ty_src, "extern union does not support enum tag type", .{}), | ||
| 20470 | .@"packed" => break :ty .{ null, arg_ty.toType() }, | ||
| 20471 | .auto => break :ty .{ arg_ty.toType(), null }, | ||
| 20472 | } | 20427 | } |
| 20473 | }; | ||
| 20474 | if (any_aligned_fields and layout == .@"packed") { | ||
| 20475 | return sema.fail(block, field_attrs_src, "packed union fields cannot be aligned", .{}); | ||
| 20476 | } | 20428 | } |
| 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 | .fields_len = @intCast(fields_len), | 20433 | .fields_len = @intCast(fields_len), |
| 20480 | .layout = layout, | 20434 | .layout = layout, |
| 20481 | .explicit_packed_backing_type = if (explicit_packed_backing_type) |t| t.toIntern() else .none, | 20435 | .any_field_aligns = any_field_aligns, |
| 20482 | .runtime_tag = rt: { | 20436 | .runtime_tag = rt: { |
| 20483 | if (explicit_tag_ty != null) break :rt .tagged; | 20437 | if (explicit_tag_ty != null) break :rt .tagged; |
| 20484 | if (layout == .auto and block.wantSafeTypes()) break :rt .safety; | 20438 | if (layout == .auto and block.wantSafeTypes()) break :rt .safety; |
| 20485 | break :rt .none; | 20439 | break :rt .none; |
| 20486 | }, | 20440 | }, |
| 20487 | .have_explicit_enum_tag = explicit_tag_ty != null, | 20441 | .enum_tag_type = if (explicit_tag_ty) |ty| ty.toIntern() else .none, |
| 20488 | .any_field_aligns = any_aligned_fields, | 20442 | .packed_backing_int_type = if (explicit_packed_backing_type) |ty| ty.toIntern() else .none, |
| 20489 | .key = .{ .reified = .{ | ||
| 20490 | .zir_index = tracked_inst, | ||
| 20491 | .type_hash = hasher.final(), | ||
| 20492 | } }, | ||
| 20493 | })) { | 20443 | })) { |
| 20494 | .wip => |wip| wip, | ||
| 20495 | .existing => |ty| { | 20444 | .existing => |ty| { |
| 20496 | try sema.addTypeReferenceEntry(src, .fromInterned(ty)); | 20445 | try sema.addTypeReferenceEntry(src, .fromInterned(ty)); |
| 20497 | return .fromIntern(ty); | 20446 | return .fromIntern(ty); |
| 20498 | }, | 20447 | }, |
| 20499 | }; | 20448 | .wip => |wip| { |
| 20500 | errdefer wip_ty.cancel(ip, pt.tid); | 20449 | errdefer wip.cancel(ip, pt.tid); |
| 20501 | 20450 | try sema.setTypeName(block, &wip, name_strategy, "union", inst); | |
| 20502 | const type_name = try (try sema.createTypeName( | ||
| 20503 | block, | ||
| 20504 | name_strategy, | ||
| 20505 | "union", | ||
| 20506 | inst, | ||
| 20507 | )).apply(&wip_ty, pt); | ||
| 20508 | |||
| 20509 | const loaded_union = ip.loadUnionType(wip_ty.index); | ||
| 20510 | |||
| 20511 | const generated_tag_ty: InternPool.Index = if (explicit_tag_ty) |enum_tag_ty| generated_tag: { | ||
| 20512 | if (enum_tag_ty.zigTypeTag(zcu) != .@"enum") { | ||
| 20513 | return sema.fail(block, arg_ty_src, "tag type must be an enum type", .{}); | ||
| 20514 | } | ||
| 20515 | |||
| 20516 | const tag_ty_fields_len = enum_tag_ty.enumFieldCount(zcu); | ||
| 20517 | 20451 | ||
| 20518 | for (0..fields_len) |field_idx| { | 20452 | for (0..fields_len) |field_idx| { |
| 20519 | const field_name_val = try field_names_arr.elemValue(pt, field_idx); | 20453 | const field_name_val = try field_names_arr.elemValue(pt, field_idx); |
| 20520 | // Don't pass a reason; first loop acts as a check that this is valid. | 20454 | // No source location or reason; first loop checked this is valid. |
| 20521 | const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined); | 20455 | const field_name = try sema.sliceToIpString(block, .unneeded, field_name_val, undefined); |
| 20456 | wip.field_names.get(ip)[field_idx] = field_name; | ||
| 20522 | 20457 | ||
| 20523 | if (field_idx >= tag_ty_fields_len) { | 20458 | const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType(); |
| 20524 | return sema.fail(block, field_names_src, "no field named '{f}' in enum '{f}'", .{ | 20459 | wip.field_types.get(ip)[field_idx] = field_ty.toIntern(); |
| 20525 | field_name.fmt(ip), enum_tag_ty.fmt(pt), | ||
| 20526 | }); | ||
| 20527 | } | ||
| 20528 | 20460 | ||
| 20529 | const enum_field_name = enum_tag_ty.enumFieldName(field_idx, zcu); | 20461 | // No source location; first loop checked this is valid. |
| 20530 | if (enum_field_name != field_name) { | 20462 | const field_attrs = try sema.interpretBuiltinType( |
| 20531 | return sema.fail(block, field_names_src, "union field name '{f}' does not match enum field name '{f}'", .{ | 20463 | block, |
| 20532 | field_name.fmt(ip), enum_field_name.fmt(ip), | 20464 | .unneeded, |
| 20533 | }); | 20465 | try field_attrs_arr.elemValue(pt, field_idx), |
| 20534 | } | 20466 | std.builtin.Type.UnionField.Attributes, |
| 20535 | } | 20467 | ); |
| 20536 | if (tag_ty_fields_len > fields_len) return sema.failWithOwnedErrorMsg(block, msg: { | 20468 | if (field_attrs.@"align") |bytes| { |
| 20537 | const msg = try sema.errMsg(field_names_src, "{d} enum fields missing in union", .{ | 20469 | // No source location; first loop checked this is valid. |
| 20538 | tag_ty_fields_len - fields_len, | 20470 | const a = try sema.validateAlign(block, .unneeded, bytes); |
| 20539 | }); | 20471 | wip.field_aligns.get(ip)[field_idx] = a; |
| 20540 | errdefer msg.destroy(gpa); | 20472 | } else if (any_field_aligns) { |
| 20541 | for (fields_len..tag_ty_fields_len) |enum_field_idx| { | 20473 | wip.field_aligns.get(ip)[field_idx] = .none; |
| 20542 | try sema.addFieldErrNote(enum_tag_ty, enum_field_idx, msg, "field '{f}' missing, declared here", .{ | 20474 | } |
| 20543 | enum_tag_ty.enumFieldName(enum_field_idx, zcu).fmt(ip), | ||
| 20544 | }); | ||
| 20545 | } | 20475 | } |
| 20546 | try sema.addDeclaredHereNote(msg, enum_tag_ty); | ||
| 20547 | break :msg msg; | ||
| 20548 | }); | ||
| 20549 | wip_ty.setTagType(ip, enum_tag_ty.toIntern()); | ||
| 20550 | break :generated_tag .none; | ||
| 20551 | } else generated_tag: { | ||
| 20552 | // Generate the union's hypothetical tag type. | ||
| 20553 | const wip_tag_ty = switch (try ip.getEnumType(gpa, io, pt.tid, .{ | ||
| 20554 | .fields_len = @intCast(fields_len), | ||
| 20555 | .explicit_int_tag_type = .none, | ||
| 20556 | .nonexhaustive = false, | ||
| 20557 | .key = .{ .generated_union_tag = wip_ty.index }, | ||
| 20558 | })) { | ||
| 20559 | .existing => unreachable, // enum type is keyed on this union type which we're only just creating | ||
| 20560 | .wip => |wip_tag_ty| wip_tag_ty, | ||
| 20561 | }; | ||
| 20562 | errdefer wip_tag_ty.cancel(ip, pt.tid); | ||
| 20563 | |||
| 20564 | // Set its name based on the union's name | ||
| 20565 | _ = wip_tag_ty.setName(ip, try ip.getOrPutStringFmt( | ||
| 20566 | gpa, | ||
| 20567 | io, | ||
| 20568 | pt.tid, | ||
| 20569 | "@typeInfo({f}).@\"union\".tag_type.?", | ||
| 20570 | .{type_name.fmt(ip)}, | ||
| 20571 | .no_embedded_nulls, | ||
| 20572 | ), .none); | ||
| 20573 | |||
| 20574 | // Populate its fields (and report any duplicates) | ||
| 20575 | for (0..fields_len) |field_idx| { | ||
| 20576 | const field_name_val = try field_names_arr.elemValue(pt, field_idx); | ||
| 20577 | // Don't pass a reason; first loop acts as a check that this is valid. | ||
| 20578 | const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined); | ||
| 20579 | if (wip_tag_ty.nextField(ip, field_name, false)) |prev_field_idx| return sema.failWithOwnedErrorMsg(block, msg: { | ||
| 20580 | const msg = try sema.errMsg(src, "duplicate union field '{f}' at index '{d}", .{ field_name.fmt(ip), field_idx }); | ||
| 20581 | errdefer msg.destroy(gpa); | ||
| 20582 | try sema.errNote(src, msg, "previous field at index '{d}'", .{prev_field_idx}); | ||
| 20583 | break :msg msg; | ||
| 20584 | }); | ||
| 20585 | } | ||
| 20586 | |||
| 20587 | // Populate the enum tag type's *integer* tag type | ||
| 20588 | wip_tag_ty.setTagType(ip, int_tag_ty: { | ||
| 20589 | // Infer the int tag type from the field count | ||
| 20590 | const bits = Type.smallestUnsignedBits(fields_len -| 1); | ||
| 20591 | break :int_tag_ty (try pt.intType(.unsigned, bits)).toIntern(); | ||
| 20592 | }); | ||
| 20593 | |||
| 20594 | // Lastly, it needs a dummy namespace | ||
| 20595 | const enum_tag_type_namespace = try pt.createNamespace(.{ | ||
| 20596 | .parent = block.namespace.toOptional(), | ||
| 20597 | .owner_type = wip_tag_ty.index, | ||
| 20598 | .file_scope = block.getFileScopeIndex(zcu), | ||
| 20599 | .generation = zcu.generation, | ||
| 20600 | }); | ||
| 20601 | errdefer pt.destroyNamespace(enum_tag_type_namespace); | ||
| 20602 | |||
| 20603 | wip_ty.setTagType(ip, wip_tag_ty.index); | ||
| 20604 | |||
| 20605 | break :generated_tag wip_tag_ty.finish(ip, enum_tag_type_namespace); | ||
| 20606 | }; | ||
| 20607 | // If we fail to create the union type, we must delete the generated enum tag type, since it | ||
| 20608 | // would hold a reference to the deleted union. | ||
| 20609 | errdefer if (generated_tag_ty != .none) ip.remove(pt.tid, generated_tag_ty); | ||
| 20610 | |||
| 20611 | for (0..fields_len) |field_idx| { | ||
| 20612 | const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType(); | ||
| 20613 | const field_attrs = try sema.interpretBuiltinType( | ||
| 20614 | block, | ||
| 20615 | field_attrs_src, | ||
| 20616 | try field_attrs_arr.elemValue(pt, field_idx), | ||
| 20617 | std.builtin.Type.UnionField.Attributes, | ||
| 20618 | ); | ||
| 20619 | 20476 | ||
| 20620 | if (field_ty.zigTypeTag(zcu) == .@"opaque") { | 20477 | const new_namespace_index = try pt.createNamespace(.{ |
| 20621 | return sema.failWithOwnedErrorMsg(block, msg: { | 20478 | .parent = block.namespace.toOptional(), |
| 20622 | const msg = try sema.errMsg(field_types_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{}); | 20479 | .owner_type = wip.index, |
| 20623 | errdefer msg.destroy(gpa); | 20480 | .file_scope = block.getFileScopeIndex(zcu), |
| 20624 | try sema.addDeclaredHereNote(msg, field_ty); | 20481 | .generation = zcu.generation, |
| 20625 | break :msg msg; | ||
| 20626 | }); | 20482 | }); |
| 20627 | } | 20483 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); |
| 20628 | 20484 | try sema.addTypeReferenceEntry(src, .fromInterned(wip.index)); | |
| 20629 | switch (layout) { | ||
| 20630 | .auto => {}, | ||
| 20631 | .@"extern" => if (!try sema.validateExternType(field_ty, .union_field)) { | ||
| 20632 | return sema.failWithOwnedErrorMsg(block, msg: { | ||
| 20633 | const msg = try sema.errMsg(field_types_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | ||
| 20634 | errdefer msg.destroy(gpa); | ||
| 20635 | |||
| 20636 | try sema.explainWhyTypeIsNotExtern(msg, field_types_src, field_ty, .union_field); | ||
| 20637 | |||
| 20638 | try sema.addDeclaredHereNote(msg, field_ty); | ||
| 20639 | break :msg msg; | ||
| 20640 | }); | ||
| 20641 | }, | ||
| 20642 | .@"packed" => if (!field_ty.packable(zcu)) { | ||
| 20643 | return sema.failWithOwnedErrorMsg(block, msg: { | ||
| 20644 | const msg = try sema.errMsg(field_types_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | ||
| 20645 | errdefer msg.destroy(gpa); | ||
| 20646 | |||
| 20647 | try sema.explainWhyTypeIsNotPackable(msg, field_types_src, field_ty); | ||
| 20648 | |||
| 20649 | try sema.addDeclaredHereNote(msg, field_ty); | ||
| 20650 | break :msg msg; | ||
| 20651 | }); | ||
| 20652 | }, | ||
| 20653 | } | ||
| 20654 | |||
| 20655 | loaded_union.field_types.get(ip)[field_idx] = field_ty.toIntern(); | ||
| 20656 | if (field_attrs.@"align") |bytes| { | ||
| 20657 | assert(layout != .@"packed"); | ||
| 20658 | const a = try sema.validateAlign(block, field_attrs_src, bytes); | ||
| 20659 | loaded_union.field_aligns.get(ip)[field_idx] = a; | ||
| 20660 | } else if (any_aligned_fields) { | ||
| 20661 | assert(layout != .@"packed"); | ||
| 20662 | loaded_union.field_aligns.get(ip)[field_idx] = .none; | ||
| 20663 | } | ||
| 20664 | } | ||
| 20665 | 20485 | ||
| 20666 | if (layout == .@"packed") { | 20486 | // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind |
| 20667 | try type_resolution.resolvePackedUnionBackingInt( | 20487 | try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) }); |
| 20668 | sema, | ||
| 20669 | block, | ||
| 20670 | .fromInterned(wip_ty.index), | ||
| 20671 | &loaded_union, | ||
| 20672 | true, | ||
| 20673 | ); | ||
| 20674 | } else { | ||
| 20675 | try type_resolution.finishUnionLayout( | ||
| 20676 | sema, | ||
| 20677 | block, | ||
| 20678 | src, | ||
| 20679 | wip_ty.index, | ||
| 20680 | &loaded_union, | ||
| 20681 | explicit_tag_ty orelse .fromInterned(generated_tag_ty), | ||
| 20682 | ); | ||
| 20683 | } | ||
| 20684 | 20488 | ||
| 20685 | const new_namespace_index = try pt.createNamespace(.{ | 20489 | try zcu.outdated.ensureUnusedCapacity(gpa, 1); |
| 20686 | .parent = block.namespace.toOptional(), | 20490 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); |
| 20687 | .owner_type = wip_ty.index, | 20491 | errdefer comptime unreachable; // because we don't remove the `outdated` entry |
| 20688 | .file_scope = block.getFileScopeIndex(zcu), | 20492 | zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); |
| 20689 | .generation = zcu.generation, | 20493 | zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); |
| 20690 | }); | ||
| 20691 | 20494 | ||
| 20692 | codegen_type: { | 20495 | return .fromIntern(wip.finish(ip, new_namespace_index)); |
| 20693 | if (zcu.comp.config.use_llvm) break :codegen_type; | 20496 | }, |
| 20694 | if (block.ownerModule().strip) break :codegen_type; | ||
| 20695 | zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); | ||
| 20696 | try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); | ||
| 20697 | } | ||
| 20698 | try sema.addTypeReferenceEntry(src, .fromInterned(wip_ty.index)); | ||
| 20699 | if (zcu.comp.debugIncremental()) { | ||
| 20700 | try zcu.incremental_debug_state.newType(zcu, wip_ty.index); | ||
| 20701 | } | 20497 | } |
| 20702 | return .fromIntern(wip_ty.finish(ip, new_namespace_index)); | ||
| 20703 | } | 20498 | } |
| 20704 | 20499 | ||
| 20705 | fn zirReifyEnum( | 20500 | fn zirReifyEnum( |
| ... | @@ -20754,10 +20549,10 @@ fn zirReifyEnum( | ... | @@ -20754,10 +20549,10 @@ fn zirReifyEnum( |
| 20754 | 20549 | ||
| 20755 | const enum_mode_ty = try sema.getBuiltinType(mode_src, .@"Type.Enum.Mode"); | 20550 | const enum_mode_ty = try sema.getBuiltinType(mode_src, .@"Type.Enum.Mode"); |
| 20756 | 20551 | ||
| 20757 | const tag_ty = try sema.resolveType(block, tag_ty_src, extra.tag_ty); | 20552 | const tag_ty_uncoerced = try sema.resolveInst(extra.tag_ty); |
| 20758 | if (tag_ty.zigTypeTag(zcu) != .int) { | 20553 | const tag_ty_coerced = try sema.coerce(block, .type, tag_ty_uncoerced, tag_ty_src); |
| 20759 | return sema.fail(block, tag_ty_src, "tag type must be an integer type", .{}); | 20554 | const tag_ty_val = try sema.resolveConstDefinedValue(block, tag_ty_src, tag_ty_coerced, .{ .simple = .enum_int_tag_type }); |
| 20760 | } | 20555 | const tag_ty = tag_ty_val.toType(); |
| 20761 | 20556 | ||
| 20762 | const mode_uncoerced = try sema.resolveInst(extra.mode); | 20557 | const mode_uncoerced = try sema.resolveInst(extra.mode); |
| 20763 | const mode_coerced = try sema.coerce(block, enum_mode_ty, mode_uncoerced, mode_src); | 20558 | const mode_coerced = try sema.coerce(block, enum_mode_ty, mode_uncoerced, mode_src); |
| ... | @@ -20790,11 +20585,13 @@ fn zirReifyEnum( | ... | @@ -20790,11 +20585,13 @@ fn zirReifyEnum( |
| 20790 | } | 20585 | } |
| 20791 | // We don't need to check `field_names_arr`, because `sliceToIpString` will check that for us. | 20586 | // We don't need to check `field_names_arr`, because `sliceToIpString` will check that for us. |
| 20792 | 20587 | ||
| 20793 | // The validation work here is non-trivial, and it's possible the type already exists. | 20588 | // Most validation of this type happens during type resolution. We basically need to do the work |
| 20794 | // So in this first pass, let's just construct a hash to optimize for this case. If the | 20589 | // which AstGen would normally do. An exception is checking for duplicate field names, which is |
| 20795 | // inputs turn out to be invalid, we can cancel the WIP type later. | 20590 | // handled by type resolution---it just simplifies some logic a little. |
| 20591 | |||
| 20592 | // As well as validation, we're going to gather some information about the fields, and construct | ||
| 20593 | // a hash representing the inputs for deduplication purposes. | ||
| 20796 | 20594 | ||
| 20797 | // For deduplication purposes, we must create a hash including all details of this type. | ||
| 20798 | // TODO: use a longer hash! | 20595 | // TODO: use a longer hash! |
| 20799 | var hasher = std.hash.Wyhash.init(0); | 20596 | var hasher = std.hash.Wyhash.init(0); |
| 20800 | std.hash.autoHash(&hasher, tag_ty.toIntern()); | 20597 | std.hash.autoHash(&hasher, tag_ty.toIntern()); |
| ... | @@ -20810,85 +20607,55 @@ fn zirReifyEnum( | ... | @@ -20810,85 +20607,55 @@ fn zirReifyEnum( |
| 20810 | std.hash.autoHash(&hasher, field_name); | 20607 | std.hash.autoHash(&hasher, field_name); |
| 20811 | } | 20608 | } |
| 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 | .fields_len = @intCast(fields_len), | 20613 | .fields_len = @intCast(fields_len), |
| 20815 | .explicit_int_tag_type = tag_ty.toIntern(), | ||
| 20816 | .nonexhaustive = nonexhaustive, | 20614 | .nonexhaustive = nonexhaustive, |
| 20817 | .key = .{ .reified = .{ | 20615 | .int_tag_type = tag_ty.toIntern(), |
| 20818 | .zir_index = tracked_inst, | ||
| 20819 | .type_hash = hasher.final(), | ||
| 20820 | } }, | ||
| 20821 | })) { | 20616 | })) { |
| 20822 | .wip => |wip| wip, | ||
| 20823 | .existing => |ty| { | 20617 | .existing => |ty| { |
| 20824 | try sema.addTypeReferenceEntry(src, .fromInterned(ty)); | 20618 | try sema.addTypeReferenceEntry(src, .fromInterned(ty)); |
| 20825 | return .fromIntern(ty); | 20619 | return .fromIntern(ty); |
| 20826 | }, | 20620 | }, |
| 20827 | }; | 20621 | .wip => |wip| { |
| 20828 | errdefer wip_ty.cancel(ip, pt.tid); | 20622 | errdefer wip.cancel(ip, pt.tid); |
| 20829 | 20623 | ||
| 20830 | _ = try (try sema.createTypeName( | 20624 | try sema.setTypeName(block, &wip, name_strategy, "enum", inst); |
| 20831 | block, | ||
| 20832 | name_strategy, | ||
| 20833 | "enum", | ||
| 20834 | inst, | ||
| 20835 | )).apply(&wip_ty, pt); | ||
| 20836 | 20625 | ||
| 20837 | for (0..fields_len) |field_idx| { | 20626 | // Populate field names and values. Duplicate checking will be handled by type resolution. |
| 20838 | const field_name_val = try field_names_arr.elemValue(pt, field_idx); | 20627 | for (0..fields_len) |field_index| { |
| 20839 | // Don't pass a reason; first loop acts as a check that this is valid. | 20628 | const field_name_val = try field_names_arr.elemValue(pt, field_index); |
| 20840 | const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined); | 20629 | // No source location or reason; first loop checked this is valid. |
| 20841 | if (wip_ty.nextField(ip, field_name, false)) |prev_field_idx| return sema.failWithOwnedErrorMsg(block, msg: { | 20630 | const field_name = try sema.sliceToIpString(block, .unneeded, field_name_val, undefined); |
| 20842 | const msg = try sema.errMsg(field_names_src, "duplicate enum field '{f}' at index '{d}'", .{ field_name.fmt(ip), field_idx }); | 20631 | wip.field_names.get(ip)[field_index] = field_name; |
| 20843 | errdefer msg.destroy(gpa); | ||
| 20844 | try sema.errNote(field_names_src, msg, "previous field at index '{d}'", .{prev_field_idx}); | ||
| 20845 | break :msg msg; | ||
| 20846 | }); | ||
| 20847 | } | ||
| 20848 | 20632 | ||
| 20849 | const enum_obj = ip.loadEnumType(wip_ty.index); | 20633 | const field_val = try field_values_arr.elemValue(pt, field_index); |
| 20850 | const field_value_map = enum_obj.field_value_map.unwrap().?; | 20634 | wip.field_values.get(ip)[field_index] = field_val.toIntern(); |
| 20851 | for (0..fields_len) |field_idx| { | 20635 | } |
| 20852 | const field_val = try field_values_arr.elemValue(pt, field_idx); | 20636 | |
| 20853 | const field_values = enum_obj.field_values.get(ip); | 20637 | const new_namespace_index = try pt.createNamespace(.{ |
| 20854 | field_values[field_idx] = field_val.toIntern(); | 20638 | .parent = block.namespace.toOptional(), |
| 20855 | const adapter: InternPool.Index.Adapter = .{ .indexes = field_values[0..field_idx] }; | 20639 | .owner_type = wip.index, |
| 20856 | const gop = field_value_map.get(ip).getOrPutAssumeCapacityAdapted(field_val.toIntern(), adapter); | 20640 | .file_scope = block.getFileScopeIndex(zcu), |
| 20857 | if (gop.found_existing) return sema.failWithOwnedErrorMsg(block, msg: { | 20641 | .generation = zcu.generation, |
| 20858 | const field_names = enum_obj.field_names.get(ip); | ||
| 20859 | const this_field_name = field_names[field_idx]; | ||
| 20860 | const prev_field_name = field_names[gop.index]; | ||
| 20861 | const msg = try sema.errMsg(field_names_src, "duplicate enum tag value '{f}' in field '{f}'", .{ | ||
| 20862 | field_val.fmtValueSema(pt, sema), | ||
| 20863 | this_field_name.fmt(ip), | ||
| 20864 | }); | 20642 | }); |
| 20865 | errdefer msg.destroy(gpa); | ||
| 20866 | try sema.errNote(field_names_src, msg, "previous usage in field '{f}'", .{prev_field_name.fmt(ip)}); | ||
| 20867 | break :msg msg; | ||
| 20868 | }); | ||
| 20869 | } | ||
| 20870 | 20643 | ||
| 20871 | if (nonexhaustive and fields_len > 1 and std.math.log2_int(u64, fields_len) == tag_ty.bitSize(zcu)) { | 20644 | try sema.addTypeReferenceEntry(src, .fromInterned(wip.index)); |
| 20872 | return sema.fail(block, src, "non-exhaustive enum specified every value", .{}); | 20645 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); |
| 20873 | } | ||
| 20874 | 20646 | ||
| 20875 | const new_namespace_index = try pt.createNamespace(.{ | 20647 | // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind |
| 20876 | .parent = block.namespace.toOptional(), | 20648 | try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) }); |
| 20877 | .owner_type = wip_ty.index, | ||
| 20878 | .file_scope = block.getFileScopeIndex(zcu), | ||
| 20879 | .generation = zcu.generation, | ||
| 20880 | }); | ||
| 20881 | 20649 | ||
| 20882 | codegen_type: { | 20650 | try zcu.outdated.ensureUnusedCapacity(gpa, 1); |
| 20883 | if (zcu.comp.config.use_llvm) break :codegen_type; | 20651 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); |
| 20884 | if (block.ownerModule().strip) break :codegen_type; | 20652 | errdefer comptime unreachable; // because we don't remove the `outdated` entry |
| 20885 | zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); | 20653 | zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); |
| 20886 | try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); | 20654 | zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); |
| 20887 | } | ||
| 20888 | 20655 | ||
| 20889 | try sema.addTypeReferenceEntry(src, .fromInterned(wip_ty.index)); | 20656 | return .fromIntern(wip.finish(ip, new_namespace_index)); |
| 20890 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index); | 20657 | }, |
| 20891 | return .fromIntern(wip_ty.finish(ip, new_namespace_index)); | 20658 | } |
| 20892 | } | 20659 | } |
| 20893 | 20660 | ||
| 20894 | fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref { | 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,7 +20676,7 @@ fn zirCVaArg(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C |
| 20909 | const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.lhs); | 20676 | const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.lhs); |
| 20910 | const arg_ty = try sema.resolveType(block, ty_src, extra.rhs); | 20677 | const arg_ty = try sema.resolveType(block, ty_src, extra.rhs); |
| 20911 | 20678 | ||
| 20912 | if (!try sema.validateExternType(arg_ty, .param_ty)) { | 20679 | if (!arg_ty.validateExtern(.param_ty, sema.pt.zcu)) { |
| 20913 | const msg = msg: { | 20680 | const msg = msg: { |
| 20914 | const msg = try sema.errMsg(ty_src, "cannot get '{f}' from variadic argument", .{arg_ty.fmt(sema.pt)}); | 20681 | const msg = try sema.errMsg(ty_src, "cannot get '{f}' from variadic argument", .{arg_ty.fmt(sema.pt)}); |
| 20915 | errdefer msg.destroy(sema.gpa); | 20682 | errdefer msg.destroy(sema.gpa); |
| ... | @@ -24205,8 +23972,8 @@ fn zirMemcpy( | ... | @@ -24205,8 +23972,8 @@ fn zirMemcpy( |
| 24205 | return sema.failWithOwnedErrorMsg(block, msg); | 23972 | return sema.failWithOwnedErrorMsg(block, msg); |
| 24206 | } | 23973 | } |
| 24207 | 23974 | ||
| 24208 | const dest_elem_ty = dest_ty.indexablePtrElem(zcu); | 23975 | const dest_elem_ty = dest_ty.indexableElem(zcu); |
| 24209 | const src_elem_ty = src_ty.indexablePtrElem(zcu); | 23976 | const src_elem_ty = src_ty.indexableElem(zcu); |
| 24210 | 23977 | ||
| 24211 | try sema.ensureLayoutResolved(dest_elem_ty); | 23978 | try sema.ensureLayoutResolved(dest_elem_ty); |
| 24212 | try sema.ensureLayoutResolved(src_elem_ty); | 23979 | try sema.ensureLayoutResolved(src_elem_ty); |
| ... | @@ -24906,7 +24673,7 @@ fn zirBuiltinExtern( | ... | @@ -24906,7 +24673,7 @@ fn zirBuiltinExtern( |
| 24906 | if (!ty.isPtrAtRuntime(zcu)) { | 24673 | if (!ty.isPtrAtRuntime(zcu)) { |
| 24907 | return sema.fail(block, ty_src, "expected (optional) pointer", .{}); | 24674 | return sema.fail(block, ty_src, "expected (optional) pointer", .{}); |
| 24908 | } | 24675 | } |
| 24909 | if (!try sema.validateExternType(ty, .other)) { | 24676 | if (!ty.validateExtern(.other, zcu)) { |
| 24910 | const msg = msg: { | 24677 | const msg = msg: { |
| 24911 | const msg = try sema.errMsg(ty_src, "extern symbol cannot have type '{f}'", .{ty.fmt(pt)}); | 24678 | const msg = try sema.errMsg(ty_src, "extern symbol cannot have type '{f}'", .{ty.fmt(pt)}); |
| 24912 | errdefer msg.destroy(sema.gpa); | 24679 | errdefer msg.destroy(sema.gpa); |
| ... | @@ -24954,7 +24721,7 @@ fn zirBuiltinExtern( | ... | @@ -24954,7 +24721,7 @@ fn zirBuiltinExtern( |
| 24954 | // So, for now, just use our containing `declaration`. | 24721 | // So, for now, just use our containing `declaration`. |
| 24955 | .zir_index = switch (sema.owner.unwrap()) { | 24722 | .zir_index = switch (sema.owner.unwrap()) { |
| 24956 | .@"comptime" => |cu| ip.getComptimeUnit(cu).zir_index, | 24723 | .@"comptime" => |cu| ip.getComptimeUnit(cu).zir_index, |
| 24957 | .type_layout, .type_inits => |owner_ty| Type.fromInterned(owner_ty).typeDeclInstAllowGeneratedTag(zcu).?, | 24724 | .type_layout, .struct_defaults => |owner_ty| Type.fromInterned(owner_ty).typeDeclInstAllowGeneratedTag(zcu).?, |
| 24958 | .memoized_state => unreachable, | 24725 | .memoized_state => unreachable, |
| 24959 | .nav_ty, .nav_val => |nav| ip.getNav(nav).analysis.?.zir_index, | 24726 | .nav_ty, .nav_val => |nav| ip.getNav(nav).analysis.?.zir_index, |
| 24960 | .func => |func| zir_index: { | 24727 | .func => |func| zir_index: { |
| ... | @@ -25060,6 +24827,7 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD | ... | @@ -25060,6 +24827,7 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD |
| 25060 | // Values are handled here. | 24827 | // Values are handled here. |
| 25061 | .calling_convention_c => { | 24828 | .calling_convention_c => { |
| 25062 | const callconv_ty = try sema.getBuiltinType(src, .CallingConvention); | 24829 | const callconv_ty = try sema.getBuiltinType(src, .CallingConvention); |
| 24830 | // Cannot use `Value.uninterpret` because `c` is a *declaration* whose value depends on the target. | ||
| 25063 | return try sema.namespaceLookupVal( | 24831 | return try sema.namespaceLookupVal( |
| 25064 | block, | 24832 | block, |
| 25065 | src, | 24833 | src, |
| ... | @@ -25068,17 +24836,15 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD | ... | @@ -25068,17 +24836,15 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD |
| 25068 | ) orelse @panic("std.builtin is corrupt"); | 24836 | ) orelse @panic("std.builtin is corrupt"); |
| 25069 | }, | 24837 | }, |
| 25070 | .calling_convention_inline => { | 24838 | .calling_convention_inline => { |
| 25071 | comptime assert(@typeInfo(std.builtin.CallingConvention.Tag).@"enum".tag_type == u8); | ||
| 25072 | const callconv_ty = try sema.getBuiltinType(src, .CallingConvention); | 24839 | const callconv_ty = try sema.getBuiltinType(src, .CallingConvention); |
| 25073 | const callconv_tag_ty = callconv_ty.unionTagType(zcu) orelse @panic("std.builtin is corrupt"); | 24840 | return .fromValue(Value.uninterpret( |
| 25074 | const inline_tag_val = try pt.enumValue( | 24841 | @as(std.builtin.CallingConvention, .@"inline"), |
| 25075 | callconv_tag_ty, | 24842 | callconv_ty, |
| 25076 | (try pt.intValue( | 24843 | pt, |
| 25077 | .u8, | 24844 | ) catch |err| switch (err) { |
| 25078 | @intFromEnum(std.builtin.CallingConvention.@"inline"), | 24845 | error.TypeMismatch => @panic("std.builtin is corrupt"), |
| 25079 | )).toIntern(), | 24846 | error.OutOfMemory => |e| return e, |
| 25080 | ); | 24847 | }); |
| 25081 | return sema.coerce(block, callconv_ty, Air.internedToRef(inline_tag_val.toIntern()), src); | ||
| 25082 | }, | 24848 | }, |
| 25083 | }; | 24849 | }; |
| 25084 | return .fromType(try sema.getBuiltinType(src, builtin_type)); | 24850 | return .fromType(try sema.getBuiltinType(src, builtin_type)); |
| ... | @@ -25180,7 +24946,7 @@ pub fn validateVarType( | ... | @@ -25180,7 +24946,7 @@ pub fn validateVarType( |
| 25180 | const zcu = pt.zcu; | 24946 | const zcu = pt.zcu; |
| 25181 | var_ty.assertHasLayout(zcu); | 24947 | var_ty.assertHasLayout(zcu); |
| 25182 | if (is_extern) { | 24948 | if (is_extern) { |
| 25183 | if (!try sema.validateExternType(var_ty, .other)) { | 24949 | if (!var_ty.validateExtern(.other, zcu)) { |
| 25184 | const msg = msg: { | 24950 | const msg = msg: { |
| 25185 | const msg = try sema.errMsg(src, "extern variable cannot have type '{f}'", .{var_ty.fmt(pt)}); | 24951 | const msg = try sema.errMsg(src, "extern variable cannot have type '{f}'", .{var_ty.fmt(pt)}); |
| 25186 | errdefer msg.destroy(sema.gpa); | 24952 | errdefer msg.destroy(sema.gpa); |
| ... | @@ -25296,124 +25062,17 @@ fn explainWhyTypeIsComptime( | ... | @@ -25296,124 +25062,17 @@ fn explainWhyTypeIsComptime( |
| 25296 | } | 25062 | } |
| 25297 | } | 25063 | } |
| 25298 | 25064 | ||
| 25299 | const ExternPosition = enum { | 25065 | /// Keep in sync with `Type.validateExtern`. |
| 25300 | ret_ty, | ||
| 25301 | param_ty, | ||
| 25302 | union_field, | ||
| 25303 | struct_field, | ||
| 25304 | element, | ||
| 25305 | other, | ||
| 25306 | }; | ||
| 25307 | |||
| 25308 | /// Returns true if `ty` is allowed in extern types. | ||
| 25309 | /// Does not require `ty` to be resolved in any way. | ||
| 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 | |||
| 25401 | pub fn explainWhyTypeIsNotExtern( | 25066 | pub fn explainWhyTypeIsNotExtern( |
| 25402 | sema: *Sema, | 25067 | sema: *Sema, |
| 25403 | msg: *Zcu.ErrorMsg, | 25068 | msg: *Zcu.ErrorMsg, |
| 25404 | src_loc: LazySrcLoc, | 25069 | src_loc: LazySrcLoc, |
| 25405 | ty: Type, | 25070 | ty: Type, |
| 25406 | position: ExternPosition, | 25071 | position: Type.ExternPosition, |
| 25407 | ) CompileError!void { | 25072 | ) CompileError!void { |
| 25408 | const pt = sema.pt; | 25073 | const pt = sema.pt; |
| 25409 | const zcu = pt.zcu; | 25074 | const zcu = pt.zcu; |
| 25410 | switch (ty.zigTypeTag(zcu)) { | 25075 | switch (ty.zigTypeTag(zcu)) { |
| 25411 | .@"opaque", | ||
| 25412 | .bool, | ||
| 25413 | .float, | ||
| 25414 | .@"anyframe", | ||
| 25415 | => return, | ||
| 25416 | |||
| 25417 | .type, | 25076 | .type, |
| 25418 | .comptime_float, | 25077 | .comptime_float, |
| 25419 | .comptime_int, | 25078 | .comptime_int, |
| ... | @@ -25425,101 +25084,110 @@ pub fn explainWhyTypeIsNotExtern( | ... | @@ -25425,101 +25084,110 @@ pub fn explainWhyTypeIsNotExtern( |
| 25425 | .frame, | 25084 | .frame, |
| 25426 | => return, | 25085 | => return, |
| 25427 | 25086 | ||
| 25428 | .pointer => { | 25087 | .void => try sema.errNote(src_loc, msg, "'void' is a zero bit type", .{}), |
| 25429 | if (ty.isSlice(zcu)) { | 25088 | .noreturn => try sema.errNote(src_loc, msg, "'noreturn' is only allowed as a return type", .{}), |
| 25430 | try sema.errNote(src_loc, msg, "slices have no guaranteed in-memory representation", .{}); | 25089 | |
| 25090 | .@"opaque", | ||
| 25091 | .bool, | ||
| 25092 | .float, | ||
| 25093 | .@"anyframe", | ||
| 25094 | => unreachable, // these *are* allowed | ||
| 25095 | |||
| 25096 | .pointer => if (ty.isSlice(zcu)) { | ||
| 25097 | try sema.errNote(src_loc, msg, "slices have no guaranteed in-memory representation", .{}); | ||
| 25098 | } else { | ||
| 25099 | assert(ty.childType(zcu).zigTypeTag(zcu) == .@"fn"); | ||
| 25100 | if (!ty.isConstPtr(zcu)) { | ||
| 25101 | try sema.errNote(src_loc, msg, "pointer to extern function must be 'const'", .{}); | ||
| 25431 | } else { | 25102 | } else { |
| 25432 | const pointee_ty = ty.childType(zcu); | 25103 | try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.childType(zcu), .other); |
| 25433 | if (!ty.isConstPtr(zcu) and pointee_ty.zigTypeTag(zcu) == .@"fn") { | ||
| 25434 | try sema.errNote(src_loc, msg, "pointer to extern function must be 'const'", .{}); | ||
| 25435 | } | ||
| 25436 | try sema.explainWhyTypeIsNotExtern(msg, src_loc, pointee_ty, .other); | ||
| 25437 | } | 25104 | } |
| 25438 | }, | 25105 | }, |
| 25439 | .void => try sema.errNote(src_loc, msg, "'void' is a zero bit type; for C 'void' use 'anyopaque'", .{}), | ||
| 25440 | .noreturn => try sema.errNote(src_loc, msg, "'noreturn' is only allowed as a return type", .{}), | ||
| 25441 | .int => if (!std.math.isPowerOfTwo(ty.intInfo(zcu).bits)) { | 25106 | .int => if (!std.math.isPowerOfTwo(ty.intInfo(zcu).bits)) { |
| 25442 | try sema.errNote(src_loc, msg, "only integers with 0 or power of two bits are extern compatible", .{}); | 25107 | try sema.errNote(src_loc, msg, "only integers with 0 or power of two bits are extern compatible", .{}); |
| 25443 | } else { | 25108 | } else { |
| 25444 | try sema.errNote(src_loc, msg, "only integers with 0, 8, 16, 32, 64 and 128 bits are extern compatible", .{}); | 25109 | try sema.errNote(src_loc, msg, "only integers with 0, 8, 16, 32, 64 and 128 bits are extern compatible", .{}); |
| 25445 | }, | 25110 | }, |
| 25446 | .@"fn" => { | 25111 | .@"fn" => if (position != .other) { |
| 25447 | if (position != .other) { | 25112 | try sema.errNote(src_loc, msg, "type has no guaranteed in-memory representation", .{}); |
| 25448 | try sema.errNote(src_loc, msg, "type has no guaranteed in-memory representation", .{}); | 25113 | try sema.errNote(src_loc, msg, "use '*const ' to make a function pointer type", .{}); |
| 25449 | try sema.errNote(src_loc, msg, "use '*const ' to make a function pointer type", .{}); | 25114 | } else switch (ty.fnCallingConvention(zcu)) { |
| 25450 | return; | 25115 | .auto => try sema.errNote(src_loc, msg, "extern function must specify calling convention", .{}), |
| 25451 | } | 25116 | else => |cc| try sema.errNote(src_loc, msg, "{t} function cannot be extern", .{cc}), |
| 25452 | switch (ty.fnCallingConvention(zcu)) { | ||
| 25453 | .auto => try sema.errNote(src_loc, msg, "extern function must specify calling convention", .{}), | ||
| 25454 | .async => try sema.errNote(src_loc, msg, "async function cannot be extern", .{}), | ||
| 25455 | .@"inline" => try sema.errNote(src_loc, msg, "inline function cannot be extern", .{}), | ||
| 25456 | else => return, | ||
| 25457 | } | ||
| 25458 | }, | 25117 | }, |
| 25459 | .@"enum" => { | 25118 | .@"enum" => { |
| 25460 | const tag_ty = ty.intTagType(zcu); | 25119 | const tag_ty = ty.intTagType(zcu); |
| 25461 | try sema.errNote(src_loc, msg, "enum tag type '{f}' is not extern compatible", .{tag_ty.fmt(pt)}); | 25120 | try sema.errNote(src_loc, msg, "enum tag type '{f}' is not extern compatible", .{tag_ty.fmt(pt)}); |
| 25462 | try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position); | 25121 | try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position); |
| 25463 | }, | 25122 | }, |
| 25464 | // MLUGG TODO: these notes are bad now (because ABI sized packed type also needs explicit backing type) | 25123 | .@"struct" => { |
| 25465 | .@"struct" => try sema.errNote(src_loc, msg, "only extern structs and ABI sized packed structs are extern compatible", .{}), | 25124 | const struct_obj = zcu.intern_pool.loadStructType(ty.toIntern()); |
| 25466 | .@"union" => try sema.errNote(src_loc, msg, "only extern unions and ABI sized packed unions are extern compatible", .{}), | 25125 | switch (struct_obj.layout) { |
| 25467 | .array => { | 25126 | .auto => try sema.errNote(src_loc, msg, "struct with automatic layout has no guaranteed in-memory representation", .{}), |
| 25468 | if (position == .ret_ty) { | 25127 | .@"extern" => unreachable, |
| 25469 | return sema.errNote(src_loc, msg, "arrays are not allowed as a return type", .{}); | 25128 | .@"packed" => switch (struct_obj.packed_backing_mode) { |
| 25470 | } else if (position == .param_ty) { | 25129 | .auto => try sema.errNote(src_loc, msg, "inferred backing integer of packed struct has unspecified signedness", .{}), |
| 25471 | return sema.errNote(src_loc, msg, "arrays are not allowed as a parameter type", .{}); | 25130 | .explicit => { |
| 25131 | const backing_int_ty: Type = .fromInterned(struct_obj.packed_backing_int_type); | ||
| 25132 | try sema.errNote(src_loc, msg, "packed struct backing integer type '{f}' is not extern compatible", .{backing_int_ty.fmt(pt)}); | ||
| 25133 | try sema.explainWhyTypeIsNotExtern(msg, src_loc, backing_int_ty, position); | ||
| 25134 | }, | ||
| 25135 | }, | ||
| 25136 | } | ||
| 25137 | }, | ||
| 25138 | .@"union" => { | ||
| 25139 | const union_obj = zcu.intern_pool.loadStructType(ty.toIntern()); | ||
| 25140 | switch (union_obj.layout) { | ||
| 25141 | .auto => try sema.errNote(src_loc, msg, "union with automatic layout has no guaranteed in-memory representation", .{}), | ||
| 25142 | .@"extern" => unreachable, | ||
| 25143 | .@"packed" => switch (union_obj.packed_backing_mode) { | ||
| 25144 | .auto => try sema.errNote(src_loc, msg, "inferred backing integer of packed union has unspecified signedness", .{}), | ||
| 25145 | .explicit => { | ||
| 25146 | const backing_int_ty: Type = .fromInterned(union_obj.packed_backing_int_type); | ||
| 25147 | try sema.errNote(src_loc, msg, "packed union backing integer type '{f}' is not extern compatible", .{backing_int_ty.fmt(pt)}); | ||
| 25148 | try sema.explainWhyTypeIsNotExtern(msg, src_loc, backing_int_ty, position); | ||
| 25149 | }, | ||
| 25150 | }, | ||
| 25472 | } | 25151 | } |
| 25473 | try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.childType(zcu), .element); | 25152 | }, |
| 25153 | .array => switch (position) { | ||
| 25154 | .ret_ty => try sema.errNote(src_loc, msg, "arrays are not allowed as a return type", .{}), | ||
| 25155 | .param_ty => try sema.errNote(src_loc, msg, "arrays are not allowed as a parameter type", .{}), | ||
| 25156 | else => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.childType(zcu), .element), | ||
| 25474 | }, | 25157 | }, |
| 25475 | .vector => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.childType(zcu), .element), | 25158 | .vector => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.childType(zcu), .element), |
| 25476 | .optional => try sema.errNote(src_loc, msg, "only pointer like optionals are extern compatible", .{}), | 25159 | .optional => try sema.errNote(src_loc, msg, "non-pointer optionals have no guaranteed in-memory representation", .{}), |
| 25477 | } | 25160 | } |
| 25478 | } | 25161 | } |
| 25479 | 25162 | ||
| 25480 | pub fn explainWhyTypeIsNotPackable( | 25163 | pub fn explainWhyTypeIsUnpackable( |
| 25481 | sema: *Sema, | 25164 | sema: *Sema, |
| 25482 | msg: *Zcu.ErrorMsg, | 25165 | msg: *Zcu.ErrorMsg, |
| 25483 | src_loc: LazySrcLoc, | 25166 | src: LazySrcLoc, |
| 25484 | ty: Type, | 25167 | reason: Type.UnpackableReason, |
| 25485 | ) CompileError!void { | 25168 | ) CompileError!void { |
| 25486 | const pt = sema.pt; | 25169 | const pt = sema.pt; |
| 25487 | const zcu = pt.zcu; | 25170 | const zcu = pt.zcu; |
| 25488 | switch (ty.zigTypeTag(zcu)) { | 25171 | switch (reason) { |
| 25489 | .void, | 25172 | .comptime_only => try sema.errNote(src, msg, "comptime-only types have no bit-packed representation", .{}), |
| 25490 | .bool, | 25173 | .pointer => { |
| 25491 | .float, | 25174 | try sema.errNote(src, msg, "pointers cannot be directly bitpacked", .{}); |
| 25492 | .int, | 25175 | try sema.errNote(src, msg, "consider using 'usize' and '@intFromPtr'", .{}); |
| 25493 | .vector, | ||
| 25494 | .@"enum", | ||
| 25495 | => return, | ||
| 25496 | .type, | ||
| 25497 | .comptime_float, | ||
| 25498 | .comptime_int, | ||
| 25499 | .enum_literal, | ||
| 25500 | .undefined, | ||
| 25501 | .null, | ||
| 25502 | .frame, | ||
| 25503 | .noreturn, | ||
| 25504 | .@"opaque", | ||
| 25505 | .error_union, | ||
| 25506 | .error_set, | ||
| 25507 | .@"anyframe", | ||
| 25508 | .optional, | ||
| 25509 | .array, | ||
| 25510 | => try sema.errNote(src_loc, msg, "type has no guaranteed in-memory representation", .{}), | ||
| 25511 | .pointer => if (ty.isSlice(zcu)) { | ||
| 25512 | try sema.errNote(src_loc, msg, "slices have no guaranteed in-memory representation", .{}); | ||
| 25513 | } else { | ||
| 25514 | try sema.errNote(src_loc, msg, "comptime-only pointer has no guaranteed in-memory representation", .{}); | ||
| 25515 | try sema.explainWhyTypeIsComptime(msg, src_loc, ty); | ||
| 25516 | }, | 25176 | }, |
| 25517 | .@"fn" => { | 25177 | .enum_inferred_int_tag => |enum_ty| { |
| 25518 | try sema.errNote(src_loc, msg, "type has no guaranteed in-memory representation", .{}); | 25178 | const enum_src = enum_ty.srcLoc(zcu); |
| 25519 | try sema.errNote(src_loc, msg, "use '*const ' to make a function pointer type", .{}); | 25179 | try sema.errNote(enum_src, msg, "integer tag type of enum is inferred", .{}); |
| 25180 | try sema.errNote(enum_src, msg, "consider explicitly specifying the integer tag type", .{}); | ||
| 25181 | }, | ||
| 25182 | .non_packed_struct => |struct_ty| { | ||
| 25183 | try sema.errNote(src, msg, "non-packed structs do not have a bit-packed representation", .{}); | ||
| 25184 | try sema.addDeclaredHereNote(msg, struct_ty); | ||
| 25185 | }, | ||
| 25186 | .non_packed_union => |union_ty| { | ||
| 25187 | try sema.errNote(src, msg, "non-packed unions do not have a bit-packed representation", .{}); | ||
| 25188 | try sema.addDeclaredHereNote(msg, union_ty); | ||
| 25520 | }, | 25189 | }, |
| 25521 | .@"struct" => try sema.errNote(src_loc, msg, "struct in packed type must have packed layout", .{}), | 25190 | .other => try sema.errNote(src, msg, "type does not have a bit-packed representation", .{}), |
| 25522 | .@"union" => try sema.errNote(src_loc, msg, "union in packed type must have packed layout", .{}), | ||
| 25523 | } | 25191 | } |
| 25524 | } | 25192 | } |
| 25525 | 25193 | ||
| ... | @@ -25545,7 +25213,7 @@ fn getPanicIdFunc(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.SimplePanicId) !In | ... | @@ -25545,7 +25213,7 @@ fn getPanicIdFunc(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.SimplePanicId) !In |
| 25545 | try sema.ensureMemoizedStateResolved(src, .panic); | 25213 | try sema.ensureMemoizedStateResolved(src, .panic); |
| 25546 | const panic_fn_index = zcu.builtin_decl_values.get(panic_id.toBuiltin()); | 25214 | const panic_fn_index = zcu.builtin_decl_values.get(panic_id.toBuiltin()); |
| 25547 | switch (sema.owner.unwrap()) { | 25215 | switch (sema.owner.unwrap()) { |
| 25548 | .@"comptime", .nav_ty, .nav_val, .type_layout, .type_inits, .memoized_state => {}, | 25216 | .@"comptime", .nav_ty, .nav_val, .type_layout, .struct_defaults, .memoized_state => {}, |
| 25549 | .func => |owner_func| zcu.intern_pool.funcSetHasErrorTrace(io, owner_func, true), | 25217 | .func => |owner_func| zcu.intern_pool.funcSetHasErrorTrace(io, owner_func, true), |
| 25550 | } | 25218 | } |
| 25551 | return panic_fn_index; | 25219 | return panic_fn_index; |
| ... | @@ -25962,6 +25630,7 @@ fn fieldVal( | ... | @@ -25962,6 +25630,7 @@ fn fieldVal( |
| 25962 | if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| { | 25630 | if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| { |
| 25963 | return inst; | 25631 | return inst; |
| 25964 | } | 25632 | } |
| 25633 | try sema.ensureLayoutResolved(child_type); | ||
| 25965 | if (child_type.unionTagType(zcu)) |enum_ty| { | 25634 | if (child_type.unionTagType(zcu)) |enum_ty| { |
| 25966 | if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index_usize| { | 25635 | if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index_usize| { |
| 25967 | const field_index: u32 = @intCast(field_index_usize); | 25636 | const field_index: u32 = @intCast(field_index_usize); |
| ... | @@ -25974,6 +25643,7 @@ fn fieldVal( | ... | @@ -25974,6 +25643,7 @@ fn fieldVal( |
| 25974 | if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| { | 25643 | if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| { |
| 25975 | return inst; | 25644 | return inst; |
| 25976 | } | 25645 | } |
| 25646 | try sema.ensureLayoutResolved(child_type); | ||
| 25977 | const field_index_usize = child_type.enumFieldIndex(field_name, zcu) orelse | 25647 | const field_index_usize = child_type.enumFieldIndex(field_name, zcu) orelse |
| 25978 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); | 25648 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); |
| 25979 | const field_index: u32 = @intCast(field_index_usize); | 25649 | const field_index: u32 = @intCast(field_index_usize); |
| ... | @@ -26195,6 +25865,7 @@ fn fieldPtr( | ... | @@ -26195,6 +25865,7 @@ fn fieldPtr( |
| 26195 | if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| { | 25865 | if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| { |
| 26196 | return inst; | 25866 | return inst; |
| 26197 | } | 25867 | } |
| 25868 | try sema.ensureLayoutResolved(child_type); | ||
| 26198 | if (child_type.unionTagType(zcu)) |enum_ty| { | 25869 | if (child_type.unionTagType(zcu)) |enum_ty| { |
| 26199 | if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index| { | 25870 | if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index| { |
| 26200 | const field_index_u32: u32 = @intCast(field_index); | 25871 | const field_index_u32: u32 = @intCast(field_index); |
| ... | @@ -26208,6 +25879,7 @@ fn fieldPtr( | ... | @@ -26208,6 +25879,7 @@ fn fieldPtr( |
| 26208 | if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| { | 25879 | if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| { |
| 26209 | return inst; | 25880 | return inst; |
| 26210 | } | 25881 | } |
| 25882 | try sema.ensureLayoutResolved(child_type); | ||
| 26211 | const field_index = child_type.enumFieldIndex(field_name, zcu) orelse { | 25883 | const field_index = child_type.enumFieldIndex(field_name, zcu) orelse { |
| 26212 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); | 25884 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); |
| 26213 | }; | 25885 | }; |
| ... | @@ -26444,9 +26116,6 @@ fn finishFieldCallBind( | ... | @@ -26444,9 +26116,6 @@ fn finishFieldCallBind( |
| 26444 | const container_ty = ptr_ty.childType(zcu); | 26116 | const container_ty = ptr_ty.childType(zcu); |
| 26445 | if (container_ty.zigTypeTag(zcu) == .@"struct") { | 26117 | if (container_ty.zigTypeTag(zcu) == .@"struct") { |
| 26446 | if (container_ty.structFieldIsComptime(field_index, zcu)) { | 26118 | if (container_ty.structFieldIsComptime(field_index, zcu)) { |
| 26447 | if (!container_ty.isTuple(zcu)) { | ||
| 26448 | try sema.ensureFieldInitsResolved(container_ty); | ||
| 26449 | } | ||
| 26450 | const default_val = (try container_ty.structFieldValueComptime(pt, field_index)).?; | 26119 | const default_val = (try container_ty.structFieldValueComptime(pt, field_index)).?; |
| 26451 | return .{ .direct = Air.internedToRef(default_val.toIntern()) }; | 26120 | return .{ .direct = Air.internedToRef(default_val.toIntern()) }; |
| 26452 | } | 26121 | } |
| ... | @@ -26623,7 +26292,7 @@ fn structFieldPtrByIndex( | ... | @@ -26623,7 +26292,7 @@ fn structFieldPtrByIndex( |
| 26623 | const ptr_field_ty = try pt.ptrType(ptr_ty_data); | 26292 | const ptr_field_ty = try pt.ptrType(ptr_ty_data); |
| 26624 | 26293 | ||
| 26625 | if (field_is_comptime) { | 26294 | if (field_is_comptime) { |
| 26626 | try sema.ensureFieldInitsResolved(struct_ty); | 26295 | assert(struct_type.field_defaults.get(ip)[field_index] != .none); |
| 26627 | const val = try pt.intern(.{ .ptr = .{ | 26296 | const val = try pt.intern(.{ .ptr = .{ |
| 26628 | .ty = ptr_field_ty.toIntern(), | 26297 | .ty = ptr_field_ty.toIntern(), |
| 26629 | .base_addr = .{ .comptime_field = struct_type.field_defaults.get(ip)[field_index] }, | 26298 | .base_addr = .{ .comptime_field = struct_type.field_defaults.get(ip)[field_index] }, |
| ... | @@ -26647,6 +26316,8 @@ fn structFieldVal( | ... | @@ -26647,6 +26316,8 @@ fn structFieldVal( |
| 26647 | const zcu = pt.zcu; | 26316 | const zcu = pt.zcu; |
| 26648 | const ip = &zcu.intern_pool; | 26317 | const ip = &zcu.intern_pool; |
| 26649 | assert(struct_ty.zigTypeTag(zcu) == .@"struct"); | 26318 | assert(struct_ty.zigTypeTag(zcu) == .@"struct"); |
| 26319 | assert(sema.typeOf(struct_byval).toIntern() == struct_ty.toIntern()); | ||
| 26320 | struct_ty.assertHasLayout(zcu); | ||
| 26650 | 26321 | ||
| 26651 | switch (ip.indexToKey(struct_ty.toIntern())) { | 26322 | switch (ip.indexToKey(struct_ty.toIntern())) { |
| 26652 | .struct_type => { | 26323 | .struct_type => { |
| ... | @@ -26655,7 +26326,6 @@ fn structFieldVal( | ... | @@ -26655,7 +26326,6 @@ fn structFieldVal( |
| 26655 | const field_index = struct_type.nameIndex(ip, field_name) orelse | 26326 | const field_index = struct_type.nameIndex(ip, field_name) orelse |
| 26656 | return sema.failWithBadStructFieldAccess(block, struct_ty, struct_type, field_name_src, field_name); | 26327 | return sema.failWithBadStructFieldAccess(block, struct_ty, struct_type, field_name_src, field_name); |
| 26657 | if (struct_type.field_is_comptime_bits.get(ip, field_index)) { | 26328 | if (struct_type.field_is_comptime_bits.get(ip, field_index)) { |
| 26658 | try sema.ensureFieldInitsResolved(struct_ty); | ||
| 26659 | return .fromIntern(struct_type.field_defaults.get(ip)[field_index]); | 26329 | return .fromIntern(struct_type.field_defaults.get(ip)[field_index]); |
| 26660 | } | 26330 | } |
| 26661 | 26331 | ||
| ... | @@ -26886,6 +26556,8 @@ fn unionFieldVal( | ... | @@ -26886,6 +26556,8 @@ fn unionFieldVal( |
| 26886 | const zcu = pt.zcu; | 26556 | const zcu = pt.zcu; |
| 26887 | const ip = &zcu.intern_pool; | 26557 | const ip = &zcu.intern_pool; |
| 26888 | assert(union_ty.zigTypeTag(zcu) == .@"union"); | 26558 | assert(union_ty.zigTypeTag(zcu) == .@"union"); |
| 26559 | assert(sema.typeOf(union_byval).toIntern() == union_ty.toIntern()); | ||
| 26560 | union_ty.assertHasLayout(zcu); | ||
| 26889 | 26561 | ||
| 26890 | const union_obj = zcu.typeToUnion(union_ty).?; | 26562 | const union_obj = zcu.typeToUnion(union_ty).?; |
| 26891 | const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); | 26563 | const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); |
| ... | @@ -27149,11 +26821,11 @@ fn validateRuntimeElemAccess( | ... | @@ -27149,11 +26821,11 @@ fn validateRuntimeElemAccess( |
| 27149 | const msg = try sema.errMsg( | 26821 | const msg = try sema.errMsg( |
| 27150 | elem_index_src, | 26822 | elem_index_src, |
| 27151 | "values of type '{f}' must be comptime-known, but index value is runtime-known", | 26823 | "values of type '{f}' must be comptime-known, but index value is runtime-known", |
| 27152 | .{parent_ty.fmt(sema.pt)}, | 26824 | .{elem_ty.fmt(sema.pt)}, |
| 27153 | ); | 26825 | ); |
| 27154 | errdefer msg.destroy(sema.gpa); | 26826 | errdefer msg.destroy(sema.gpa); |
| 27155 | 26827 | ||
| 27156 | try sema.explainWhyTypeIsComptime(msg, parent_src, parent_ty); | 26828 | try sema.explainWhyTypeIsComptime(msg, parent_src, elem_ty); |
| 27157 | 26829 | ||
| 27158 | break :msg msg; | 26830 | break :msg msg; |
| 27159 | }; | 26831 | }; |
| ... | @@ -27885,18 +27557,14 @@ fn coerceExtra( | ... | @@ -27885,18 +27557,14 @@ fn coerceExtra( |
| 27885 | // empty tuple to zero-length slice | 27557 | // empty tuple to zero-length slice |
| 27886 | // note that this allows coercing to a mutable slice. | 27558 | // note that this allows coercing to a mutable slice. |
| 27887 | if (inst_child_ty.structFieldCount(zcu) == 0) { | 27559 | if (inst_child_ty.structFieldCount(zcu) == 0) { |
| 27888 | // TODO MLUGG: this is *unacceptably* stupid. we're resolving the child for the alignment value | 27560 | const empty_array_ty = try pt.arrayType(.{ |
| 27889 | try sema.ensureLayoutResolved(dest_ty.childType(zcu)); | 27561 | .len = 0, |
| 27890 | const align_val = dest_ty.ptrAlignment(zcu); | 27562 | .child = dest_info.child, |
| 27891 | return Air.internedToRef(try pt.intern(.{ .slice = .{ | 27563 | .sentinel = dest_info.sentinel, |
| 27892 | .ty = dest_ty.toIntern(), | 27564 | }); |
| 27893 | .ptr = try pt.intern(.{ .ptr = .{ | 27565 | const empty_array_val = try pt.aggregateValue(empty_array_ty, &.{}); |
| 27894 | .ty = dest_ty.slicePtrFieldType(zcu).toIntern(), | 27566 | const empty_array_ptr = try sema.uavRef(empty_array_val.toIntern()); |
| 27895 | .base_addr = .int, | 27567 | return sema.coerceArrayPtrToSlice(block, dest_ty, empty_array_ptr, inst_src); |
| 27896 | .byte_offset = align_val.toByteUnits().?, | ||
| 27897 | } }), | ||
| 27898 | .len = .zero_usize, | ||
| 27899 | } })); | ||
| 27900 | } | 27568 | } |
| 27901 | 27569 | ||
| 27902 | // pointer to tuple to slice | 27570 | // pointer to tuple to slice |
| ... | @@ -27955,7 +27623,7 @@ fn coerceExtra( | ... | @@ -27955,7 +27623,7 @@ fn coerceExtra( |
| 27955 | .int, .comptime_int => { | 27623 | .int, .comptime_int => { |
| 27956 | if (maybe_inst_val) |val| { | 27624 | if (maybe_inst_val) |val| { |
| 27957 | // comptime-known integer to other number | 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 | if (!opts.report_err) return error.NotCoercible; | 27627 | if (!opts.report_err) return error.NotCoercible; |
| 27960 | return sema.fail(block, inst_src, "type '{f}' cannot represent integer value '{f}'", .{ dest_ty.fmt(pt), val.fmtValueSema(pt, sema) }); | 27628 | return sema.fail(block, inst_src, "type '{f}' cannot represent integer value '{f}'", .{ dest_ty.fmt(pt), val.fmtValueSema(pt, sema) }); |
| 27961 | } | 27629 | } |
| ... | @@ -28039,28 +27707,26 @@ fn coerceExtra( | ... | @@ -28039,28 +27707,26 @@ fn coerceExtra( |
| 28039 | } | 27707 | } |
| 28040 | break :int; | 27708 | break :int; |
| 28041 | }; | 27709 | }; |
| 27710 | if (val.isUndef(zcu)) { | ||
| 27711 | return .fromValue(try pt.undefValue(dest_ty)); | ||
| 27712 | } | ||
| 28042 | const result_val = try pt.floatValue(dest_ty, val.toFloat(f128, zcu)); | 27713 | const result_val = try pt.floatValue(dest_ty, val.toFloat(f128, zcu)); |
| 28043 | const fits: bool = switch (ip.indexToKey(result_val.toIntern())) { | 27714 | const float = ip.indexToKey(result_val.toIntern()).float; |
| 28044 | else => unreachable, | 27715 | var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined; |
| 28045 | .undef => true, | 27716 | const operand_big_int = val.toBigInt(&buffer, zcu); |
| 28046 | .float => |float| fits: { | 27717 | const fits = switch (float.storage) { |
| 28047 | var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined; | 27718 | inline else => |x| fits: { |
| 28048 | const operand_big_int = val.toBigInt(&buffer, zcu); | 27719 | if (!std.math.isFinite(x)) break :fits false; |
| 28049 | switch (float.storage) { | 27720 | var result_big_int: std.math.big.int.Mutable = .{ |
| 28050 | inline else => |x| { | 27721 | .limbs = try sema.arena.alloc(std.math.big.Limb, std.math.big.int.calcLimbLen(x)), |
| 28051 | if (!std.math.isFinite(x)) break :fits false; | 27722 | .len = undefined, |
| 28052 | var result_big_int: std.math.big.int.Mutable = .{ | 27723 | .positive = undefined, |
| 28053 | .limbs = try sema.arena.alloc(std.math.big.Limb, std.math.big.int.calcLimbLen(x)), | 27724 | }; |
| 28054 | .len = undefined, | 27725 | switch (result_big_int.setFloat(x, .nearest_even)) { |
| 28055 | .positive = undefined, | 27726 | .inexact => break :fits false, |
| 28056 | }; | 27727 | .exact => {}, |
| 28057 | switch (result_big_int.setFloat(x, .nearest_even)) { | ||
| 28058 | .inexact => break :fits false, | ||
| 28059 | .exact => {}, | ||
| 28060 | } | ||
| 28061 | break :fits result_big_int.toConst().eql(operand_big_int); | ||
| 28062 | }, | ||
| 28063 | } | 27728 | } |
| 27729 | break :fits result_big_int.toConst().eql(operand_big_int); | ||
| 28064 | }, | 27730 | }, |
| 28065 | }; | 27731 | }; |
| 28066 | if (!fits) return sema.fail( | 27732 | if (!fits) return sema.fail( |
| ... | @@ -28699,7 +28365,7 @@ pub fn coerceInMemoryAllowed( | ... | @@ -28699,7 +28365,7 @@ pub fn coerceInMemoryAllowed( |
| 28699 | // Comptime int to regular int. | 28365 | // Comptime int to regular int. |
| 28700 | if (dest_tag == .int and src_tag == .comptime_int) { | 28366 | if (dest_tag == .int and src_tag == .comptime_int) { |
| 28701 | if (src_val) |val| { | 28367 | if (src_val) |val| { |
| 28702 | if (!(try sema.intFitsInType(val, dest_ty, null))) { | 28368 | if (!val.intFitsInType(dest_ty, null, zcu)) { |
| 28703 | return .{ .comptime_int_not_coercible = .{ .wanted = dest_ty, .actual = val } }; | 28369 | return .{ .comptime_int_not_coercible = .{ .wanted = dest_ty, .actual = val } }; |
| 28704 | } | 28370 | } |
| 28705 | } | 28371 | } |
| ... | @@ -29333,7 +28999,7 @@ fn coerceVarArgParam( | ... | @@ -29333,7 +28999,7 @@ fn coerceVarArgParam( |
| 29333 | } | 28999 | } |
| 29334 | }, | 29000 | }, |
| 29335 | else => if (uncasted_ty.isAbiInt(zcu)) int: { | 29001 | else => if (uncasted_ty.isAbiInt(zcu)) int: { |
| 29336 | if (!try sema.validateExternType(uncasted_ty, .param_ty)) break :int inst; | 29002 | if (!uncasted_ty.validateExtern(.param_ty, zcu)) break :int inst; |
| 29337 | const target = zcu.getTarget(); | 29003 | const target = zcu.getTarget(); |
| 29338 | const uncasted_info = uncasted_ty.intInfo(zcu); | 29004 | const uncasted_info = uncasted_ty.intInfo(zcu); |
| 29339 | if (uncasted_info.bits <= target.cTypeBitSize(switch (uncasted_info.signedness) { | 29005 | if (uncasted_info.bits <= target.cTypeBitSize(switch (uncasted_info.signedness) { |
| ... | @@ -29362,7 +29028,7 @@ fn coerceVarArgParam( | ... | @@ -29362,7 +29028,7 @@ fn coerceVarArgParam( |
| 29362 | }; | 29028 | }; |
| 29363 | 29029 | ||
| 29364 | const coerced_ty = sema.typeOf(coerced); | 29030 | const coerced_ty = sema.typeOf(coerced); |
| 29365 | if (!try sema.validateExternType(coerced_ty, .param_ty)) { | 29031 | if (!coerced_ty.validateExtern(.param_ty, zcu)) { |
| 29366 | const msg = msg: { | 29032 | const msg = msg: { |
| 29367 | const msg = try sema.errMsg(inst_src, "cannot pass '{f}' to variadic function", .{coerced_ty.fmt(pt)}); | 29033 | const msg = try sema.errMsg(inst_src, "cannot pass '{f}' to variadic function", .{coerced_ty.fmt(pt)}); |
| 29368 | errdefer msg.destroy(sema.gpa); | 29034 | errdefer msg.destroy(sema.gpa); |
| ... | @@ -33283,12 +32949,12 @@ fn typeIsArrayLike(sema: *Sema, ty: Type) ?ArrayLike { | ... | @@ -33283,12 +32949,12 @@ fn typeIsArrayLike(sema: *Sema, ty: Type) ?ArrayLike { |
| 33283 | .elem_ty = ty.childType(zcu), | 32949 | .elem_ty = ty.childType(zcu), |
| 33284 | }, | 32950 | }, |
| 33285 | .@"struct" => { | 32951 | .@"struct" => { |
| 32952 | if (!ty.isTuple(zcu)) return null; | ||
| 33286 | const field_count = ty.structFieldCount(zcu); | 32953 | const field_count = ty.structFieldCount(zcu); |
| 33287 | if (field_count == 0) return .{ | 32954 | if (field_count == 0) return .{ |
| 33288 | .len = 0, | 32955 | .len = 0, |
| 33289 | .elem_ty = .noreturn, | 32956 | .elem_ty = .noreturn, |
| 33290 | }; | 32957 | }; |
| 33291 | if (!ty.isTuple(zcu)) return null; | ||
| 33292 | const elem_ty = ty.fieldType(0, zcu); | 32958 | const elem_ty = ty.fieldType(0, zcu); |
| 33293 | for (1..field_count) |i| { | 32959 | for (1..field_count) |i| { |
| 33294 | if (!ty.fieldType(i, zcu).eql(elem_ty, zcu)) { | 32960 | if (!ty.fieldType(i, zcu).eql(elem_ty, zcu)) { |
| ... | @@ -33700,6 +33366,7 @@ fn usizeCast(sema: *Sema, block: *Block, src: LazySrcLoc, int: u64) CompileError | ... | @@ -33700,6 +33366,7 @@ fn usizeCast(sema: *Sema, block: *Block, src: LazySrcLoc, int: u64) CompileError |
| 33700 | return std.math.cast(usize, int) orelse return sema.fail(block, src, "expression produces integer value '{d}' which is too big for this compiler implementation to handle", .{int}); | 33366 | return std.math.cast(usize, int) orelse return sema.fail(block, src, "expression produces integer value '{d}' which is too big for this compiler implementation to handle", .{int}); |
| 33701 | } | 33367 | } |
| 33702 | 33368 | ||
| 33369 | /// Asserts that the layout of `union_ty` is already resolved. | ||
| 33703 | fn unionFieldIndex( | 33370 | fn unionFieldIndex( |
| 33704 | sema: *Sema, | 33371 | sema: *Sema, |
| 33705 | block: *Block, | 33372 | block: *Block, |
| ... | @@ -33717,6 +33384,7 @@ fn unionFieldIndex( | ... | @@ -33717,6 +33384,7 @@ fn unionFieldIndex( |
| 33717 | return @intCast(field_index); | 33384 | return @intCast(field_index); |
| 33718 | } | 33385 | } |
| 33719 | 33386 | ||
| 33387 | /// Asserts that the layout of `struct_ty` is already resolved. | ||
| 33720 | fn structFieldIndex( | 33388 | fn structFieldIndex( |
| 33721 | sema: *Sema, | 33389 | sema: *Sema, |
| 33722 | block: *Block, | 33390 | block: *Block, |
| ... | @@ -33811,64 +33479,6 @@ fn intFromFloatScalar( | ... | @@ -33811,64 +33479,6 @@ fn intFromFloatScalar( |
| 33811 | return pt.getCoerced(cti_result, int_ty); | 33479 | return pt.getCoerced(cti_result, int_ty); |
| 33812 | } | 33480 | } |
| 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 | fn intInRange(sema: *Sema, tag_ty: Type, int_val: Value, end: usize) !bool { | 33482 | fn intInRange(sema: *Sema, tag_ty: Type, int_val: Value, end: usize) !bool { |
| 33873 | const pt = sema.pt; | 33483 | const pt = sema.pt; |
| 33874 | if (!int_val.compareAllWithZero(.gte, pt.zcu)) return false; | 33484 | if (!int_val.compareAllWithZero(.gte, pt.zcu)) return false; |
| ... | @@ -33886,7 +33496,7 @@ fn enumHasInt(sema: *Sema, ty: Type, int: Value) CompileError!bool { | ... | @@ -33886,7 +33496,7 @@ fn enumHasInt(sema: *Sema, ty: Type, int: Value) CompileError!bool { |
| 33886 | // The `tagValueIndex` function call below relies on the type being the integer tag type. | 33496 | // The `tagValueIndex` function call below relies on the type being the integer tag type. |
| 33887 | // `getCoerced` assumes the value will fit the new type. | 33497 | // `getCoerced` assumes the value will fit the new type. |
| 33888 | const int_tag_ty: Type = .fromInterned(enum_type.int_tag_type); | 33498 | const int_tag_ty: Type = .fromInterned(enum_type.int_tag_type); |
| 33889 | if (!try sema.intFitsInType(int, int_tag_ty, null)) return false; | 33499 | if (!int.intFitsInType(int_tag_ty, null, zcu)) return false; |
| 33890 | const int_coerced = try pt.getCoerced(int, int_tag_ty); | 33500 | const int_coerced = try pt.getCoerced(int, int_tag_ty); |
| 33891 | return enum_type.tagValueIndex(&zcu.intern_pool, int_coerced.toIntern()) != null; | 33501 | return enum_type.tagValueIndex(&zcu.intern_pool, int_coerced.toIntern()) != null; |
| 33892 | } | 33502 | } |
| ... | @@ -33919,7 +33529,6 @@ fn compareAll( | ... | @@ -33919,7 +33529,6 @@ fn compareAll( |
| 33919 | } | 33529 | } |
| 33920 | 33530 | ||
| 33921 | /// Asserts the values are comparable. Both operands have type `ty`. | 33531 | /// Asserts the values are comparable. Both operands have type `ty`. |
| 33922 | /// MLUGG TODO: move to `Value`? | ||
| 33923 | fn compareScalar( | 33532 | fn compareScalar( |
| 33924 | sema: *Sema, | 33533 | sema: *Sema, |
| 33925 | lhs: Value, | 33534 | lhs: Value, |
| ... | @@ -34422,7 +34031,7 @@ const ComptimeStoreResult = @import("Sema/comptime_ptr_access.zig").ComptimeStor | ... | @@ -34422,7 +34031,7 @@ const ComptimeStoreResult = @import("Sema/comptime_ptr_access.zig").ComptimeStor |
| 34422 | // MLUGG TODO: decide how to do the namespacing here | 34031 | // MLUGG TODO: decide how to do the namespacing here |
| 34423 | pub const type_resolution = @import("Sema/type_resolution.zig"); | 34032 | pub const type_resolution = @import("Sema/type_resolution.zig"); |
| 34424 | pub const ensureLayoutResolved = type_resolution.ensureLayoutResolved; | 34033 | pub const ensureLayoutResolved = type_resolution.ensureLayoutResolved; |
| 34425 | pub const ensureFieldInitsResolved = type_resolution.ensureFieldInitsResolved; | 34034 | pub const ensureStructDefaultsResolved = type_resolution.ensureStructDefaultsResolved; |
| 34426 | 34035 | ||
| 34427 | pub fn getBuiltinType(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl) SemaError!Type { | 34036 | pub fn getBuiltinType(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl) SemaError!Type { |
| 34428 | assert(decl.kind() == .type); | 34037 | assert(decl.kind() == .type); |
| ... | @@ -34644,48 +34253,14 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ | ... | @@ -34644,48 +34253,14 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ |
| 34644 | }; | 34253 | }; |
| 34645 | } | 34254 | } |
| 34646 | 34255 | ||
| 34647 | /// TODO MLUGG: this is a gnarly hack | 34256 | fn setTypeName( |
| 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( | ||
| 34683 | sema: *Sema, | 34257 | sema: *Sema, |
| 34684 | block: *Block, | 34258 | block: *Block, |
| 34259 | wip: *const InternPool.WipContainerType, | ||
| 34685 | name_strategy: Zir.Inst.NameStrategy, | 34260 | name_strategy: Zir.Inst.NameStrategy, |
| 34686 | anon_prefix: []const u8, | 34261 | anon_prefix: []const u8, |
| 34687 | inst: Zir.Inst.Index, | 34262 | inst: Zir.Inst.Index, |
| 34688 | ) CompileError!PartialTypeName { | 34263 | ) CompileError!void { |
| 34689 | const pt = sema.pt; | 34264 | const pt = sema.pt; |
| 34690 | const zcu = pt.zcu; | 34265 | const zcu = pt.zcu; |
| 34691 | const comp = zcu.comp; | 34266 | const comp = zcu.comp; |
| ... | @@ -34693,13 +34268,26 @@ pub fn createTypeName( | ... | @@ -34693,13 +34268,26 @@ pub fn createTypeName( |
| 34693 | const io = comp.io; | 34268 | const io = comp.io; |
| 34694 | const ip = &zcu.intern_pool; | 34269 | const ip = &zcu.intern_pool; |
| 34695 | 34270 | ||
| 34696 | switch (name_strategy) { | 34271 | strat: switch (name_strategy) { |
| 34697 | .anon => {}, // handled after switch | 34272 | .anon => { |
| 34698 | .parent => return .{ .exact = .{ | 34273 | // It would be neat to have "struct:line:column" but this name has |
| 34699 | .name = block.type_name_ctx, | 34274 | // to survive incremental updates, where it may have been shifted down |
| 34700 | .nav = sema.owner.unwrap().nav_val.toOptional(), | 34275 | // or up to a different line, but unchanged, and thus not unnecessarily |
| 34701 | } }, | 34276 | // semantically analyzed. |
| 34702 | .func => func_strat: { | 34277 | // TODO: that would be possible, by detecting line number changes and renaming |
| 34278 | // types appropriately. However, `@typeName` becomes a problem then. If we remove | ||
| 34279 | // that builtin from the language, we can consider this. | ||
| 34280 | wip.setName(ip, try ip.getOrPutStringFmt( | ||
| 34281 | gpa, | ||
| 34282 | io, | ||
| 34283 | pt.tid, | ||
| 34284 | "{f}__{s}_{d}", | ||
| 34285 | .{ block.type_name_ctx.fmt(ip), anon_prefix, @intFromEnum(wip.index) }, | ||
| 34286 | .no_embedded_nulls, | ||
| 34287 | ), .none); | ||
| 34288 | }, | ||
| 34289 | .parent => wip.setName(ip, block.type_name_ctx, sema.owner.unwrap().nav_val.toOptional()), | ||
| 34290 | .func => { | ||
| 34703 | const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse return error.AnalysisFail); | 34291 | const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse return error.AnalysisFail); |
| 34704 | const zir_tags = sema.code.instructions.items(.tag); | 34292 | const zir_tags = sema.code.instructions.items(.tag); |
| 34705 | 34293 | ||
| ... | @@ -34717,7 +34305,9 @@ pub fn createTypeName( | ... | @@ -34717,7 +34305,9 @@ pub fn createTypeName( |
| 34717 | // If not then this is a struct type being returned from a non-generic | 34305 | // If not then this is a struct type being returned from a non-generic |
| 34718 | // function and the name doesn't matter since it will later | 34306 | // function and the name doesn't matter since it will later |
| 34719 | // result in a compile error. | 34307 | // result in a compile error. |
| 34720 | const arg_val = try sema.resolveValue(arg) orelse break :func_strat; // fall through to anon strat | 34308 | const arg_val = try sema.resolveValue(arg) orelse { |
| 34309 | continue :strat .anon; | ||
| 34310 | }; | ||
| 34721 | 34311 | ||
| 34722 | if (arg_i != 0) w.writeByte(',') catch return error.OutOfMemory; | 34312 | if (arg_i != 0) w.writeByte(',') catch return error.OutOfMemory; |
| 34723 | 34313 | ||
| ... | @@ -34739,431 +34329,28 @@ pub fn createTypeName( | ... | @@ -34739,431 +34329,28 @@ pub fn createTypeName( |
| 34739 | }; | 34329 | }; |
| 34740 | 34330 | ||
| 34741 | w.writeByte(')') catch return error.OutOfMemory; | 34331 | w.writeByte(')') catch return error.OutOfMemory; |
| 34742 | return .{ .exact = .{ | 34332 | const name = try ip.getOrPutString(gpa, io, pt.tid, aw.written(), .no_embedded_nulls); |
| 34743 | .name = try ip.getOrPutString(gpa, io, pt.tid, aw.written(), .no_embedded_nulls), | 34333 | wip.setName(ip, name, .none); |
| 34744 | .nav = .none, | ||
| 34745 | } }; | ||
| 34746 | }, | 34334 | }, |
| 34747 | .dbg_var => { | 34335 | .dbg_var => { |
| 34748 | // TODO: this logic is questionable. We ideally should be traversing the `Block` rather than relying on the order of AstGen instructions. | 34336 | // TODO: this logic is questionable. We ideally should be traversing the `Block` rather than relying on the order of AstGen instructions. |
| 34749 | const ref = inst.toRef(); | 34337 | const ref = inst.toRef(); |
| 34750 | const zir_tags = sema.code.instructions.items(.tag); | 34338 | const zir_tags = sema.code.instructions.items(.tag); |
| 34751 | const zir_data = sema.code.instructions.items(.data); | 34339 | const zir_data = sema.code.instructions.items(.data); |
| 34752 | for (@intFromEnum(inst)..zir_tags.len) |i| switch (zir_tags[i]) { | 34340 | const var_name = for (@intFromEnum(inst)..zir_tags.len) |i| switch (zir_tags[i]) { |
| 34753 | .dbg_var_ptr, .dbg_var_val => if (zir_data[i].str_op.operand == ref) { | 34341 | .dbg_var_ptr, .dbg_var_val => if (zir_data[i].str_op.operand == ref) { |
| 34754 | return .{ .exact = .{ | 34342 | break zir_data[i].str_op.getStr(sema.code); |
| 34755 | .name = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}.{s}", .{ | ||
| 34756 | block.type_name_ctx.fmt(ip), zir_data[i].str_op.getStr(sema.code), | ||
| 34757 | }, .no_embedded_nulls), | ||
| 34758 | .nav = .none, | ||
| 34759 | } }; | ||
| 34760 | }, | 34343 | }, |
| 34761 | else => {}, | 34344 | else => {}, |
| 34345 | } else { | ||
| 34346 | continue :strat .anon; | ||
| 34762 | }; | 34347 | }; |
| 34763 | // fall through to anon 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 | fn zirStructDecl( | 34356 | fn zirStructDecl( |
| ... | @@ -35173,6 +34360,10 @@ fn zirStructDecl( | ... | @@ -35173,6 +34360,10 @@ fn zirStructDecl( |
| 35173 | ) CompileError!Air.Inst.Ref { | 34360 | ) CompileError!Air.Inst.Ref { |
| 35174 | const pt = sema.pt; | 34361 | const pt = sema.pt; |
| 35175 | const zcu = pt.zcu; | 34362 | const zcu = pt.zcu; |
| 34363 | const comp = zcu.comp; | ||
| 34364 | const gpa = comp.gpa; | ||
| 34365 | const io = comp.io; | ||
| 34366 | const ip = &zcu.intern_pool; | ||
| 35176 | 34367 | ||
| 35177 | const tracked_inst = try block.trackZir(inst); | 34368 | const tracked_inst = try block.trackZir(inst); |
| 35178 | 34369 | ||
| ... | @@ -35180,32 +34371,50 @@ fn zirStructDecl( | ... | @@ -35180,32 +34371,50 @@ fn zirStructDecl( |
| 35180 | .base_node_inst = tracked_inst, | 34371 | .base_node_inst = tracked_inst, |
| 35181 | .offset = .nodeOffset(.zero), | 34372 | .offset = .nodeOffset(.zero), |
| 35182 | }; | 34373 | }; |
| 35183 | const backing_ty_src: LazySrcLoc = .{ | ||
| 35184 | .base_node_inst = tracked_inst, | ||
| 35185 | .offset = .{ .node_offset_container_tag = .zero }, | ||
| 35186 | }; | ||
| 35187 | 34374 | ||
| 35188 | const struct_decl = sema.code.getStructDecl(inst); | 34375 | const struct_decl = sema.code.getStructDecl(inst); |
| 35189 | 34376 | ||
| 35190 | const captures = try sema.getCaptures(block, src, struct_decl.captures, struct_decl.capture_names); | 34377 | const captures = try sema.getCaptures(block, src, struct_decl.captures, struct_decl.capture_names); |
| 35191 | 34378 | ||
| 35192 | const backing_int_type: ?Type = ty: { | 34379 | const ty: Type = switch (try ip.getDeclaredStructType(gpa, io, pt.tid, .{ |
| 35193 | if (struct_decl.backing_int_type == .none) break :ty null; | 34380 | .zir_index = tracked_inst, |
| 35194 | break :ty try sema.resolveType(block, backing_ty_src, struct_decl.backing_int_type); | 34381 | .captures = captures, |
| 35195 | // MLUGG TODO validate it's an int! | 34382 | .fields_len = @intCast(struct_decl.field_names.len), |
| 35196 | }; | 34383 | .layout = struct_decl.layout, |
| 34384 | .any_comptime_fields = struct_decl.field_comptime_bits != null, | ||
| 34385 | .any_field_defaults = struct_decl.field_default_body_lens != null, | ||
| 34386 | .any_field_aligns = struct_decl.field_align_body_lens != null, | ||
| 34387 | .packed_backing_mode = if (struct_decl.backing_int_type_body != null) .explicit else .auto, | ||
| 34388 | })) { | ||
| 34389 | .existing => |ty| .fromInterned(ty), | ||
| 34390 | .wip => |wip| ty: { | ||
| 34391 | errdefer wip.cancel(ip, pt.tid); | ||
| 34392 | try sema.setTypeName(block, &wip, struct_decl.name_strategy, "struct", inst); | ||
| 34393 | const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ | ||
| 34394 | .parent = block.namespace.toOptional(), | ||
| 34395 | .owner_type = wip.index, | ||
| 34396 | .file_scope = block.getFileScopeIndex(zcu), | ||
| 34397 | .generation = zcu.generation, | ||
| 34398 | }); | ||
| 34399 | errdefer pt.destroyNamespace(new_namespace_index); | ||
| 34400 | try pt.scanNamespace(new_namespace_index, struct_decl.decls); | ||
| 34401 | // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind | ||
| 34402 | try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) }); | ||
| 34403 | try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .struct_defaults = wip.index }) }); | ||
| 35197 | 34404 | ||
| 35198 | const ty = try analyzeStructDecl( | 34405 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); |
| 35199 | pt, | 34406 | |
| 35200 | block.getFileScopeIndex(zcu), | 34407 | try zcu.outdated.ensureUnusedCapacity(gpa, 2); |
| 35201 | &sema.code, | 34408 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 2); |
| 35202 | block.namespace.toOptional(), | 34409 | errdefer comptime unreachable; // because we don't remove the `outdated` entries |
| 35203 | tracked_inst, | 34410 | zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); |
| 35204 | &struct_decl, | 34411 | zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .struct_defaults = wip.index }), 0); |
| 35205 | backing_int_type, | 34412 | zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); |
| 35206 | captures, | 34413 | zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .struct_defaults = wip.index }), {}); |
| 35207 | try sema.createTypeName(block, struct_decl.name_strategy, "struct", inst), | 34414 | |
| 35208 | ); | 34415 | break :ty .fromInterned(wip.finish(ip, new_namespace_index)); |
| 34416 | }, | ||
| 34417 | }; | ||
| 35209 | 34418 | ||
| 35210 | try sema.addTypeReferenceEntry(src, ty); | 34419 | try sema.addTypeReferenceEntry(src, ty); |
| 35211 | 34420 | ||
| ... | @@ -35234,124 +34443,68 @@ fn zirUnionDecl( | ... | @@ -35234,124 +34443,68 @@ fn zirUnionDecl( |
| 35234 | .base_node_inst = tracked_inst, | 34443 | .base_node_inst = tracked_inst, |
| 35235 | .offset = .nodeOffset(.zero), | 34444 | .offset = .nodeOffset(.zero), |
| 35236 | }; | 34445 | }; |
| 35237 | const arg_ty_src: LazySrcLoc = .{ | ||
| 35238 | .base_node_inst = tracked_inst, | ||
| 35239 | .offset = .{ .node_offset_container_tag = .zero }, | ||
| 35240 | }; | ||
| 35241 | 34446 | ||
| 35242 | const union_decl = sema.code.getUnionDecl(inst); | 34447 | const union_decl = sema.code.getUnionDecl(inst); |
| 35243 | 34448 | ||
| 35244 | const captures = try sema.getCaptures(block, src, union_decl.captures, union_decl.capture_names); | 34449 | const captures = try sema.getCaptures(block, src, union_decl.captures, union_decl.capture_names); |
| 35245 | 34450 | ||
| 35246 | const arg_type: ?Type = ty: { | 34451 | const ty: Type = switch (try ip.getDeclaredUnionType(gpa, io, pt.tid, .{ |
| 35247 | if (union_decl.arg_type == .none) break :ty null; | 34452 | .zir_index = tracked_inst, |
| 35248 | break :ty try sema.resolveType(block, arg_ty_src, union_decl.arg_type); | 34453 | .captures = captures, |
| 35249 | }; | 34454 | .fields_len = @intCast(union_decl.field_names.len), |
| 34455 | .layout = union_decl.kind.layout(), | ||
| 34456 | .any_field_aligns = union_decl.field_align_body_lens != null, | ||
| 34457 | .runtime_tag = switch (union_decl.kind) { | ||
| 34458 | .auto => if (block.wantSafeTypes()) .safety else .none, | ||
| 35250 | 34459 | ||
| 35251 | const ty = analyzeUnionDecl( | 34460 | .tagged_explicit, |
| 35252 | pt, | 34461 | .tagged_enum, |
| 35253 | block.getFileScopeIndex(zcu), | 34462 | .tagged_enum_explicit, |
| 35254 | &sema.code, | 34463 | => .tagged, |
| 35255 | block.namespace.toOptional(), | 34464 | |
| 35256 | block.wantSafeTypes(), | 34465 | .@"extern", |
| 35257 | tracked_inst, | 34466 | .@"packed", |
| 35258 | &union_decl, | 34467 | .packed_explicit, |
| 35259 | arg_type, | 34468 | => .none, |
| 35260 | captures, | ||
| 35261 | try sema.createTypeName(block, union_decl.name_strategy, "union", inst), | ||
| 35262 | ) catch |err| switch (err) { | ||
| 35263 | error.OutOfMemory, | ||
| 35264 | error.Canceled, | ||
| 35265 | => |e| return e, | ||
| 35266 | |||
| 35267 | error.ExplicitBackingNotInt => return sema.fail( | ||
| 35268 | block, | ||
| 35269 | arg_ty_src, | ||
| 35270 | "expected integer backing type, found '{f}'", | ||
| 35271 | .{arg_type.?.fmt(pt)}, | ||
| 35272 | ), | ||
| 35273 | error.ExplicitTagNotInt => return sema.fail( | ||
| 35274 | block, | ||
| 35275 | arg_ty_src, | ||
| 35276 | "expected integer tag type, found '{f}'", | ||
| 35277 | .{arg_type.?.fmt(pt)}, | ||
| 35278 | ), | ||
| 35279 | error.ExplicitTagNotEnum => return sema.fail( | ||
| 35280 | block, | ||
| 35281 | arg_ty_src, | ||
| 35282 | "expected enum tag type, found '{f}'", | ||
| 35283 | .{arg_type.?.fmt(pt)}, | ||
| 35284 | ), | ||
| 35285 | error.ExplicitTagFieldMismatch => { | ||
| 35286 | const enum_obj = ip.loadEnumType(arg_type.?.toIntern()); | ||
| 35287 | const enum_to_union_map = try sema.arena.alloc(?u32, enum_obj.field_names.len); | ||
| 35288 | @memset(enum_to_union_map, null); | ||
| 35289 | for (union_decl.field_names, 0..) |field_name_zir, union_field_idx| { | ||
| 35290 | const field_name_ip = try ip.getOrPutString(gpa, io, pt.tid, sema.code.nullTerminatedString(field_name_zir), .no_embedded_nulls); | ||
| 35291 | if (enum_obj.nameIndex(ip, field_name_ip)) |enum_field_idx| { | ||
| 35292 | enum_to_union_map[enum_field_idx] = @intCast(union_field_idx); | ||
| 35293 | continue; | ||
| 35294 | } | ||
| 35295 | const union_field_src: LazySrcLoc = .{ | ||
| 35296 | .base_node_inst = tracked_inst, | ||
| 35297 | .offset = .{ .container_field_name = @intCast(union_field_idx) }, | ||
| 35298 | }; | ||
| 35299 | return sema.failWithOwnedErrorMsg(block, msg: { | ||
| 35300 | const msg = try sema.errMsg(union_field_src, "no field named '{f}' in enum '{f}'", .{ field_name_ip.fmt(ip), arg_type.?.fmt(pt) }); | ||
| 35301 | errdefer msg.destroy(gpa); | ||
| 35302 | try sema.addDeclaredHereNote(msg, arg_type.?); | ||
| 35303 | break :msg msg; | ||
| 35304 | }); | ||
| 35305 | } | ||
| 35306 | for (enum_to_union_map, 0..) |union_field_idx, enum_field_idx| { | ||
| 35307 | if (union_field_idx != null) continue; | ||
| 35308 | const field_name_ip = enum_obj.field_names.get(ip)[enum_field_idx]; | ||
| 35309 | const enum_field_src: LazySrcLoc = .{ | ||
| 35310 | .base_node_inst = arg_type.?.typeDeclInstAllowGeneratedTag(zcu).?, | ||
| 35311 | .offset = .{ .container_field_name = @intCast(enum_field_idx) }, | ||
| 35312 | }; | ||
| 35313 | return sema.failWithOwnedErrorMsg(block, msg: { | ||
| 35314 | const msg = try sema.errMsg(src, "enum field '{f}' missing from union", .{field_name_ip.fmt(ip)}); | ||
| 35315 | errdefer msg.destroy(gpa); | ||
| 35316 | try sema.errNote(enum_field_src, msg, "enum field here", .{}); | ||
| 35317 | break :msg msg; | ||
| 35318 | }); | ||
| 35319 | } | ||
| 35320 | for (enum_to_union_map, 0..) |union_field_idx, enum_field_idx| { | ||
| 35321 | if (union_field_idx.? == enum_field_idx) continue; | ||
| 35322 | const field_name = sema.code.nullTerminatedString( | ||
| 35323 | union_decl.field_names[union_field_idx.?], | ||
| 35324 | ); | ||
| 35325 | const union_field_src: LazySrcLoc = .{ | ||
| 35326 | .base_node_inst = tracked_inst, | ||
| 35327 | .offset = .{ .container_field_name = union_field_idx.? }, | ||
| 35328 | }; | ||
| 35329 | const enum_field_src: LazySrcLoc = .{ | ||
| 35330 | .base_node_inst = arg_type.?.typeDeclInstAllowGeneratedTag(zcu).?, | ||
| 35331 | .offset = .{ .container_field_name = @intCast(enum_field_idx) }, | ||
| 35332 | }; | ||
| 35333 | return sema.failWithOwnedErrorMsg(block, msg: { | ||
| 35334 | const msg = try sema.errMsg(src, "union field order does not match tag enum field order", .{}); | ||
| 35335 | errdefer msg.destroy(gpa); | ||
| 35336 | try sema.errNote(union_field_src, msg, "union field '{s}' is index {d}", .{ field_name, union_field_idx.? }); | ||
| 35337 | try sema.errNote(enum_field_src, msg, "enum field '{s}' is index {d}", .{ field_name, enum_field_idx }); | ||
| 35338 | break :msg msg; | ||
| 35339 | }); | ||
| 35340 | } | ||
| 35341 | unreachable; | ||
| 35342 | }, | 34469 | }, |
| 35343 | }; | 34470 | .enum_tag_mode = switch (union_decl.kind) { |
| 34471 | .tagged_explicit => .explicit, | ||
| 34472 | else => .auto, | ||
| 34473 | }, | ||
| 34474 | .packed_backing_mode = switch (union_decl.kind) { | ||
| 34475 | .packed_explicit => .explicit, | ||
| 34476 | else => .auto, | ||
| 34477 | }, | ||
| 34478 | })) { | ||
| 34479 | .existing => |ty| .fromInterned(ty), | ||
| 34480 | .wip => |wip| ty: { | ||
| 34481 | errdefer wip.cancel(ip, pt.tid); | ||
| 34482 | try sema.setTypeName(block, &wip, union_decl.name_strategy, "union", inst); | ||
| 35344 | 34483 | ||
| 35345 | const enum_tag_ty = ty.unionTagTypeHypothetical(zcu); | 34484 | const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ |
| 35346 | switch (ip.indexToKey(enum_tag_ty.toIntern()).enum_type) { | 34485 | .parent = block.namespace.toOptional(), |
| 35347 | .declared, .reified => {}, | 34486 | .owner_type = wip.index, |
| 35348 | .generated_union_tag => |owner_union_ty| { | 34487 | .file_scope = block.getFileScopeIndex(zcu), |
| 35349 | assert(owner_union_ty == ty.toIntern()); | 34488 | .generation = zcu.generation, |
| 35350 | // generated tag type [MLUGG] | 34489 | }); |
| 35351 | // Enum inits are resolved eagerly. TODO MLUGG: honestly i don't think they SHOULD be lol | 34490 | errdefer pt.destroyNamespace(new_namespace_index); |
| 35352 | try sema.ensureFieldInitsResolved(.fromInterned(ip.loadUnionType(ty.toIntern()).enum_tag_type)); | 34491 | |
| 34492 | try pt.scanNamespace(new_namespace_index, union_decl.decls); | ||
| 34493 | |||
| 34494 | // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind | ||
| 34495 | try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) }); | ||
| 34496 | |||
| 34497 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); | ||
| 34498 | |||
| 34499 | try zcu.outdated.ensureUnusedCapacity(gpa, 1); | ||
| 34500 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); | ||
| 34501 | errdefer comptime unreachable; // because we don't remove the `outdated` entry | ||
| 34502 | zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); | ||
| 34503 | zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); | ||
| 34504 | |||
| 34505 | break :ty .fromInterned(wip.finish(ip, new_namespace_index)); | ||
| 35353 | }, | 34506 | }, |
| 35354 | } | 34507 | }; |
| 35355 | 34508 | ||
| 35356 | try sema.addTypeReferenceEntry(src, ty); | 34509 | try sema.addTypeReferenceEntry(src, ty); |
| 35357 | 34510 | ||
| ... | @@ -35369,6 +34522,10 @@ fn zirEnumDecl( | ... | @@ -35369,6 +34522,10 @@ fn zirEnumDecl( |
| 35369 | ) CompileError!Air.Inst.Ref { | 34522 | ) CompileError!Air.Inst.Ref { |
| 35370 | const pt = sema.pt; | 34523 | const pt = sema.pt; |
| 35371 | const zcu = pt.zcu; | 34524 | const zcu = pt.zcu; |
| 34525 | const comp = zcu.comp; | ||
| 34526 | const gpa = comp.gpa; | ||
| 34527 | const io = comp.io; | ||
| 34528 | const ip = &zcu.intern_pool; | ||
| 35372 | 34529 | ||
| 35373 | const tracked_inst = try block.trackZir(inst); | 34530 | const tracked_inst = try block.trackZir(inst); |
| 35374 | 34531 | ||
| ... | @@ -35376,45 +34533,48 @@ fn zirEnumDecl( | ... | @@ -35376,45 +34533,48 @@ fn zirEnumDecl( |
| 35376 | .base_node_inst = tracked_inst, | 34533 | .base_node_inst = tracked_inst, |
| 35377 | .offset = .nodeOffset(.zero), | 34534 | .offset = .nodeOffset(.zero), |
| 35378 | }; | 34535 | }; |
| 35379 | const tag_ty_src: LazySrcLoc = .{ | ||
| 35380 | .base_node_inst = tracked_inst, | ||
| 35381 | .offset = .{ .node_offset_container_tag = .zero }, | ||
| 35382 | }; | ||
| 35383 | 34536 | ||
| 35384 | const enum_decl = sema.code.getEnumDecl(inst); | 34537 | const enum_decl = sema.code.getEnumDecl(inst); |
| 35385 | 34538 | ||
| 35386 | const captures = try sema.getCaptures(block, src, enum_decl.captures, enum_decl.capture_names); | 34539 | const captures = try sema.getCaptures(block, src, enum_decl.captures, enum_decl.capture_names); |
| 35387 | 34540 | ||
| 35388 | const tag_type: ?Type = ty: { | 34541 | const ty: Type = switch (try ip.getDeclaredEnumType(gpa, io, pt.tid, .{ |
| 35389 | if (enum_decl.tag_type == .none) break :ty null; | 34542 | .zir_index = tracked_inst, |
| 35390 | break :ty try sema.resolveType(block, tag_ty_src, enum_decl.tag_type); | 34543 | .captures = captures, |
| 35391 | }; | 34544 | .fields_len = @intCast(enum_decl.field_names.len), |
| 34545 | .nonexhaustive = enum_decl.nonexhaustive, | ||
| 34546 | .int_tag_mode = if (enum_decl.tag_type_body != null) .explicit else .auto, | ||
| 34547 | })) { | ||
| 34548 | .existing => |ty| .fromInterned(ty), | ||
| 34549 | .wip => |wip| ty: { | ||
| 34550 | errdefer wip.cancel(ip, pt.tid); | ||
| 35392 | 34551 | ||
| 35393 | const ty = analyzeEnumDecl( | 34552 | try sema.setTypeName(block, &wip, enum_decl.name_strategy, "enum", inst); |
| 35394 | pt, | 34553 | |
| 35395 | block.getFileScopeIndex(zcu), | 34554 | const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ |
| 35396 | &sema.code, | 34555 | .parent = block.namespace.toOptional(), |
| 35397 | block.namespace.toOptional(), | 34556 | .owner_type = wip.index, |
| 35398 | tracked_inst, | 34557 | .file_scope = block.getFileScopeIndex(zcu), |
| 35399 | &enum_decl, | 34558 | .generation = zcu.generation, |
| 35400 | tag_type, | 34559 | }); |
| 35401 | captures, | 34560 | errdefer pt.destroyNamespace(new_namespace_index); |
| 35402 | try sema.createTypeName(block, enum_decl.name_strategy, "enum", inst), | ||
| 35403 | ) catch |err| switch (err) { | ||
| 35404 | error.OutOfMemory, | ||
| 35405 | error.Canceled, | ||
| 35406 | => |e| return e, | ||
| 35407 | |||
| 35408 | error.ExplicitTagNotInt => return sema.fail( | ||
| 35409 | block, | ||
| 35410 | tag_ty_src, | ||
| 35411 | "expected integer tag type, found '{f}'", | ||
| 35412 | .{tag_type.?.fmt(pt)}, | ||
| 35413 | ), | ||
| 35414 | }; | ||
| 35415 | 34561 | ||
| 35416 | // Enum inits are resolved eagerly. TODO MLUGG: honestly i don't think they SHOULD be lol | 34562 | try pt.scanNamespace(new_namespace_index, enum_decl.decls); |
| 35417 | try sema.ensureFieldInitsResolved(ty); | 34563 | |
| 34564 | // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind | ||
| 34565 | try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) }); | ||
| 34566 | |||
| 34567 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); | ||
| 34568 | |||
| 34569 | try zcu.outdated.ensureUnusedCapacity(gpa, 1); | ||
| 34570 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); | ||
| 34571 | errdefer comptime unreachable; // because we don't remove the `outdated` entry | ||
| 34572 | zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); | ||
| 34573 | zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); | ||
| 34574 | |||
| 34575 | break :ty .fromInterned(wip.finish(ip, new_namespace_index)); | ||
| 34576 | }, | ||
| 34577 | }; | ||
| 35418 | 34578 | ||
| 35419 | try sema.addTypeReferenceEntry(src, ty); | 34579 | try sema.addTypeReferenceEntry(src, ty); |
| 35420 | 34580 | ||
| ... | @@ -35432,6 +34592,10 @@ fn zirOpaqueDecl( | ... | @@ -35432,6 +34592,10 @@ fn zirOpaqueDecl( |
| 35432 | ) CompileError!Air.Inst.Ref { | 34592 | ) CompileError!Air.Inst.Ref { |
| 35433 | const pt = sema.pt; | 34593 | const pt = sema.pt; |
| 35434 | const zcu = pt.zcu; | 34594 | const zcu = pt.zcu; |
| 34595 | const comp = zcu.comp; | ||
| 34596 | const gpa = comp.gpa; | ||
| 34597 | const io = comp.io; | ||
| 34598 | const ip = &zcu.intern_pool; | ||
| 35435 | 34599 | ||
| 35436 | const tracked_inst = try block.trackZir(inst); | 34600 | const tracked_inst = try block.trackZir(inst); |
| 35437 | 34601 | ||
| ... | @@ -35444,15 +34608,26 @@ fn zirOpaqueDecl( | ... | @@ -35444,15 +34608,26 @@ fn zirOpaqueDecl( |
| 35444 | 34608 | ||
| 35445 | const captures = try sema.getCaptures(block, src, opaque_decl.captures, opaque_decl.capture_names); | 34609 | const captures = try sema.getCaptures(block, src, opaque_decl.captures, opaque_decl.capture_names); |
| 35446 | 34610 | ||
| 35447 | const ty = try analyzeOpaqueDecl( | 34611 | const ty: Type = switch (try ip.getDeclaredOpaqueType(gpa, io, pt.tid, .{ |
| 35448 | pt, | 34612 | .zir_index = tracked_inst, |
| 35449 | block.getFileScopeIndex(zcu), | 34613 | .captures = captures, |
| 35450 | block.namespace.toOptional(), | 34614 | })) { |
| 35451 | tracked_inst, | 34615 | .existing => |ty| .fromInterned(ty), |
| 35452 | &opaque_decl, | 34616 | .wip => |wip| ty: { |
| 35453 | captures, | 34617 | errdefer wip.cancel(ip, pt.tid); |
| 35454 | try sema.createTypeName(block, opaque_decl.name_strategy, "opaque", inst), | 34618 | try sema.setTypeName(block, &wip, opaque_decl.name_strategy, "opaque", inst); |
| 35455 | ); | 34619 | const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ |
| 34620 | .parent = block.namespace.toOptional(), | ||
| 34621 | .owner_type = wip.index, | ||
| 34622 | .file_scope = block.getFileScopeIndex(zcu), | ||
| 34623 | .generation = zcu.generation, | ||
| 34624 | }); | ||
| 34625 | errdefer pt.destroyNamespace(new_namespace_index); | ||
| 34626 | try pt.scanNamespace(new_namespace_index, opaque_decl.decls); | ||
| 34627 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); | ||
| 34628 | break :ty .fromInterned(wip.finish(ip, new_namespace_index)); | ||
| 34629 | }, | ||
| 34630 | }; | ||
| 35456 | 34631 | ||
| 35457 | try sema.addTypeReferenceEntry(src, ty); | 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,7 +769,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool |
| 769 | const ip = &pt.zcu.intern_pool; | 769 | const ip = &pt.zcu.intern_pool; |
| 770 | 770 | ||
| 771 | try self.sema.ensureLayoutResolved(res_ty); | 771 | try self.sema.ensureLayoutResolved(res_ty); |
| 772 | try self.sema.ensureFieldInitsResolved(res_ty); | 772 | try self.sema.ensureStructDefaultsResolved(res_ty); |
| 773 | const struct_info = self.sema.pt.zcu.typeToStruct(res_ty).?; | 773 | const struct_info = self.sema.pt.zcu.typeToStruct(res_ty).?; |
| 774 | 774 | ||
| 775 | const fields: @FieldType(Zoir.Node, "struct_literal") = switch (node.get(self.file.zoir.?)) { | 775 | const fields: @FieldType(Zoir.Node, "struct_literal") = switch (node.get(self.file.zoir.?)) { |
src/Sema/type_resolution.zig+719-454| ... | @@ -18,10 +18,6 @@ const arith = @import("arith.zig"); | ... | @@ -18,10 +18,6 @@ const arith = @import("arith.zig"); |
| 18 | /// `ty` may be any type; its layout is resolved *recursively* if necessary. | 18 | /// `ty` may be any type; its layout is resolved *recursively* if necessary. |
| 19 | /// Adds incremental dependencies tracking any required type resolution. | 19 | /// Adds incremental dependencies tracking any required type resolution. |
| 20 | /// MLUGG TODO: to make the langspec non-stupid, we need to call this from WAY fewer places (the conditions need to be less specific). | 20 | /// MLUGG TODO: to make the langspec non-stupid, we need to call this from WAY fewer places (the conditions need to be less specific). |
| 21 | /// e.g. I think creating the type `fn (A, B) C` should force layout resolution of `A`,`B`,`C`, which will simplify some `analyzeCall` logic. | ||
| 22 | /// wait i just realised that's probably a terrible idea, fns are a common cause of dep loops rn... so maybe not lol idk... | ||
| 23 | /// perhaps "layout resolution" for a function should resolve layout of ret ty and stuff, idk. justification: the "layout" of a function is whether | ||
| 24 | /// fnHasRuntimeBits, which depends whether the ret ty is comptime-only, i.e. the ret ty layout | ||
| 25 | /// MLUGG TODO: to be clear, i should audit EVERY use of this before PRing | 21 | /// MLUGG TODO: to be clear, i should audit EVERY use of this before PRing |
| 26 | pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void { | 22 | pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void { |
| 27 | const pt = sema.pt; | 23 | const pt = sema.pt; |
| ... | @@ -33,7 +29,6 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void { | ... | @@ -33,7 +29,6 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void { |
| 33 | .anyframe_type, | 29 | .anyframe_type, |
| 34 | .simple_type, | 30 | .simple_type, |
| 35 | .opaque_type, | 31 | .opaque_type, |
| 36 | .enum_type, | ||
| 37 | .error_set_type, | 32 | .error_set_type, |
| 38 | .inferred_error_set_type, | 33 | .inferred_error_set_type, |
| 39 | => {}, | 34 | => {}, |
| ... | @@ -52,7 +47,7 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void { | ... | @@ -52,7 +47,7 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void { |
| 52 | .tuple_type => |tuple| for (tuple.types.get(ip)) |field_ty| { | 47 | .tuple_type => |tuple| for (tuple.types.get(ip)) |field_ty| { |
| 53 | try ensureLayoutResolved(sema, .fromInterned(field_ty)); | 48 | try ensureLayoutResolved(sema, .fromInterned(field_ty)); |
| 54 | }, | 49 | }, |
| 55 | .struct_type, .union_type => { | 50 | .struct_type, .union_type, .enum_type => { |
| 56 | try sema.declareDependency(.{ .type_layout = ty.toIntern() }); | 51 | try sema.declareDependency(.{ .type_layout = ty.toIntern() }); |
| 57 | if (zcu.analysis_in_progress.contains(.wrap(.{ .type_layout = ty.toIntern() }))) { | 52 | if (zcu.analysis_in_progress.contains(.wrap(.{ .type_layout = ty.toIntern() }))) { |
| 58 | // TODO: better error message | 53 | // TODO: better error message |
| ... | @@ -89,36 +84,36 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void { | ... | @@ -89,36 +84,36 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void { |
| 89 | } | 84 | } |
| 90 | } | 85 | } |
| 91 | 86 | ||
| 92 | /// Asserts that `ty` is either a `struct` type, or an `enum` type. | 87 | /// Asserts that `ty` is a non-tuple `struct` type, and ensures that its fields' default values |
| 93 | /// If `ty` is a struct, ensures that fields' default values are resolved. | 88 | /// are resolved. Adds incremental dependencies tracking the required type resolution. |
| 94 | /// If `ty` is an enum, ensures that fields' integer tag valus are resolved. | 89 | /// |
| 95 | /// Adds incremental dependencies tracking the required type resolution. | 90 | /// It is not necessary to call this function to query the values of comptime fields: those values |
| 96 | pub fn ensureFieldInitsResolved(sema: *Sema, ty: Type) SemaError!void { | 91 | /// are available from type *layout* resolution, see `ensureLayoutResolved`. |
| 92 | pub fn ensureStructDefaultsResolved(sema: *Sema, ty: Type) SemaError!void { | ||
| 97 | const pt = sema.pt; | 93 | const pt = sema.pt; |
| 98 | const zcu = pt.zcu; | 94 | const zcu = pt.zcu; |
| 99 | const ip = &zcu.intern_pool; | 95 | const ip = &zcu.intern_pool; |
| 100 | switch (ip.indexToKey(ty.toIntern())) { | 96 | assert(ip.indexToKey(ty.toIntern()) == .struct_type); |
| 101 | .struct_type, .enum_type => {}, | ||
| 102 | else => unreachable, // assertion failure | ||
| 103 | } | ||
| 104 | 97 | ||
| 105 | try sema.declareDependency(.{ .type_inits = ty.toIntern() }); | 98 | try sema.declareDependency(.{ .struct_defaults = ty.toIntern() }); |
| 106 | if (zcu.analysis_in_progress.contains(.wrap(.{ .type_inits = ty.toIntern() }))) { | 99 | if (zcu.analysis_in_progress.contains(.wrap(.{ .struct_defaults = ty.toIntern() }))) { |
| 107 | // TODO: better error message | 100 | // TODO: better error message |
| 108 | return sema.failWithOwnedErrorMsg(null, try sema.errMsg( | 101 | return sema.failWithOwnedErrorMsg(null, try sema.errMsg( |
| 109 | ty.srcLoc(zcu), | 102 | ty.srcLoc(zcu), |
| 110 | "{s} '{f}' depends on itself", | 103 | "struct '{f}' depends on itself", |
| 111 | .{ @tagName(ty.zigTypeTag(zcu)), ty.fmt(pt) }, | 104 | .{ty.fmt(pt)}, |
| 112 | )); | 105 | )); |
| 113 | } | 106 | } |
| 114 | try pt.ensureTypeInitsUpToDate(ty); | 107 | try pt.ensureStructDefaultsUpToDate(ty); |
| 115 | } | 108 | } |
| 109 | |||
| 116 | /// Asserts that `struct_ty` is a non-packed non-tuple struct, and that `sema.owner` is that type. | 110 | /// Asserts that `struct_ty` is a non-packed non-tuple struct, and that `sema.owner` is that type. |
| 117 | /// This function *does* register the `src_hash` dependency on the struct. | 111 | /// This function *does* register the `src_hash` dependency on the struct. |
| 118 | pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { | 112 | pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { |
| 119 | const pt = sema.pt; | 113 | const pt = sema.pt; |
| 120 | const zcu = pt.zcu; | 114 | const zcu = pt.zcu; |
| 121 | const comp = zcu.comp; | 115 | const comp = zcu.comp; |
| 116 | const io = comp.io; | ||
| 122 | const gpa = comp.gpa; | 117 | const gpa = comp.gpa; |
| 123 | const ip = &zcu.intern_pool; | 118 | const ip = &zcu.intern_pool; |
| 124 | 119 | ||
| ... | @@ -127,10 +122,6 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { | ... | @@ -127,10 +122,6 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { |
| 127 | const struct_obj = ip.loadStructType(struct_ty.toIntern()); | 122 | const struct_obj = ip.loadStructType(struct_ty.toIntern()); |
| 128 | const zir_index = struct_obj.zir_index.resolve(ip).?; | 123 | const zir_index = struct_obj.zir_index.resolve(ip).?; |
| 129 | 124 | ||
| 130 | assert(struct_obj.layout != .@"packed"); | ||
| 131 | |||
| 132 | try sema.declareDependency(.{ .src_hash = struct_obj.zir_index }); | ||
| 133 | |||
| 134 | var block: Block = .{ | 125 | var block: Block = .{ |
| 135 | .parent = null, | 126 | .parent = null, |
| 136 | .sema = sema, | 127 | .sema = sema, |
| ... | @@ -143,39 +134,92 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { | ... | @@ -143,39 +134,92 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { |
| 143 | }; | 134 | }; |
| 144 | defer assert(block.instructions.items.len == 0); | 135 | defer assert(block.instructions.items.len == 0); |
| 145 | 136 | ||
| 146 | const zir_struct = sema.code.getStructDecl(zir_index); | 137 | // There may be old field names in here from a previous update. |
| 147 | var field_it = zir_struct.iterateFields(); | 138 | struct_obj.field_name_map.get(ip).clearRetainingCapacity(); |
| 148 | while (field_it.next()) |zir_field| { | 139 | |
| 149 | const field_ty_src: LazySrcLoc = .{ | 140 | if (struct_obj.is_reified) { |
| 150 | .base_node_inst = struct_obj.zir_index, | 141 | // The field names are populated, but we haven't checked for duplicates (nor populated the map) yet. |
| 151 | .offset = .{ .container_field_type = zir_field.idx }, | 142 | for (0..struct_obj.field_names.len) |field_index| { |
| 152 | }; | 143 | const name = struct_obj.field_names.get(ip)[field_index]; |
| 153 | const field_align_src: LazySrcLoc = .{ | 144 | if (ip.addFieldName(struct_obj.field_names, struct_obj.field_name_map, name)) |prev_field_index| { |
| 154 | .base_node_inst = struct_obj.zir_index, | 145 | return sema.failWithOwnedErrorMsg(&block, msg: { |
| 155 | .offset = .{ .container_field_align = zir_field.idx }, | 146 | const src = block.nodeOffset(.zero); |
| 156 | }; | 147 | const msg = try sema.errMsg(src, "duplicate struct field '{f}' at index '{d}", .{ name.fmt(ip), field_index }); |
| 148 | errdefer msg.destroy(gpa); | ||
| 149 | try sema.errNote(src, msg, "previous field at index '{d}'", .{prev_field_index}); | ||
| 150 | break :msg msg; | ||
| 151 | }); | ||
| 152 | } | ||
| 153 | } | ||
| 154 | } else { | ||
| 155 | // Declared structs do not yet have field information populated: | ||
| 156 | // * field names | ||
| 157 | // * field comptime-ness | ||
| 158 | // * field types | ||
| 159 | // * field aligns | ||
| 160 | // It's our job to populate these now. | ||
| 161 | try sema.declareDependency(.{ .src_hash = struct_obj.zir_index }); | ||
| 162 | |||
| 163 | // Likewise, comptime bits may be set. We clear them all first because it avoids needing | ||
| 164 | // "unset bit with AND" logic below (instead we only need the "set bit with OR" case). | ||
| 165 | @memset(struct_obj.field_is_comptime_bits.getAll(ip), 0); | ||
| 166 | |||
| 167 | const zir_struct = sema.code.getStructDecl(zir_index); | ||
| 168 | var field_it = zir_struct.iterateFields(); | ||
| 169 | while (field_it.next()) |zir_field| { | ||
| 170 | { | ||
| 171 | const name_slice = sema.code.nullTerminatedString(zir_field.name); | ||
| 172 | const name = try ip.getOrPutString(gpa, io, pt.tid, name_slice, .no_embedded_nulls); | ||
| 173 | assert(ip.addFieldName(struct_obj.field_names, struct_obj.field_name_map, name) == null); // AstGen validated this for us | ||
| 174 | } | ||
| 157 | 175 | ||
| 158 | const field_ty: Type = field_ty: { | 176 | if (zir_field.is_comptime) { |
| 159 | block.comptime_reason = .{ .reason = .{ | 177 | const bit_bag_index = zir_field.idx / 32; |
| 160 | .src = field_ty_src, | 178 | const mask = @as(u32, 1) << @intCast(zir_field.idx % 32); |
| 161 | .r = .{ .simple = .struct_field_types }, | 179 | struct_obj.field_is_comptime_bits.getAll(ip)[bit_bag_index] |= mask; |
| 162 | } }; | 180 | } |
| 163 | const type_ref = try sema.resolveInlineBody(&block, zir_field.type_body, zir_index); | ||
| 164 | break :field_ty try sema.analyzeAsType(&block, field_ty_src, type_ref); | ||
| 165 | }; | ||
| 166 | assert(!field_ty.isGenericPoison()); | ||
| 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: { | 195 | if (struct_obj.field_aligns.len == 0) { |
| 171 | block.comptime_reason = .{ .reason = .{ | 196 | assert(zir_field.align_body == null); |
| 172 | .src = field_align_src, | 197 | } else { |
| 173 | .r = .{ .simple = .struct_field_attrs }, | 198 | const field_align_src = block.src(.{ .container_field_align = zir_field.idx }); |
| 174 | } }; | 199 | const field_align: Alignment = a: { |
| 175 | const align_body = zir_field.align_body orelse break :a .none; | 200 | block.comptime_reason = .{ .reason = .{ |
| 176 | const align_ref = try sema.resolveInlineBody(&block, align_body, zir_index); | 201 | .src = field_align_src, |
| 177 | break :a try sema.analyzeAsAlign(&block, field_align_src, align_ref); | 202 | .r = .{ .simple = .struct_field_attrs }, |
| 178 | }; | 203 | } }; |
| 204 | const align_body = zir_field.align_body orelse break :a .none; | ||
| 205 | const align_ref = try sema.resolveInlineBody(&block, align_body, zir_index); | ||
| 206 | break :a try sema.analyzeAsAlign(&block, field_align_src, align_ref); | ||
| 207 | }; | ||
| 208 | struct_obj.field_aligns.get(ip)[zir_field.idx] = field_align; | ||
| 209 | } | ||
| 210 | } | ||
| 211 | } | ||
| 212 | |||
| 213 | if (struct_obj.layout == .@"packed") { | ||
| 214 | return resolvePackedStructLayout(sema, &block, struct_ty, &struct_obj); | ||
| 215 | } | ||
| 216 | |||
| 217 | // Resolve the layout of all fields, and check their types are allowed. | ||
| 218 | for (struct_obj.field_types.get(ip), 0..) |field_ty_ip, field_index| { | ||
| 219 | const field_ty: Type = .fromInterned(field_ty_ip); | ||
| 220 | assert(!field_ty.isGenericPoison()); | ||
| 221 | const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) }); | ||
| 222 | try sema.ensureLayoutResolved(field_ty); | ||
| 179 | 223 | ||
| 180 | if (field_ty.zigTypeTag(zcu) == .@"opaque") { | 224 | if (field_ty.zigTypeTag(zcu) == .@"opaque") { |
| 181 | return sema.failWithOwnedErrorMsg(&block, msg: { | 225 | return sema.failWithOwnedErrorMsg(&block, msg: { |
| ... | @@ -186,7 +230,8 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { | ... | @@ -186,7 +230,8 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { |
| 186 | break :msg msg; | 230 | break :msg msg; |
| 187 | }); | 231 | }); |
| 188 | } | 232 | } |
| 189 | if (struct_obj.layout == .@"extern" and !try sema.validateExternType(field_ty, .struct_field)) { | 233 | |
| 234 | if (struct_obj.layout == .@"extern" and !field_ty.validateExtern(.struct_field, zcu)) { | ||
| 190 | return sema.failWithOwnedErrorMsg(&block, msg: { | 235 | return sema.failWithOwnedErrorMsg(&block, msg: { |
| 191 | const msg = try sema.errMsg(field_ty_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | 236 | const msg = try sema.errMsg(field_ty_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); |
| 192 | errdefer msg.destroy(gpa); | 237 | errdefer msg.destroy(gpa); |
| ... | @@ -195,35 +240,14 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { | ... | @@ -195,35 +240,14 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { |
| 195 | break :msg msg; | 240 | break :msg msg; |
| 196 | }); | 241 | }); |
| 197 | } | 242 | } |
| 198 | |||
| 199 | struct_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern(); | ||
| 200 | if (struct_obj.field_aligns.len != 0) { | ||
| 201 | struct_obj.field_aligns.get(ip)[zir_field.idx] = explicit_field_align; | ||
| 202 | } else { | ||
| 203 | assert(explicit_field_align == .none); | ||
| 204 | } | ||
| 205 | } | 243 | } |
| 206 | 244 | ||
| 207 | try finishStructLayout(sema, &block, struct_ty.srcLoc(zcu), struct_ty.toIntern(), &struct_obj); | 245 | // Fields are okay. Now we need to resolve the struct's overall layout (size, field offsets, etc). |
| 208 | } | ||
| 209 | 246 | ||
| 210 | /// Called after populating field types and alignments; populates field offsets, runtime order, and | 247 | var any_comptime_fields = false; |
| 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; | ||
| 225 | var comptime_only = false; | 248 | var comptime_only = false; |
| 226 | var one_possible_value = true; | 249 | var one_possible_value = true; |
| 250 | var has_runtime_bits = false; | ||
| 227 | var struct_align: Alignment = .@"1"; | 251 | var struct_align: Alignment = .@"1"; |
| 228 | // Unlike `struct_obj.field_aligns`, these are not `.none`. | 252 | // Unlike `struct_obj.field_aligns`, these are not `.none`. |
| 229 | const resolved_field_aligns = try sema.arena.alloc(Alignment, struct_obj.field_names.len); | 253 | const resolved_field_aligns = try sema.arena.alloc(Alignment, struct_obj.field_names.len); |
| ... | @@ -240,12 +264,15 @@ pub fn finishStructLayout( | ... | @@ -240,12 +264,15 @@ pub fn finishStructLayout( |
| 240 | // Non-`comptime` fields contribute to the struct's layout. | 264 | // Non-`comptime` fields contribute to the struct's layout. |
| 241 | struct_align = struct_align.maxStrict(field_align); | 265 | struct_align = struct_align.maxStrict(field_align); |
| 242 | if (field_ty.comptimeOnly(zcu)) comptime_only = true; | 266 | if (field_ty.comptimeOnly(zcu)) comptime_only = true; |
| 267 | if (field_ty.hasRuntimeBits(zcu)) has_runtime_bits = true; | ||
| 243 | if (try field_ty.onePossibleValue(pt) == null) one_possible_value = false; | 268 | if (try field_ty.onePossibleValue(pt) == null) one_possible_value = false; |
| 244 | if (struct_obj.layout == .auto) { | 269 | if (struct_obj.layout == .auto) { |
| 245 | struct_obj.field_runtime_order.get(ip)[field_idx] = @enumFromInt(field_idx); | 270 | struct_obj.field_runtime_order.get(ip)[field_idx] = @enumFromInt(field_idx); |
| 246 | } | 271 | } |
| 247 | } else if (struct_obj.layout == .auto) { | 272 | } else { |
| 273 | assert(struct_obj.layout == .auto); // comptime fields not allowed in extern or packed structs | ||
| 248 | struct_obj.field_runtime_order.get(ip)[field_idx] = .omitted; // comptime fields are not in the runtime order | 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 | align_out.* = field_align; | 277 | align_out.* = field_align; |
| 251 | } | 278 | } |
| ... | @@ -297,75 +324,53 @@ pub fn finishStructLayout( | ... | @@ -297,75 +324,53 @@ pub fn finishStructLayout( |
| 297 | cur_offset = offset + field_ty.abiSize(zcu); | 324 | cur_offset = offset + field_ty.abiSize(zcu); |
| 298 | } | 325 | } |
| 299 | const struct_size = std.math.cast(u32, struct_align.forward(cur_offset)) orelse return sema.fail( | 326 | const struct_size = std.math.cast(u32, struct_align.forward(cur_offset)) orelse return sema.fail( |
| 300 | block, | 327 | &block, |
| 301 | struct_src, | 328 | struct_ty.srcLoc(zcu), |
| 302 | "struct layout requires size {d}, this compiler implementation supports up to {d}", | 329 | "struct layout requires size {d}, this compiler implementation supports up to {d}", |
| 303 | .{ struct_align.forward(cur_offset), std.math.maxInt(u32) }, | 330 | .{ struct_align.forward(cur_offset), std.math.maxInt(u32) }, |
| 304 | ); | 331 | ); |
| 305 | ip.resolveStructLayout( | 332 | ip.resolveStructLayout( |
| 306 | io, | 333 | io, |
| 307 | struct_ty, | 334 | struct_ty.toIntern(), |
| 308 | struct_size, | 335 | struct_size, |
| 309 | struct_align, | 336 | struct_align, |
| 310 | false, // MLUGG TODO XXX NPV | 337 | false, // MLUGG TODO XXX NPV |
| 311 | one_possible_value, | 338 | one_possible_value, |
| 312 | comptime_only, | 339 | comptime_only, |
| 340 | has_runtime_bits, | ||
| 313 | ); | 341 | ); |
| 342 | |||
| 343 | if (any_comptime_fields and !struct_obj.is_reified) { | ||
| 344 | // We also resolve field inits in this case. MLUGG TODO: this sucks, see TODO in resolveStructDefaults | ||
| 345 | return resolveStructDefaultsInner(sema, &block, &struct_obj); | ||
| 346 | } | ||
| 314 | } | 347 | } |
| 315 | 348 | ||
| 316 | /// Asserts that `struct_ty` is a packed struct, and that `sema.owner` is that type. | 349 | /// Asserts that `struct_ty` is a packed struct, and that `sema.owner` is that type. |
| 317 | /// This function *does* register the `src_hash` dependency on the struct. | 350 | /// This function *does* register the `src_hash` dependency on the struct. |
| 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 | const pt = sema.pt; | 357 | const pt = sema.pt; |
| 320 | const zcu = pt.zcu; | 358 | const zcu = pt.zcu; |
| 321 | const comp = zcu.comp; | 359 | const comp = zcu.comp; |
| 360 | const io = comp.io; | ||
| 322 | const gpa = comp.gpa; | 361 | const gpa = comp.gpa; |
| 323 | const ip = &zcu.intern_pool; | 362 | const ip = &zcu.intern_pool; |
| 324 | 363 | ||
| 325 | assert(sema.owner.unwrap().type_layout == struct_ty.toIntern()); | 364 | // Resolve the layout of all fields, and check their types are allowed. |
| 326 | 365 | // Also count the number of bits while we're at it. | |
| 327 | const struct_obj = ip.loadStructType(struct_ty.toIntern()); | ||
| 328 | const zir_index = struct_obj.zir_index.resolve(ip).?; | ||
| 329 | |||
| 330 | assert(struct_obj.layout == .@"packed"); | ||
| 331 | |||
| 332 | try sema.declareDependency(.{ .src_hash = struct_obj.zir_index }); | ||
| 333 | |||
| 334 | var block: Block = .{ | ||
| 335 | .parent = null, | ||
| 336 | .sema = sema, | ||
| 337 | .namespace = struct_obj.namespace, | ||
| 338 | .instructions = .{}, | ||
| 339 | .inlining = null, | ||
| 340 | .comptime_reason = undefined, // always set before using `block` | ||
| 341 | .src_base_inst = struct_obj.zir_index, | ||
| 342 | .type_name_ctx = struct_obj.name, | ||
| 343 | }; | ||
| 344 | defer assert(block.instructions.items.len == 0); | ||
| 345 | |||
| 346 | var field_bits: u64 = 0; | 366 | var field_bits: u64 = 0; |
| 347 | const zir_struct = sema.code.getStructDecl(zir_index); | 367 | for (struct_obj.field_types.get(ip), 0..) |field_ty_ip, field_index| { |
| 348 | var field_it = zir_struct.iterateFields(); | 368 | const field_ty: Type = .fromInterned(field_ty_ip); |
| 349 | while (field_it.next()) |zir_field| { | ||
| 350 | const field_ty_src: LazySrcLoc = .{ | ||
| 351 | .base_node_inst = struct_obj.zir_index, | ||
| 352 | .offset = .{ .container_field_type = zir_field.idx }, | ||
| 353 | }; | ||
| 354 | const field_ty: Type = field_ty: { | ||
| 355 | block.comptime_reason = .{ .reason = .{ | ||
| 356 | .src = field_ty_src, | ||
| 357 | .r = .{ .simple = .struct_field_types }, | ||
| 358 | } }; | ||
| 359 | const type_ref = try sema.resolveInlineBody(&block, zir_field.type_body, zir_index); | ||
| 360 | break :field_ty try sema.analyzeAsType(&block, field_ty_src, type_ref); | ||
| 361 | }; | ||
| 362 | assert(!field_ty.isGenericPoison()); | 369 | assert(!field_ty.isGenericPoison()); |
| 363 | struct_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern(); | 370 | const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) }); |
| 364 | |||
| 365 | try sema.ensureLayoutResolved(field_ty); | 371 | try sema.ensureLayoutResolved(field_ty); |
| 366 | |||
| 367 | if (field_ty.zigTypeTag(zcu) == .@"opaque") { | 372 | if (field_ty.zigTypeTag(zcu) == .@"opaque") { |
| 368 | return sema.failWithOwnedErrorMsg(&block, msg: { | 373 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 369 | const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in struct", .{field_ty.fmt(pt)}); | 374 | const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in struct", .{field_ty.fmt(pt)}); |
| 370 | errdefer msg.destroy(gpa); | 375 | errdefer msg.destroy(gpa); |
| 371 | try sema.errNote(field_ty_src, msg, "opaque types have unknown size", .{}); | 376 | try sema.errNote(field_ty_src, msg, "opaque types have unknown size", .{}); |
| ... | @@ -373,62 +378,73 @@ pub fn resolvePackedStructLayout(sema: *Sema, struct_ty: Type) CompileError!void | ... | @@ -373,62 +378,73 @@ pub fn resolvePackedStructLayout(sema: *Sema, struct_ty: Type) CompileError!void |
| 373 | break :msg msg; | 378 | break :msg msg; |
| 374 | }); | 379 | }); |
| 375 | } | 380 | } |
| 376 | if (!field_ty.packable(zcu)) { | 381 | if (field_ty.unpackable(zcu)) |reason| return sema.failWithOwnedErrorMsg(block, msg: { |
| 377 | return sema.failWithOwnedErrorMsg(&block, msg: { | 382 | const msg = try sema.errMsg(field_ty_src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); |
| 378 | const msg = try sema.errMsg(field_ty_src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | 383 | errdefer msg.destroy(gpa); |
| 379 | errdefer msg.destroy(gpa); | 384 | try sema.explainWhyTypeIsUnpackable(msg, field_ty_src, reason); |
| 380 | try sema.explainWhyTypeIsNotPackable(msg, field_ty_src, field_ty); | 385 | try sema.addDeclaredHereNote(msg, field_ty); |
| 381 | try sema.addDeclaredHereNote(msg, field_ty); | 386 | break :msg msg; |
| 382 | break :msg msg; | 387 | }); |
| 383 | }); | ||
| 384 | } | ||
| 385 | assert(!field_ty.comptimeOnly(zcu)); // packable types are not comptime-only | 388 | assert(!field_ty.comptimeOnly(zcu)); // packable types are not comptime-only |
| 386 | field_bits += field_ty.bitSize(zcu); | 389 | field_bits += field_ty.bitSize(zcu); |
| 387 | } | 390 | } |
| 388 | 391 | ||
| 389 | try resolvePackedStructBackingInt(sema, &block, field_bits, struct_ty, &struct_obj); | 392 | const explicit_backing_int_ty: ?Type = if (struct_obj.is_reified) ty: { |
| 390 | } | 393 | break :ty switch (struct_obj.packed_backing_mode) { |
| 391 | 394 | .explicit => .fromInterned(struct_obj.packed_backing_int_type), | |
| 392 | pub fn resolvePackedStructBackingInt( | 395 | .auto => null, |
| 393 | sema: *Sema, | 396 | }; |
| 394 | block: *Block, | 397 | } else ty: { |
| 395 | field_bits: u64, | 398 | const zir_index = struct_obj.zir_index.resolve(ip).?; |
| 396 | struct_ty: Type, | 399 | const zir_struct = sema.code.getStructDecl(zir_index); |
| 397 | struct_obj: *const InternPool.LoadedStructType, | 400 | const backing_int_type_body = zir_struct.backing_int_type_body orelse { |
| 398 | ) SemaError!void { | 401 | break :ty null; // inferred backing type |
| 399 | const pt = sema.pt; | 402 | }; |
| 400 | const zcu = pt.zcu; | 403 | // Explicitly specified, so evaluate the backing int type expression. |
| 401 | const comp = zcu.comp; | 404 | const backing_int_type_src = block.src(.container_arg); |
| 402 | const gpa = comp.gpa; | 405 | block.comptime_reason = .{ .reason = .{ |
| 403 | const io = comp.io; | 406 | .src = backing_int_type_src, |
| 404 | const ip = &zcu.intern_pool; | 407 | .r = .{ .simple = .packed_struct_backing_int_type }, |
| 408 | } }; | ||
| 409 | const type_ref = try sema.resolveInlineBody(block, backing_int_type_body, zir_index); | ||
| 410 | break :ty try sema.analyzeAsType(block, backing_int_type_src, .packed_struct_backing_int_type, type_ref); | ||
| 411 | }; | ||
| 405 | 412 | ||
| 406 | switch (struct_obj.packed_backing_mode) { | 413 | // Finally, either validate or infer the backing int type. |
| 407 | .explicit => { | 414 | const backing_int_ty: Type = if (explicit_backing_int_ty) |backing_ty| ty: { |
| 408 | // We only need to validate the type. | 415 | // We only need to validate the type. |
| 409 | const backing_ty: Type = .fromInterned(struct_obj.packed_backing_int_type); | 416 | if (backing_ty.zigTypeTag(zcu) != .int) return sema.failWithOwnedErrorMsg(block, msg: { |
| 410 | assert(backing_ty.zigTypeTag(zcu) == .int); | 417 | const src = struct_ty.srcLoc(zcu); |
| 411 | if (field_bits != backing_ty.intInfo(zcu).bits) return sema.failWithOwnedErrorMsg(block, msg: { | 418 | const msg = try sema.errMsg(src, "expected backing integer type, found '{f}'", .{backing_ty.fmt(pt)}); |
| 412 | const src = struct_ty.srcLoc(zcu); | 419 | errdefer msg.destroy(gpa); |
| 413 | const msg = try sema.errMsg(src, "backing integer bit width does not match total bit width of fields", .{}); | 420 | try sema.errNote(src, msg, "backing integer '{f}' has bit width '{d}'", .{ backing_ty.fmt(pt), backing_ty.bitSize(zcu) }); |
| 414 | errdefer msg.destroy(gpa); | 421 | try sema.errNote(src, msg, "struct fields have total bit width '{d}'", .{field_bits}); |
| 415 | try sema.errNote(src, msg, "backing integer '{f}' has bit width '{d}'", .{ backing_ty.fmt(pt), backing_ty.bitSize(zcu) }); | 422 | break :msg msg; |
| 416 | try sema.errNote(src, msg, "struct fields have total bit width '{d}'", .{field_bits}); | 423 | }); |
| 417 | break :msg msg; | 424 | if (field_bits != backing_ty.intInfo(zcu).bits) return sema.failWithOwnedErrorMsg(block, msg: { |
| 418 | }); | 425 | const src = struct_ty.srcLoc(zcu); |
| 419 | }, | 426 | const msg = try sema.errMsg(src, "backing integer bit width does not match total bit width of fields", .{}); |
| 420 | .auto => { | 427 | errdefer msg.destroy(gpa); |
| 421 | // We need to generate the inferred tag. | 428 | try sema.errNote(src, msg, "backing integer '{f}' has bit width '{d}'", .{ backing_ty.fmt(pt), backing_ty.bitSize(zcu) }); |
| 422 | const want_bits = std.math.cast(u16, field_bits) orelse return sema.fail( | 429 | try sema.errNote(src, msg, "struct fields have total bit width '{d}'", .{field_bits}); |
| 423 | block, | 430 | break :msg msg; |
| 424 | struct_ty.srcLoc(zcu), | 431 | }); |
| 425 | "packed struct bit width '{d}' exceeds maximum bit width of 65535", | 432 | break :ty backing_ty; |
| 426 | .{field_bits}, | 433 | } else ty: { |
| 427 | ); | 434 | // We need to generate the inferred tag. |
| 428 | const backing_int = try pt.intType(.unsigned, want_bits); | 435 | const backing_int_bits = std.math.cast(u16, field_bits) orelse return sema.fail( |
| 429 | ip.resolvePackedStructBackingInt(io, struct_ty.toIntern(), backing_int.toIntern()); | 436 | block, |
| 430 | }, | 437 | struct_ty.srcLoc(zcu), |
| 431 | } | 438 | "packed struct bit width '{d}' exceeds maximum bit width of 65535", |
| 439 | .{field_bits}, | ||
| 440 | ); | ||
| 441 | break :ty try pt.intType(.unsigned, backing_int_bits); | ||
| 442 | }; | ||
| 443 | ip.resolvePackedStructLayout( | ||
| 444 | io, | ||
| 445 | struct_ty.toIntern(), | ||
| 446 | backing_int_ty.toIntern(), | ||
| 447 | ); | ||
| 432 | } | 448 | } |
| 433 | 449 | ||
| 434 | /// Asserts that `struct_ty` is a non-tuple struct, and that `sema.owner` is that type. | 450 | /// Asserts that `struct_ty` is a non-tuple struct, and that `sema.owner` is that type. |
| ... | @@ -436,25 +452,33 @@ pub fn resolvePackedStructBackingInt( | ... | @@ -436,25 +452,33 @@ pub fn resolvePackedStructBackingInt( |
| 436 | pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void { | 452 | pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void { |
| 437 | const pt = sema.pt; | 453 | const pt = sema.pt; |
| 438 | const zcu = pt.zcu; | 454 | const zcu = pt.zcu; |
| 439 | const comp = zcu.comp; | ||
| 440 | const gpa = comp.gpa; | ||
| 441 | const ip = &zcu.intern_pool; | 455 | const ip = &zcu.intern_pool; |
| 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 | try sema.ensureLayoutResolved(struct_ty); | 459 | try sema.ensureLayoutResolved(struct_ty); |
| 446 | 460 | ||
| 447 | const struct_obj = ip.loadStructType(struct_ty.toIntern()); | 461 | const struct_obj = ip.loadStructType(struct_ty.toIntern()); |
| 448 | const zir_index = struct_obj.zir_index.resolve(ip).?; | ||
| 449 | 462 | ||
| 450 | try sema.declareDependency(.{ .src_hash = struct_obj.zir_index }); | 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 | if (struct_obj.field_defaults.len == 0) { | 470 | if (struct_obj.field_defaults.len == 0) { |
| 453 | // The struct has no default field values, so the slice has been omitted. | 471 | // The struct has no default field values, so the slice has been omitted. |
| 454 | return; | 472 | return; |
| 455 | } | 473 | } |
| 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 | var block: Block = .{ | 483 | var block: Block = .{ |
| 460 | .parent = null, | 484 | .parent = null, |
| ... | @@ -468,16 +492,30 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void { | ... | @@ -468,16 +492,30 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void { |
| 468 | }; | 492 | }; |
| 469 | defer assert(block.instructions.items.len == 0); | 493 | defer assert(block.instructions.items.len == 0); |
| 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 | // We'll need to map the struct decl instruction to provide result types | 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 | try sema.inst_map.ensureSpaceForInstructions(gpa, &.{zir_index}); | 511 | try sema.inst_map.ensureSpaceForInstructions(gpa, &.{zir_index}); |
| 473 | 512 | ||
| 513 | const field_types = struct_obj.field_types.get(ip); | ||
| 514 | |||
| 474 | const zir_struct = sema.code.getStructDecl(zir_index); | 515 | const zir_struct = sema.code.getStructDecl(zir_index); |
| 475 | var field_it = zir_struct.iterateFields(); | 516 | var field_it = zir_struct.iterateFields(); |
| 476 | while (field_it.next()) |zir_field| { | 517 | while (field_it.next()) |zir_field| { |
| 477 | const default_val_src: LazySrcLoc = .{ | 518 | const default_val_src = block.src(.{ .container_field_value = zir_field.idx }); |
| 478 | .base_node_inst = struct_obj.zir_index, | ||
| 479 | .offset = .{ .container_field_value = zir_field.idx }, | ||
| 480 | }; | ||
| 481 | block.comptime_reason = .{ .reason = .{ | 519 | block.comptime_reason = .{ .reason = .{ |
| 482 | .src = default_val_src, | 520 | .src = default_val_src, |
| 483 | .r = .{ .simple = .struct_field_default_value }, | 521 | .r = .{ .simple = .struct_field_default_value }, |
| ... | @@ -491,13 +529,13 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void { | ... | @@ -491,13 +529,13 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void { |
| 491 | // Provide the result type | 529 | // Provide the result type |
| 492 | sema.inst_map.putAssumeCapacity(zir_index, .fromIntern(field_ty.toIntern())); | 530 | sema.inst_map.putAssumeCapacity(zir_index, .fromIntern(field_ty.toIntern())); |
| 493 | defer assert(sema.inst_map.remove(zir_index)); | 531 | defer assert(sema.inst_map.remove(zir_index)); |
| 494 | break :ref try sema.resolveInlineBody(&block, default_body, zir_index); | 532 | break :ref try sema.resolveInlineBody(block, default_body, zir_index); |
| 495 | }; | 533 | }; |
| 496 | const coerced = try sema.coerce(&block, field_ty, uncoerced, default_val_src); | 534 | const coerced = try sema.coerce(block, field_ty, uncoerced, default_val_src); |
| 497 | const default_val = try sema.resolveConstValue(&block, default_val_src, coerced, null); | 535 | const default_val = try sema.resolveConstValue(block, default_val_src, coerced, null); |
| 498 | if (default_val.canMutateComptimeVarState(zcu)) { | 536 | if (default_val.canMutateComptimeVarState(zcu)) { |
| 499 | const field_name = struct_obj.field_names.get(ip)[zir_field.idx]; | 537 | const field_name = struct_obj.field_names.get(ip)[zir_field.idx]; |
| 500 | return sema.failWithContainsReferenceToComptimeVar(&block, default_val_src, field_name, "field default value", default_val); | 538 | return sema.failWithContainsReferenceToComptimeVar(block, default_val_src, field_name, "field default value", default_val); |
| 501 | } | 539 | } |
| 502 | struct_obj.field_defaults.get(ip)[zir_field.idx] = default_val.toIntern(); | 540 | struct_obj.field_defaults.get(ip)[zir_field.idx] = default_val.toIntern(); |
| 503 | } | 541 | } |
| ... | @@ -508,6 +546,7 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { | ... | @@ -508,6 +546,7 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { |
| 508 | const pt = sema.pt; | 546 | const pt = sema.pt; |
| 509 | const zcu = pt.zcu; | 547 | const zcu = pt.zcu; |
| 510 | const comp = zcu.comp; | 548 | const comp = zcu.comp; |
| 549 | const io = comp.io; | ||
| 511 | const gpa = comp.gpa; | 550 | const gpa = comp.gpa; |
| 512 | const ip = &zcu.intern_pool; | 551 | const ip = &zcu.intern_pool; |
| 513 | 552 | ||
| ... | @@ -516,10 +555,6 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { | ... | @@ -516,10 +555,6 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { |
| 516 | const union_obj = ip.loadUnionType(union_ty.toIntern()); | 555 | const union_obj = ip.loadUnionType(union_ty.toIntern()); |
| 517 | const zir_index = union_obj.zir_index.resolve(ip).?; | 556 | const zir_index = union_obj.zir_index.resolve(ip).?; |
| 518 | 557 | ||
| 519 | assert(union_obj.layout != .@"packed"); | ||
| 520 | |||
| 521 | try sema.declareDependency(.{ .src_hash = union_obj.zir_index }); | ||
| 522 | |||
| 523 | var block: Block = .{ | 558 | var block: Block = .{ |
| 524 | .parent = null, | 559 | .parent = null, |
| 525 | .sema = sema, | 560 | .sema = sema, |
| ... | @@ -532,48 +567,169 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { | ... | @@ -532,48 +567,169 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { |
| 532 | }; | 567 | }; |
| 533 | defer assert(block.instructions.items.len == 0); | 568 | defer assert(block.instructions.items.len == 0); |
| 534 | 569 | ||
| 535 | const zir_union = sema.code.getUnionDecl(zir_index); | 570 | // MLUGG TODO: this is fucking ugly bro |
| 536 | var field_it = zir_union.iterateFields(); | 571 | const explicit_enum_tag_ty: ?Type = if (union_obj.is_reified) ty: { |
| 537 | while (field_it.next()) |zir_field| { | 572 | break :ty switch (union_obj.enum_tag_mode) { |
| 538 | const field_ty_src: LazySrcLoc = .{ | 573 | .explicit => .fromInterned(union_obj.enum_tag_type), |
| 539 | .base_node_inst = union_obj.zir_index, | 574 | .auto => null, |
| 540 | .offset = .{ .container_field_type = zir_field.idx }, | ||
| 541 | }; | ||
| 542 | const field_align_src: LazySrcLoc = .{ | ||
| 543 | .base_node_inst = union_obj.zir_index, | ||
| 544 | .offset = .{ .container_field_align = zir_field.idx }, | ||
| 545 | }; | 575 | }; |
| 576 | } else ty: { | ||
| 577 | const zir_union = sema.code.getUnionDecl(zir_index); | ||
| 578 | if (zir_union.kind != .tagged_explicit) { | ||
| 579 | break :ty null; // enum tag type will be automatically generated | ||
| 580 | } | ||
| 581 | // Explicitly specified, so evaluate the enum tag type expression. | ||
| 582 | const tag_type_body = zir_union.arg_type_body.?; | ||
| 583 | const tag_type_src = block.src(.container_arg); | ||
| 584 | block.comptime_reason = .{ .reason = .{ | ||
| 585 | .src = tag_type_src, | ||
| 586 | .r = .{ .simple = .union_enum_tag_type }, | ||
| 587 | } }; | ||
| 588 | const type_ref = try sema.resolveInlineBody(&block, tag_type_body, zir_index); | ||
| 589 | break :ty try sema.analyzeAsType(&block, tag_type_src, .union_enum_tag_type, type_ref); | ||
| 590 | }; | ||
| 591 | const enum_tag_ty: Type = if (explicit_enum_tag_ty) |enum_tag_ty| ty: { | ||
| 592 | if (enum_tag_ty.zigTypeTag(zcu) != .@"enum") return sema.fail( | ||
| 593 | &block, | ||
| 594 | block.src(.container_arg), | ||
| 595 | "expected enum tag type, found '{f}'", | ||
| 596 | .{enum_tag_ty.fmt(pt)}, | ||
| 597 | ); | ||
| 598 | break :ty enum_tag_ty; | ||
| 599 | } else switch (try ip.getGeneratedEnumTagType(gpa, io, pt.tid, .{ | ||
| 600 | .union_type = union_ty.toIntern(), | ||
| 601 | // MLUGG TODO: a bit hacky icl | ||
| 602 | .int_tag_mode = mode: { | ||
| 603 | if (union_obj.is_reified) break :mode .auto; | ||
| 604 | const zir_union = sema.code.getUnionDecl(zir_index); | ||
| 605 | if (zir_union.kind != .tagged_enum_explicit) break :mode .auto; | ||
| 606 | break :mode .explicit; | ||
| 607 | }, | ||
| 608 | .fields_len = @intCast(union_obj.field_types.len), | ||
| 609 | })) { | ||
| 610 | .existing => |tag_ty| .fromInterned(tag_ty), | ||
| 611 | .wip => |wip| tag_ty: { | ||
| 612 | errdefer wip.cancel(ip, pt.tid); | ||
| 613 | _ = wip.setName(ip, try ip.getOrPutStringFmt( | ||
| 614 | gpa, | ||
| 615 | io, | ||
| 616 | pt.tid, | ||
| 617 | "@typeInfo({f}).@\"union\".tag_type.?", | ||
| 618 | .{union_obj.name.fmt(ip)}, | ||
| 619 | .no_embedded_nulls, | ||
| 620 | ), .none); | ||
| 621 | const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ | ||
| 622 | .parent = union_obj.namespace.toOptional(), | ||
| 623 | .owner_type = wip.index, | ||
| 624 | .file_scope = zcu.namespacePtr(union_obj.namespace).file_scope, | ||
| 625 | .generation = zcu.generation, | ||
| 626 | }); | ||
| 627 | if (comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); | ||
| 628 | try zcu.outdated.ensureUnusedCapacity(gpa, 1); | ||
| 629 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); | ||
| 630 | errdefer comptime unreachable; // because we don't remove the `outdated` entry | ||
| 631 | zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); | ||
| 632 | zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); | ||
| 633 | break :tag_ty .fromInterned(wip.finish(ip, new_namespace_index)); | ||
| 634 | }, | ||
| 635 | }; | ||
| 546 | 636 | ||
| 547 | const field_ty: Type = field_ty: { | 637 | try sema.ensureLayoutResolved(enum_tag_ty); |
| 548 | block.comptime_reason = .{ .reason = .{ | 638 | const enum_obj = ip.loadEnumType(enum_tag_ty.toIntern()); |
| 549 | .src = field_ty_src, | 639 | |
| 550 | .r = .{ .simple = .union_field_types }, | 640 | if (union_obj.is_reified) { |
| 551 | } }; | 641 | // We have field names in `union_obj.reified_field_names`, but we haven't |
| 552 | const type_body = zir_field.type_body orelse break :field_ty .void; | 642 | // checked them against the backing type yet. |
| 553 | const type_ref = try sema.resolveInlineBody(&block, type_body, zir_index); | 643 | const union_field_names = union_obj.reified_field_names.get(ip); |
| 554 | break :field_ty try sema.analyzeAsType(&block, field_ty_src, type_ref); | 644 | match_fields: { |
| 555 | }; | 645 | // We can efficiently *check* if the fields match... |
| 556 | assert(!field_ty.isGenericPoison()); | 646 | if (union_field_names.len == enum_obj.field_names.len) { |
| 557 | union_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern(); | 647 | for (union_field_names, enum_obj.field_names.get(ip)) |union_field_name, enum_field_name| { |
| 558 | 648 | if (!std.mem.eql(u8, union_field_name.toSlice(ip), enum_field_name.toSlice(ip))) break; | |
| 559 | try sema.ensureLayoutResolved(field_ty); | 649 | } else { |
| 650 | break :match_fields; | ||
| 651 | } | ||
| 652 | } | ||
| 653 | // ...but if they don't, reporting a nice error is a little more involved. If some field | ||
| 654 | // is present in the enum but not the union, or vice versa, we will report that instead | ||
| 655 | // of a generic "field order mismatch" error. Of course, this error is impossible for a | ||
| 656 | // generated tag type, because we populated that from the union ZIR! | ||
| 657 | assert(enum_obj.owner_union != union_ty.toIntern()); | ||
| 658 | return failUnionFieldMismatch(sema, &block, union_field_names, enum_tag_ty, &enum_obj); | ||
| 659 | } | ||
| 660 | } else { | ||
| 661 | // Declared unions do not have field types or aligns populated yet. | ||
| 662 | // We also need to check the field names match the backing enum. | ||
| 663 | try sema.declareDependency(.{ .src_hash = union_obj.zir_index }); | ||
| 664 | const zir_union = sema.code.getUnionDecl(zir_index); | ||
| 560 | 665 | ||
| 561 | const explicit_field_align: Alignment = a: { | 666 | // We'll first check the field names against the backing enum, and only analyze the types |
| 562 | block.comptime_reason = .{ .reason = .{ | 667 | // once we know the fields match one-to-one. |
| 563 | .src = field_align_src, | 668 | match_fields: { |
| 564 | .r = .{ .simple = .union_field_attrs }, | 669 | // We can efficiently *check* if the fields match... |
| 565 | } }; | 670 | if (zir_union.field_names.len == enum_obj.field_names.len) { |
| 566 | const align_body = zir_field.align_body orelse break :a .none; | 671 | for (zir_union.field_names, enum_obj.field_names.get(ip)) |union_field_name_zir, enum_field_name| { |
| 567 | const align_ref = try sema.resolveInlineBody(&block, align_body, zir_index); | 672 | const union_field_name_slice = sema.code.nullTerminatedString(union_field_name_zir); |
| 568 | break :a try sema.analyzeAsAlign(&block, field_align_src, align_ref); | 673 | if (!std.mem.eql(u8, union_field_name_slice, enum_field_name.toSlice(ip))) break; |
| 569 | }; | 674 | } else { |
| 675 | break :match_fields; | ||
| 676 | } | ||
| 677 | } | ||
| 678 | // ...but if they don't, reporting a nice error is a little more involved. If some field | ||
| 679 | // is present in the enum but not the union, or vice versa, we will report that instead | ||
| 680 | // of a generic "field order mismatch" error. Of course, this error is impossible for a | ||
| 681 | // generated tag type, because we populated that from the union ZIR! | ||
| 682 | assert(enum_obj.owner_union != union_ty.toIntern()); | ||
| 683 | const union_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, zir_union.field_names.len); | ||
| 684 | for (zir_union.field_names, union_field_names) |name_zir, *name| { | ||
| 685 | name.* = try ip.getOrPutString(gpa, io, pt.tid, sema.code.nullTerminatedString(name_zir), .no_embedded_nulls); | ||
| 686 | } | ||
| 687 | return failUnionFieldMismatch(sema, &block, union_field_names, enum_tag_ty, &enum_obj); | ||
| 688 | } | ||
| 570 | 689 | ||
| 571 | if (union_obj.field_aligns.len != 0) { | 690 | // Field names okay; populate types and aligns. |
| 572 | union_obj.field_aligns.get(ip)[zir_field.idx] = explicit_field_align; | 691 | var field_it = zir_union.iterateFields(); |
| 573 | } else { | 692 | while (field_it.next()) |zir_field| { |
| 574 | assert(explicit_field_align == .none); | 693 | const field_ty_src = block.src(.{ .container_field_type = zir_field.idx }); |
| 694 | const field_ty: Type = field_ty: { | ||
| 695 | block.comptime_reason = .{ .reason = .{ | ||
| 696 | .src = field_ty_src, | ||
| 697 | .r = .{ .simple = .union_field_types }, | ||
| 698 | } }; | ||
| 699 | const type_body = zir_field.type_body orelse break :field_ty .void; | ||
| 700 | const type_ref = try sema.resolveInlineBody(&block, type_body, zir_index); | ||
| 701 | break :field_ty try sema.analyzeAsType(&block, field_ty_src, .union_field_types, type_ref); | ||
| 702 | }; | ||
| 703 | union_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern(); | ||
| 704 | |||
| 705 | const field_align_src = block.src(.{ .container_field_align = zir_field.idx }); | ||
| 706 | const explicit_field_align: Alignment = a: { | ||
| 707 | block.comptime_reason = .{ .reason = .{ | ||
| 708 | .src = field_align_src, | ||
| 709 | .r = .{ .simple = .union_field_attrs }, | ||
| 710 | } }; | ||
| 711 | const align_body = zir_field.align_body orelse break :a .none; | ||
| 712 | const align_ref = try sema.resolveInlineBody(&block, align_body, zir_index); | ||
| 713 | break :a try sema.analyzeAsAlign(&block, field_align_src, align_ref); | ||
| 714 | }; | ||
| 715 | if (union_obj.field_aligns.len != 0) { | ||
| 716 | union_obj.field_aligns.get(ip)[zir_field.idx] = explicit_field_align; | ||
| 717 | } else { | ||
| 718 | assert(explicit_field_align == .none); | ||
| 719 | } | ||
| 575 | } | 720 | } |
| 721 | } | ||
| 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 | if (field_ty.zigTypeTag(zcu) == .@"opaque") { | 733 | if (field_ty.zigTypeTag(zcu) == .@"opaque") { |
| 578 | return sema.failWithOwnedErrorMsg(&block, msg: { | 734 | return sema.failWithOwnedErrorMsg(&block, msg: { |
| 579 | const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in union", .{field_ty.fmt(pt)}); | 735 | const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in union", .{field_ty.fmt(pt)}); |
| ... | @@ -583,7 +739,7 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { | ... | @@ -583,7 +739,7 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { |
| 583 | break :msg msg; | 739 | break :msg msg; |
| 584 | }); | 740 | }); |
| 585 | } | 741 | } |
| 586 | if (union_obj.layout == .@"extern" and !try sema.validateExternType(field_ty, .union_field)) { | 742 | if (union_obj.layout == .@"extern" and !field_ty.validateExtern(.union_field, zcu)) { |
| 587 | return sema.failWithOwnedErrorMsg(&block, msg: { | 743 | return sema.failWithOwnedErrorMsg(&block, msg: { |
| 588 | const msg = try sema.errMsg(field_ty_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | 744 | const msg = try sema.errMsg(field_ty_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); |
| 589 | errdefer msg.destroy(gpa); | 745 | errdefer msg.destroy(gpa); |
| ... | @@ -594,36 +750,11 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { | ... | @@ -594,36 +750,11 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { |
| 594 | } | 750 | } |
| 595 | } | 751 | } |
| 596 | 752 | ||
| 597 | try finishUnionLayout( | 753 | // Fields are okay. Now we need to resolve the union's overall layout (size, alignment, etc). |
| 598 | sema, | ||
| 599 | &block, | ||
| 600 | union_ty.srcLoc(zcu), | ||
| 601 | union_ty.toIntern(), | ||
| 602 | &union_obj, | ||
| 603 | .fromInterned(union_obj.enum_tag_type), | ||
| 604 | ); | ||
| 605 | } | ||
| 606 | |||
| 607 | /// Called after populating field types and alignments; populates overall union layout | ||
| 608 | /// information (size, alignment, comptime-only state, etc). | ||
| 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 | |||
| 624 | var payload_align: Alignment = .@"1"; | 754 | var payload_align: Alignment = .@"1"; |
| 625 | var payload_size: u64 = 0; | 755 | var payload_size: u64 = 0; |
| 626 | var comptime_only = false; | 756 | var comptime_only = false; |
| 757 | var has_runtime_bits = union_obj.runtime_tag != .none and enum_tag_ty.hasRuntimeBits(zcu); | ||
| 627 | var possible_values: enum { none, one, many } = .none; | 758 | var possible_values: enum { none, one, many } = .none; |
| 628 | for (0..union_obj.field_types.len) |field_idx| { | 759 | for (0..union_obj.field_types.len) |field_idx| { |
| 629 | const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_idx]); | 760 | const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_idx]); |
| ... | @@ -637,6 +768,7 @@ pub fn finishUnionLayout( | ... | @@ -637,6 +768,7 @@ pub fn finishUnionLayout( |
| 637 | payload_align = payload_align.maxStrict(field_align); | 768 | payload_align = payload_align.maxStrict(field_align); |
| 638 | payload_size = @max(payload_size, field_ty.abiSize(zcu)); | 769 | payload_size = @max(payload_size, field_ty.abiSize(zcu)); |
| 639 | if (field_ty.comptimeOnly(zcu)) comptime_only = true; | 770 | if (field_ty.comptimeOnly(zcu)) comptime_only = true; |
| 771 | if (field_ty.hasRuntimeBits(zcu)) has_runtime_bits = true; | ||
| 640 | if (!field_ty.isNoReturn(zcu)) { | 772 | if (!field_ty.isNoReturn(zcu)) { |
| 641 | if (try field_ty.onePossibleValue(pt) != null) { | 773 | if (try field_ty.onePossibleValue(pt) != null) { |
| 642 | possible_values = .many; // this field alone has many possible values | 774 | possible_values = .many; // this field alone has many possible values |
| ... | @@ -664,78 +796,100 @@ pub fn finishUnionLayout( | ... | @@ -664,78 +796,100 @@ pub fn finishUnionLayout( |
| 664 | }; | 796 | }; |
| 665 | 797 | ||
| 666 | const casted_size = std.math.cast(u32, size) orelse return sema.fail( | 798 | const casted_size = std.math.cast(u32, size) orelse return sema.fail( |
| 667 | block, | 799 | &block, |
| 668 | union_src, | 800 | union_ty.srcLoc(zcu), |
| 669 | "union layout requires size {d}, this compiler implementation supports up to {d}", | 801 | "union layout requires size {d}, this compiler implementation supports up to {d}", |
| 670 | .{ size, std.math.maxInt(u32) }, | 802 | .{ size, std.math.maxInt(u32) }, |
| 671 | ); | 803 | ); |
| 672 | ip.resolveUnionLayout( | 804 | ip.resolveUnionLayout( |
| 673 | io, | 805 | io, |
| 674 | union_ty, | 806 | union_ty.toIntern(), |
| 807 | enum_tag_ty.toIntern(), | ||
| 675 | casted_size, | 808 | casted_size, |
| 676 | @intCast(padding), // okay because padding is no greater than size | 809 | @intCast(padding), // okay because padding is no greater than size |
| 677 | alignment, | 810 | alignment, |
| 678 | possible_values == .none, // MLUGG TODO: make sure queries use `LoadedUnionType.has_no_possible_value`! | 811 | possible_values == .none, // MLUGG TODO: make sure queries use `LoadedUnionType.has_no_possible_value`! |
| 679 | possible_values == .one, | 812 | possible_values == .one, |
| 680 | comptime_only, | 813 | comptime_only, |
| 814 | has_runtime_bits, | ||
| 681 | ); | 815 | ); |
| 682 | } | 816 | } |
| 683 | 817 | fn failUnionFieldMismatch(sema: *Sema, block: *Block, union_field_names: []const InternPool.NullTerminatedString, enum_tag_ty: Type, enum_obj: *const InternPool.LoadedEnumType) CompileError { | |
| 684 | pub fn resolvePackedUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { | ||
| 685 | const pt = sema.pt; | 818 | const pt = sema.pt; |
| 686 | const zcu = pt.zcu; | 819 | const zcu = pt.zcu; |
| 687 | const comp = zcu.comp; | 820 | const comp = zcu.comp; |
| 688 | const gpa = comp.gpa; | 821 | const gpa = comp.gpa; |
| 689 | const ip = &zcu.intern_pool; | 822 | const ip = &zcu.intern_pool; |
| 690 | 823 | const enum_to_union_map = try sema.arena.alloc(?u32, enum_obj.field_names.len); | |
| 691 | assert(sema.owner.unwrap().type_layout == union_ty.toIntern()); | 824 | @memset(enum_to_union_map, null); |
| 692 | 825 | for (union_field_names, 0..) |field_name, union_field_index| { | |
| 693 | const union_obj = ip.loadUnionType(union_ty.toIntern()); | 826 | if (enum_obj.nameIndex(ip, field_name)) |enum_field_index| { |
| 694 | const zir_index = union_obj.zir_index.resolve(ip).?; | 827 | enum_to_union_map[enum_field_index] = @intCast(union_field_index); |
| 695 | 828 | continue; | |
| 696 | assert(union_obj.layout == .@"packed"); | 829 | } |
| 697 | 830 | const union_field_src = block.src(.{ .container_field_name = @intCast(union_field_index) }); | |
| 698 | try sema.declareDependency(.{ .src_hash = union_obj.zir_index }); | 831 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 699 | 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) }); | |
| 700 | var block: Block = .{ | 833 | errdefer msg.destroy(gpa); |
| 701 | .parent = null, | 834 | try sema.addDeclaredHereNote(msg, enum_tag_ty); |
| 702 | .sema = sema, | 835 | break :msg msg; |
| 703 | .namespace = union_obj.namespace, | 836 | }); |
| 704 | .instructions = .{}, | 837 | } |
| 705 | .inlining = null, | 838 | for (enum_to_union_map, 0..) |union_field_index, enum_field_index| { |
| 706 | .comptime_reason = undefined, // always set before using `block` | 839 | if (union_field_index != null) continue; |
| 707 | .src_base_inst = union_obj.zir_index, | 840 | const field_name_ip = enum_obj.field_names.get(ip)[enum_field_index]; |
| 708 | .type_name_ctx = union_obj.name, | 841 | const enum_field_src: LazySrcLoc = .{ |
| 709 | }; | 842 | .base_node_inst = enum_tag_ty.typeDeclInstAllowGeneratedTag(zcu).?, |
| 710 | defer assert(block.instructions.items.len == 0); | 843 | .offset = .{ .container_field_name = @intCast(enum_field_index) }, |
| 711 | |||
| 712 | const zir_union = sema.code.getUnionDecl(zir_index); | ||
| 713 | var field_it = zir_union.iterateFields(); | ||
| 714 | while (field_it.next()) |zir_field| { | ||
| 715 | const field_ty_src: LazySrcLoc = .{ | ||
| 716 | .base_node_inst = union_obj.zir_index, | ||
| 717 | .offset = .{ .container_field_type = zir_field.idx }, | ||
| 718 | }; | 844 | }; |
| 719 | const field_ty: Type = field_ty: { | 845 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 720 | block.comptime_reason = .{ .reason = .{ | 846 | const msg = try sema.errMsg(block.nodeOffset(.zero), "enum field '{f}' missing from union", .{field_name_ip.fmt(ip)}); |
| 721 | .src = field_ty_src, | 847 | errdefer msg.destroy(gpa); |
| 722 | .r = .{ .simple = .union_field_types }, | 848 | try sema.errNote(enum_field_src, msg, "enum field here", .{}); |
| 723 | } }; | 849 | break :msg msg; |
| 724 | // MLUGG TODO: i think this should probably be a compile error? (if so, it's an astgen one, right?) | 850 | }); |
| 725 | const type_body = zir_field.type_body orelse break :field_ty .void; | 851 | } |
| 726 | const type_ref = try sema.resolveInlineBody(&block, type_body, zir_index); | 852 | // The only problem is the field ordering. |
| 727 | break :field_ty try sema.analyzeAsType(&block, field_ty_src, type_ref); | 853 | for (enum_to_union_map, 0..) |union_field_index, enum_field_index| { |
| 854 | if (union_field_index.? == enum_field_index) continue; | ||
| 855 | const field_name = enum_obj.field_names.get(ip)[enum_field_index]; | ||
| 856 | const union_field_src = block.src(.{ .container_field_name = union_field_index.? }); | ||
| 857 | const enum_field_src: LazySrcLoc = .{ | ||
| 858 | .base_node_inst = enum_tag_ty.typeDeclInstAllowGeneratedTag(zcu).?, | ||
| 859 | .offset = .{ .container_field_name = @intCast(enum_field_index) }, | ||
| 728 | }; | 860 | }; |
| 729 | assert(!field_ty.isGenericPoison()); | 861 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 730 | union_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern(); | 862 | const msg = try sema.errMsg(block.nodeOffset(.zero), "union field order does not match tag enum field order", .{}); |
| 731 | 863 | errdefer msg.destroy(gpa); | |
| 732 | assert(zir_field.align_body == null); // packed union fields cannot be aligned | 864 | try sema.errNote(union_field_src, msg, "union field '{f}' is index {d}", .{ field_name.fmt(ip), union_field_index.? }); |
| 733 | assert(zir_field.value_body == null); // packed union fields cannot have tag values | 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 | try sema.ensureLayoutResolved(field_ty); | 890 | try sema.ensureLayoutResolved(field_ty); |
| 736 | |||
| 737 | if (field_ty.zigTypeTag(zcu) == .@"opaque") { | 891 | if (field_ty.zigTypeTag(zcu) == .@"opaque") { |
| 738 | return sema.failWithOwnedErrorMsg(&block, msg: { | 892 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 739 | const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in union", .{field_ty.fmt(pt)}); | 893 | const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in union", .{field_ty.fmt(pt)}); |
| 740 | errdefer msg.destroy(gpa); | 894 | errdefer msg.destroy(gpa); |
| 741 | try sema.errNote(field_ty_src, msg, "opaque types have unknown size", .{}); | 895 | try sema.errNote(field_ty_src, msg, "opaque types have unknown size", .{}); |
| ... | @@ -743,132 +897,109 @@ pub fn resolvePackedUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { | ... | @@ -743,132 +897,109 @@ pub fn resolvePackedUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { |
| 743 | break :msg msg; | 897 | break :msg msg; |
| 744 | }); | 898 | }); |
| 745 | } | 899 | } |
| 746 | if (!field_ty.packable(zcu)) { | 900 | if (field_ty.unpackable(zcu)) |reason| return sema.failWithOwnedErrorMsg(block, msg: { |
| 747 | return sema.failWithOwnedErrorMsg(&block, msg: { | 901 | const msg = try sema.errMsg(field_ty_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); |
| 748 | const msg = try sema.errMsg(field_ty_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | 902 | errdefer msg.destroy(gpa); |
| 903 | try sema.explainWhyTypeIsUnpackable(msg, field_ty_src, reason); | ||
| 904 | try sema.addDeclaredHereNote(msg, field_ty); | ||
| 905 | break :msg msg; | ||
| 906 | }); | ||
| 907 | assert(!field_ty.comptimeOnly(zcu)); // packable types are not comptime-only | ||
| 908 | } | ||
| 909 | |||
| 910 | const explicit_backing_int_ty: ?Type = if (union_obj.is_reified) ty: { | ||
| 911 | switch (union_obj.packed_backing_mode) { | ||
| 912 | .explicit => break :ty .fromInterned(union_obj.packed_backing_int_type), | ||
| 913 | .auto => break :ty null, | ||
| 914 | } | ||
| 915 | } else ty: { | ||
| 916 | const zir_index = union_obj.zir_index.resolve(ip).?; | ||
| 917 | const zir_union = sema.code.getUnionDecl(zir_index); | ||
| 918 | const backing_int_type_body = zir_union.arg_type_body orelse { | ||
| 919 | break :ty null; // inferred backing type | ||
| 920 | }; | ||
| 921 | // Explicitly specified, so evaluate the backing int type expression. | ||
| 922 | const backing_int_type_src = block.src(.container_arg); | ||
| 923 | block.comptime_reason = .{ .reason = .{ | ||
| 924 | .src = backing_int_type_src, | ||
| 925 | .r = .{ .simple = .packed_union_backing_int_type }, | ||
| 926 | } }; | ||
| 927 | const type_ref = try sema.resolveInlineBody(block, backing_int_type_body, zir_index); | ||
| 928 | break :ty try sema.analyzeAsType(block, backing_int_type_src, .packed_union_backing_int_type, type_ref); | ||
| 929 | }; | ||
| 930 | |||
| 931 | // Finally, either validate or infer the backing int type. | ||
| 932 | const backing_int_ty: Type = if (explicit_backing_int_ty) |backing_ty| ty: { | ||
| 933 | const backing_int_bits = backing_ty.intInfo(zcu).bits; | ||
| 934 | for (union_obj.field_types.get(ip), 0..) |field_type_ip, field_idx| { | ||
| 935 | const field_type: Type = .fromInterned(field_type_ip); | ||
| 936 | const field_bits = field_type.bitSize(zcu); | ||
| 937 | if (field_bits != backing_int_bits) return sema.failWithOwnedErrorMsg(block, msg: { | ||
| 938 | const field_ty_src = block.src(.{ .container_field_type = @intCast(field_idx) }); | ||
| 939 | const msg = try sema.errMsg(field_ty_src, "field bit width does not match backing integer", .{}); | ||
| 749 | errdefer msg.destroy(gpa); | 940 | errdefer msg.destroy(gpa); |
| 750 | try sema.explainWhyTypeIsNotPackable(msg, field_ty_src, field_ty); | 941 | try sema.errNote(field_ty_src, msg, "field type '{f}' has bit width '{d}'", .{ field_type.fmt(pt), field_bits }); |
| 751 | try sema.addDeclaredHereNote(msg, field_ty); | 942 | try sema.errNote(field_ty_src, msg, "backing integer '{f}' has bit width '{d}'", .{ backing_ty.fmt(pt), backing_int_bits }); |
| 943 | try sema.errNote(field_ty_src, msg, "all fields in a packed union must have the same bit width", .{}); | ||
| 752 | break :msg msg; | 944 | break :msg msg; |
| 753 | }); | 945 | }); |
| 754 | } | 946 | } |
| 755 | assert(!field_ty.comptimeOnly(zcu)); // packable types are not comptime-only | 947 | break :ty backing_ty; |
| 756 | } | 948 | } else if (union_obj.field_types.len == 0) ty: { |
| 757 | 949 | // Special case: there is no first field to infer the type from. Treat the union as empty (zero-bit). | |
| 758 | try resolvePackedUnionBackingInt(sema, &block, union_ty, &union_obj, false); | 950 | break :ty .u0; |
| 951 | } else ty: { | ||
| 952 | const field_types = union_obj.field_types.get(ip); | ||
| 953 | const first_field_type: Type = .fromInterned(field_types[0]); | ||
| 954 | const first_field_bits = first_field_type.bitSize(zcu); | ||
| 955 | for (field_types[1..], 1..) |field_type_ip, field_idx| { | ||
| 956 | const field_type: Type = .fromInterned(field_type_ip); | ||
| 957 | const field_bits = field_type.bitSize(zcu); | ||
| 958 | if (field_bits != first_field_bits) return sema.failWithOwnedErrorMsg(block, msg: { | ||
| 959 | const first_field_ty_src = block.src(.{ .container_field_type = 0 }); | ||
| 960 | const field_ty_src = block.src(.{ .container_field_type = @intCast(field_idx) }); | ||
| 961 | const msg = try sema.errMsg(field_ty_src, "field bit width does not match earlier field", .{}); | ||
| 962 | errdefer msg.destroy(gpa); | ||
| 963 | try sema.errNote(field_ty_src, msg, "field type '{f}' has bit width '{d}'", .{ field_type.fmt(pt), field_bits }); | ||
| 964 | try sema.errNote(first_field_ty_src, msg, "other field type '{f}' has bit width '{d}'", .{ first_field_type.fmt(pt), first_field_bits }); | ||
| 965 | try sema.errNote(field_ty_src, msg, "all fields in a packed union must have the same bit width", .{}); | ||
| 966 | break :msg msg; | ||
| 967 | }); | ||
| 968 | } | ||
| 969 | const backing_int_bits = std.math.cast(u16, first_field_bits) orelse return sema.fail( | ||
| 970 | block, | ||
| 971 | union_ty.srcLoc(zcu), | ||
| 972 | "packed union bit width '{d}' exceeds maximum bit width of 65535", | ||
| 973 | .{first_field_bits}, | ||
| 974 | ); | ||
| 975 | break :ty try pt.intType(.unsigned, backing_int_bits); | ||
| 976 | }; | ||
| 977 | ip.resolvePackedUnionLayout( | ||
| 978 | io, | ||
| 979 | union_ty.toIntern(), | ||
| 980 | enum_tag_ty.toIntern(), | ||
| 981 | backing_int_ty.toIntern(), | ||
| 982 | ); | ||
| 759 | } | 983 | } |
| 760 | 984 | ||
| 761 | /// MLUGG TODO doc comment; asserts all fields are resolved or whatever | 985 | pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void { |
| 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 { | ||
| 769 | const pt = sema.pt; | 986 | const pt = sema.pt; |
| 770 | const zcu = pt.zcu; | 987 | const zcu = pt.zcu; |
| 771 | const comp = zcu.comp; | 988 | const comp = zcu.comp; |
| 772 | const gpa = comp.gpa; | ||
| 773 | const io = comp.io; | 989 | const io = comp.io; |
| 774 | const ip = &zcu.intern_pool; | ||
| 775 | switch (union_obj.packed_backing_mode) { | ||
| 776 | .explicit => { | ||
| 777 | const backing_int_type: Type = .fromInterned(union_obj.packed_backing_int_type); | ||
| 778 | const backing_int_bits = backing_int_type.intInfo(zcu).bits; | ||
| 779 | for (union_obj.field_types.get(ip), 0..) |field_type_ip, field_idx| { | ||
| 780 | const field_type: Type = .fromInterned(field_type_ip); | ||
| 781 | const field_bits = field_type.bitSize(zcu); | ||
| 782 | if (field_bits != backing_int_bits) return sema.failWithOwnedErrorMsg(block, msg: { | ||
| 783 | const field_ty_src: LazySrcLoc = .{ | ||
| 784 | .base_node_inst = union_obj.zir_index, | ||
| 785 | .offset = if (is_reified) | ||
| 786 | .nodeOffset(.zero) | ||
| 787 | else | ||
| 788 | .{ .container_field_type = @intCast(field_idx) }, | ||
| 789 | }; | ||
| 790 | const msg = try sema.errMsg(field_ty_src, "field bit width does not match backing integer", .{}); | ||
| 791 | errdefer msg.destroy(gpa); | ||
| 792 | try sema.errNote(field_ty_src, msg, "field type '{f}' has bit width '{d}'", .{ field_type.fmt(pt), field_bits }); | ||
| 793 | try sema.errNote(field_ty_src, msg, "backing integer '{f}' has bit width '{d}'", .{ backing_int_type.fmt(pt), backing_int_bits }); | ||
| 794 | try sema.errNote(field_ty_src, msg, "all fields in a packed union must have the same bit width", .{}); | ||
| 795 | break :msg msg; | ||
| 796 | }); | ||
| 797 | } | ||
| 798 | }, | ||
| 799 | .auto => switch (union_obj.field_types.len) { | ||
| 800 | 0 => ip.resolvePackedUnionBackingInt(io, union_ty.toIntern(), .u0_type), | ||
| 801 | else => { | ||
| 802 | const field_types = union_obj.field_types.get(ip); | ||
| 803 | const first_field_type: Type = .fromInterned(field_types[0]); | ||
| 804 | const first_field_bits = first_field_type.bitSize(zcu); | ||
| 805 | for (field_types[1..], 1..) |field_type_ip, field_idx| { | ||
| 806 | const field_type: Type = .fromInterned(field_type_ip); | ||
| 807 | const field_bits = field_type.bitSize(zcu); | ||
| 808 | if (field_bits != first_field_bits) return sema.failWithOwnedErrorMsg(block, msg: { | ||
| 809 | const first_field_ty_src: LazySrcLoc = .{ | ||
| 810 | .base_node_inst = union_obj.zir_index, | ||
| 811 | .offset = if (is_reified) | ||
| 812 | .nodeOffset(.zero) | ||
| 813 | else | ||
| 814 | .{ .container_field_type = 0 }, | ||
| 815 | }; | ||
| 816 | const field_ty_src: LazySrcLoc = .{ | ||
| 817 | .base_node_inst = union_obj.zir_index, | ||
| 818 | .offset = if (is_reified) | ||
| 819 | .nodeOffset(.zero) | ||
| 820 | else | ||
| 821 | .{ .container_field_type = @intCast(field_idx) }, | ||
| 822 | }; | ||
| 823 | const msg = try sema.errMsg(field_ty_src, "field bit width does not match earlier field", .{}); | ||
| 824 | errdefer msg.destroy(gpa); | ||
| 825 | try sema.errNote(field_ty_src, msg, "field type '{f}' has bit width '{d}'", .{ field_type.fmt(pt), field_bits }); | ||
| 826 | try sema.errNote(first_field_ty_src, msg, "other field type '{f}' has bit width '{d}'", .{ first_field_type.fmt(pt), first_field_bits }); | ||
| 827 | try sema.errNote(field_ty_src, msg, "all fields in a packed union must have the same bit width", .{}); | ||
| 828 | break :msg msg; | ||
| 829 | }); | ||
| 830 | } | ||
| 831 | const backing_int_bits = std.math.cast(u16, first_field_bits) orelse return sema.fail( | ||
| 832 | block, | ||
| 833 | block.nodeOffset(.zero), | ||
| 834 | "packed union bit width '{d}' exceeds maximum bit width of 65535", | ||
| 835 | .{first_field_bits}, | ||
| 836 | ); | ||
| 837 | const backing_int_type = try pt.intType(.unsigned, backing_int_bits); | ||
| 838 | ip.resolvePackedUnionBackingInt(io, union_ty.toIntern(), backing_int_type.toIntern()); | ||
| 839 | }, | ||
| 840 | }, | ||
| 841 | } | ||
| 842 | } | ||
| 843 | |||
| 844 | /// Asserts that `enum_ty` is an enum and that `sema.owner` is that type. | ||
| 845 | /// This function *does* register the `src_hash` dependency on the enum. | ||
| 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 | const gpa = comp.gpa; | 990 | const gpa = comp.gpa; |
| 851 | const ip = &zcu.intern_pool; | 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 | const enum_obj = ip.loadEnumType(enum_ty.toIntern()); | 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 | const maybe_parent_union_obj: ?InternPool.LoadedUnionType = un: { | 997 | const maybe_parent_union_obj: ?InternPool.LoadedUnionType = un: { |
| 865 | if (enum_obj.owner_union == .none) break :un null; | 998 | if (enum_obj.owner_union == .none) break :un null; |
| 866 | break :un ip.loadUnionType(enum_obj.owner_union); | 999 | break :un ip.loadUnionType(enum_obj.owner_union); |
| 867 | }; | 1000 | }; |
| 868 | const tracked_inst = enum_obj.zir_index.unwrap() orelse maybe_parent_union_obj.?.zir_index; | ||
| 869 | const zir_index = tracked_inst.resolve(ip).?; | ||
| 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 | var block: Block = .{ | 1004 | var block: Block = .{ |
| 874 | .parent = null, | 1005 | .parent = null, |
| ... | @@ -882,7 +1013,139 @@ pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void { | ... | @@ -882,7 +1013,139 @@ pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void { |
| 882 | }; | 1013 | }; |
| 883 | defer assert(block.instructions.items.len == 0); | 1014 | defer assert(block.instructions.items.len == 0); |
| 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 | // Map the enum (or union) decl instruction to provide the tag type as the result type | 1150 | // Map the enum (or union) decl instruction to provide the tag type as the result type |
| 888 | try sema.inst_map.ensureSpaceForInstructions(gpa, &.{zir_index}); | 1151 | try sema.inst_map.ensureSpaceForInstructions(gpa, &.{zir_index}); |
| ... | @@ -891,36 +1154,38 @@ pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void { | ... | @@ -891,36 +1154,38 @@ pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void { |
| 891 | 1154 | ||
| 892 | // First, populate any explicitly provided values. This is the part that actually depends on | 1155 | // First, populate any explicitly provided values. This is the part that actually depends on |
| 893 | // the ZIR, and hence depends on whether this is a declared or generated enum. If any explicit | 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 | if (maybe_parent_union_obj) |union_obj| { | 1158 | if (maybe_parent_union_obj) |union_obj| { |
| 896 | const zir_union = sema.code.getUnionDecl(zir_index); | 1159 | if (union_obj.is_reified) { |
| 897 | var field_it = zir_union.iterateFields(); | 1160 | // Generated tag type for reified union; values already populated. |
| 898 | while (field_it.next()) |zir_field| { | 1161 | } else { |
| 899 | const field_val_src: LazySrcLoc = .{ | 1162 | // Generated tag type for declared union; evaluate the expressions given in the union declaration. |
| 900 | .base_node_inst = union_obj.zir_index, | 1163 | const zir_union = sema.code.getUnionDecl(zir_index); |
| 901 | .offset = .{ .container_field_value = zir_field.idx }, | 1164 | var field_it = zir_union.iterateFields(); |
| 902 | }; | 1165 | while (field_it.next()) |zir_field| { |
| 903 | block.comptime_reason = .{ .reason = .{ | 1166 | const field_val_src = block.src(.{ .container_field_value = zir_field.idx }); |
| 904 | .src = field_val_src, | 1167 | block.comptime_reason = .{ .reason = .{ |
| 905 | .r = .{ .simple = .enum_field_values }, | 1168 | .src = field_val_src, |
| 906 | } }; | 1169 | .r = .{ .simple = .enum_field_values }, |
| 907 | const value_body = zir_field.value_body orelse { | 1170 | } }; |
| 908 | enum_obj.field_values.get(ip)[zir_field.idx] = .none; | 1171 | const value_body = zir_field.value_body orelse { |
| 909 | continue; | 1172 | enum_obj.field_values.get(ip)[zir_field.idx] = .none; |
| 910 | }; | 1173 | continue; |
| 911 | const uncoerced = try sema.resolveInlineBody(&block, value_body, zir_index); | 1174 | }; |
| 912 | const coerced = try sema.coerce(&block, int_tag_ty, uncoerced, field_val_src); | 1175 | const uncoerced = try sema.resolveInlineBody(&block, value_body, zir_index); |
| 913 | const val = try sema.resolveConstValue(&block, field_val_src, coerced, null); | 1176 | const coerced = try sema.coerce(&block, int_tag_ty, uncoerced, field_val_src); |
| 914 | enum_obj.field_values.get(ip)[zir_field.idx] = val.toIntern(); | 1177 | const val = try sema.resolveConstValue(&block, field_val_src, coerced, null); |
| 1178 | enum_obj.field_values.get(ip)[zir_field.idx] = val.toIntern(); | ||
| 1179 | } | ||
| 915 | } | 1180 | } |
| 1181 | } else if (enum_obj.is_reified) { | ||
| 1182 | // Reified enum; values already populated. | ||
| 916 | } else { | 1183 | } else { |
| 1184 | // Declared enum; evaluate the expressions given in the enum declaration. | ||
| 917 | const zir_enum = sema.code.getEnumDecl(zir_index); | 1185 | const zir_enum = sema.code.getEnumDecl(zir_index); |
| 918 | var field_it = zir_enum.iterateFields(); | 1186 | var field_it = zir_enum.iterateFields(); |
| 919 | while (field_it.next()) |zir_field| { | 1187 | while (field_it.next()) |zir_field| { |
| 920 | const field_val_src: LazySrcLoc = .{ | 1188 | const field_val_src = block.src(.{ .container_field_value = zir_field.idx }); |
| 921 | .base_node_inst = enum_obj.zir_index.unwrap().?, | ||
| 922 | .offset = .{ .container_field_value = zir_field.idx }, | ||
| 923 | }; | ||
| 924 | block.comptime_reason = .{ .reason = .{ | 1189 | block.comptime_reason = .{ .reason = .{ |
| 925 | .src = field_val_src, | 1190 | .src = field_val_src, |
| 926 | .r = .{ .simple = .enum_field_values }, | 1191 | .r = .{ .simple = .enum_field_values }, |
| ... | @@ -940,14 +1205,14 @@ pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void { | ... | @@ -940,14 +1205,14 @@ pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void { |
| 940 | // field values. This is also where we'll detect duplicates. | 1205 | // field values. This is also where we'll detect duplicates. |
| 941 | 1206 | ||
| 942 | for (0..enum_obj.field_names.len) |field_idx| { | 1207 | for (0..enum_obj.field_names.len) |field_idx| { |
| 943 | const field_val_src: LazySrcLoc = .{ | 1208 | const field_val_src = block.src(.{ .container_field_value = @intCast(field_idx) }); |
| 944 | .base_node_inst = tracked_inst, | ||
| 945 | .offset = .{ .container_field_value = @intCast(field_idx) }, | ||
| 946 | }; | ||
| 947 | // If the field value was not specified, compute the implicit value. | 1209 | // If the field value was not specified, compute the implicit value. |
| 948 | const field_val = val: { | 1210 | const field_val = val: { |
| 949 | const explicit_val = enum_obj.field_values.get(ip)[field_idx]; | 1211 | const explicit_val = enum_obj.field_values.get(ip)[field_idx]; |
| 950 | if (explicit_val != .none) break :val explicit_val; | 1212 | if (explicit_val != .none) { |
| 1213 | assert(ip.typeOf(explicit_val) == int_tag_ty.toIntern()); | ||
| 1214 | break :val explicit_val; | ||
| 1215 | } | ||
| 951 | if (field_idx == 0) { | 1216 | if (field_idx == 0) { |
| 952 | // Implicit value is 0, which is valid for every integer type. | 1217 | // Implicit value is 0, which is valid for every integer type. |
| 953 | const val = (try pt.intValue(int_tag_ty, 0)).toIntern(); | 1218 | const val = (try pt.intValue(int_tag_ty, 0)).toIntern(); |
| ... | @@ -967,23 +1232,23 @@ pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void { | ... | @@ -967,23 +1232,23 @@ pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void { |
| 967 | enum_obj.field_values.get(ip)[field_idx] = val; | 1232 | enum_obj.field_values.get(ip)[field_idx] = val; |
| 968 | break :val val; | 1233 | break :val val; |
| 969 | }; | 1234 | }; |
| 970 | const adapter: InternPool.Index.Adapter = .{ .indexes = enum_obj.field_values.get(ip)[0..field_idx] }; | 1235 | if (ip.addFieldTagValue(enum_obj.field_values, field_value_map, field_val)) |prev_field_index| { |
| 971 | const gop = field_value_map.get(ip).getOrPutAssumeCapacityAdapted(field_val, adapter); | 1236 | return sema.failWithOwnedErrorMsg(&block, msg: { |
| 972 | if (!gop.found_existing) continue; | 1237 | const prev_field_val_src = block.src(.{ .container_field_value = prev_field_index }); |
| 973 | const prev_field_val_src: LazySrcLoc = .{ | 1238 | const msg = try sema.errMsg(field_val_src, "enum tag value '{f}' for field '{f}' already taken", .{ |
| 974 | .base_node_inst = tracked_inst, | 1239 | Value.fromInterned(field_val).fmtValueSema(pt, sema), |
| 975 | .offset = .{ .container_field_value = @intCast(gop.index) }, | 1240 | enum_obj.field_names.get(ip)[field_idx].fmt(ip), |
| 976 | }; | 1241 | }); |
| 977 | return sema.failWithOwnedErrorMsg(&block, msg: { | 1242 | errdefer msg.destroy(gpa); |
| 978 | const msg = try sema.errMsg(field_val_src, "enum tag value '{f}' already taken", .{ | 1243 | try sema.errNote(prev_field_val_src, msg, "previous occurrence in field '{f}'", .{ |
| 979 | Value.fromInterned(field_val).fmtValueSema(pt, sema), | 1244 | enum_obj.field_names.get(ip)[prev_field_index].fmt(ip), |
| 1245 | }); | ||
| 1246 | break :msg msg; | ||
| 980 | }); | 1247 | }); |
| 981 | errdefer msg.destroy(gpa); | 1248 | } |
| 982 | try sema.errNote(prev_field_val_src, msg, "previous occurrence here", .{}); | ||
| 983 | break :msg msg; | ||
| 984 | }); | ||
| 985 | } | 1249 | } |
| 986 | 1250 | ||
| 1251 | // MLUGG TODO: fate of this line rests on whether comptime_int is a valid int tag type | ||
| 987 | if (enum_obj.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) { | 1252 | if (enum_obj.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) { |
| 988 | const fields_len = enum_obj.field_names.len; | 1253 | const fields_len = enum_obj.field_names.len; |
| 989 | if (fields_len >= 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(zcu)) { | 1254 | if (fields_len >= 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(zcu)) { |
src/Type.zig+250-123| ... | @@ -437,6 +437,7 @@ pub fn toValue(self: Type) Value { | ... | @@ -437,6 +437,7 @@ pub fn toValue(self: Type) Value { |
| 437 | /// - an enum with an explicit tag type has the ABI size of the integer tag type, | 437 | /// - an enum with an explicit tag type has the ABI size of the integer tag type, |
| 438 | /// making it one-possible-value only if the integer tag type has 0 bits. | 438 | /// making it one-possible-value only if the integer tag type has 0 bits. |
| 439 | pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool { | 439 | pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool { |
| 440 | ty.assertHasLayout(zcu); | ||
| 440 | const ip = &zcu.intern_pool; | 441 | const ip = &zcu.intern_pool; |
| 441 | return switch (ip.indexToKey(ty.toIntern())) { | 442 | return switch (ip.indexToKey(ty.toIntern())) { |
| 442 | .int_type => |int_type| int_type.bits != 0, | 443 | .int_type => |int_type| int_type.bits != 0, |
| ... | @@ -499,14 +500,18 @@ pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool { | ... | @@ -499,14 +500,18 @@ pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool { |
| 499 | .generic_poison => unreachable, | 500 | .generic_poison => unreachable, |
| 500 | }, | 501 | }, |
| 501 | .struct_type => { | 502 | .struct_type => { |
| 502 | // TODO MLUGG: memoize this state when resolving struct? | ||
| 503 | const struct_obj = ip.loadStructType(ty.toIntern()); | 503 | const struct_obj = ip.loadStructType(ty.toIntern()); |
| 504 | for (struct_obj.field_types.get(ip), 0..) |field_ty_ip, field_idx| { | 504 | switch (struct_obj.layout) { |
| 505 | if (struct_obj.field_is_comptime_bits.get(ip, field_idx)) continue; | 505 | .auto, .@"extern" => return struct_obj.has_runtime_bits, |
| 506 | const field_ty: Type = .fromInterned(field_ty_ip); | 506 | .@"packed" => return Type.fromInterned(struct_obj.packed_backing_int_type).hasRuntimeBits(zcu), |
| 507 | if (field_ty.hasRuntimeBits(zcu)) return true; | 507 | } |
| 508 | }, | ||
| 509 | .union_type => { | ||
| 510 | const union_obj = ip.loadUnionType(ty.toIntern()); | ||
| 511 | switch (union_obj.layout) { | ||
| 512 | .auto, .@"extern" => return union_obj.has_runtime_bits, | ||
| 513 | .@"packed" => return Type.fromInterned(union_obj.packed_backing_int_type).hasRuntimeBits(zcu), | ||
| 508 | } | 514 | } |
| 509 | return false; | ||
| 510 | }, | 515 | }, |
| 511 | .tuple_type => |tuple| { | 516 | .tuple_type => |tuple| { |
| 512 | for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| { | 517 | for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| { |
| ... | @@ -515,23 +520,8 @@ pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool { | ... | @@ -515,23 +520,8 @@ pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool { |
| 515 | } | 520 | } |
| 516 | return false; | 521 | return false; |
| 517 | }, | 522 | }, |
| 518 | .union_type => { | ||
| 519 | // TODO MLUGG: memoize this state when resolving union? | ||
| 520 | const union_obj = ip.loadUnionType(ty.toIntern()); | ||
| 521 | switch (union_obj.runtime_tag) { | ||
| 522 | .none => {}, | ||
| 523 | .safety, .tagged => { | ||
| 524 | if (Type.fromInterned(union_obj.enum_tag_type).hasRuntimeBits(zcu)) return true; | ||
| 525 | }, | ||
| 526 | } | ||
| 527 | for (union_obj.field_types.get(ip)) |field_ty_ip| { | ||
| 528 | const field_ty: Type = .fromInterned(field_ty_ip); | ||
| 529 | if (field_ty.hasRuntimeBits(zcu)) return true; | ||
| 530 | } | ||
| 531 | return false; | ||
| 532 | }, | ||
| 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 | .opaque_type => true, | 525 | .opaque_type => true, |
| 536 | .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).hasRuntimeBits(zcu), | 526 | .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).hasRuntimeBits(zcu), |
| 537 | 527 | ||
| ... | @@ -618,17 +608,18 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool { | ... | @@ -618,17 +608,18 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool { |
| 618 | .generic_poison, | 608 | .generic_poison, |
| 619 | => false, | 609 | => false, |
| 620 | }, | 610 | }, |
| 621 | .struct_type => ip.loadStructType(ty.toIntern()).layout != .auto, | 611 | .struct_type => switch (ip.loadStructType(ty.toIntern()).layout) { |
| 622 | .union_type => { | 612 | .auto => false, |
| 623 | const union_obj = ip.loadUnionType(ty.toIntern()); | 613 | .@"extern", .@"packed" => true, |
| 624 | if (union_obj.layout == .auto) return false; | 614 | }, |
| 625 | return switch (union_obj.runtime_tag) { | 615 | .union_type => switch (ip.loadUnionType(ty.toIntern()).layout) { |
| 626 | .none => true, | 616 | .auto => false, |
| 627 | .tagged => false, | 617 | .@"extern", .@"packed" => true, |
| 628 | .safety => unreachable, // well-defined layout can't have a safety tag | 618 | }, |
| 629 | }; | 619 | .enum_type => switch (ip.loadEnumType(ty.toIntern()).int_tag_mode) { |
| 620 | .explicit => true, | ||
| 621 | .auto => false, | ||
| 630 | }, | 622 | }, |
| 631 | .enum_type => ip.loadEnumType(ty.toIntern()).int_tag_is_explicit, | ||
| 632 | 623 | ||
| 633 | // values, not types | 624 | // values, not types |
| 634 | .undef, | 625 | .undef, |
| ... | @@ -664,28 +655,29 @@ pub fn fnHasRuntimeBits(fn_ty: Type, zcu: *Zcu) bool { | ... | @@ -664,28 +655,29 @@ pub fn fnHasRuntimeBits(fn_ty: Type, zcu: *Zcu) bool { |
| 664 | if (param_ty == .generic_poison_type) return false; | 655 | if (param_ty == .generic_poison_type) return false; |
| 665 | if (Type.fromInterned(param_ty).comptimeOnly(zcu)) return false; | 656 | if (Type.fromInterned(param_ty).comptimeOnly(zcu)) return false; |
| 666 | } | 657 | } |
| 658 | const ret_ty: Type = .fromInterned(fn_info.return_type); | ||
| 659 | if (ret_ty.toIntern() == .generic_poison_type) { | ||
| 660 | return false; | ||
| 661 | } | ||
| 662 | if (ret_ty.zigTypeTag(zcu) == .error_union and | ||
| 663 | ret_ty.errorUnionPayload(zcu).toIntern() == .generic_poison_type) | ||
| 664 | { | ||
| 665 | return false; | ||
| 666 | } | ||
| 667 | if (fn_info.return_type == .generic_poison_type) return false; | 667 | if (fn_info.return_type == .generic_poison_type) return false; |
| 668 | if (Type.fromInterned(fn_info.return_type).comptimeOnly(zcu)) return false; | 668 | if (Type.fromInterned(fn_info.return_type).comptimeOnly(zcu)) return false; |
| 669 | if (fn_info.cc == .@"inline") return false; | 669 | if (fn_info.cc == .@"inline") return false; |
| 670 | return true; | 670 | return true; |
| 671 | } | 671 | } |
| 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 | switch (ty.zigTypeTag(zcu)) { | 675 | switch (ty.zigTypeTag(zcu)) { |
| 675 | .@"fn" => return ty.fnHasRuntimeBits(zcu), | 676 | .@"fn" => return ty.fnHasRuntimeBits(zcu), |
| 676 | else => return ty.hasRuntimeBits(zcu), | 677 | else => return ty.hasRuntimeBits(zcu), |
| 677 | } | 678 | } |
| 678 | } | 679 | } |
| 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 | pub fn isNoReturn(ty: Type, zcu: *const Zcu) bool { | 681 | pub fn isNoReturn(ty: Type, zcu: *const Zcu) bool { |
| 690 | return zcu.intern_pool.isNoReturn(ty.toIntern()); | 682 | return zcu.intern_pool.isNoReturn(ty.toIntern()); |
| 691 | } | 683 | } |
| ... | @@ -711,7 +703,6 @@ pub fn ptrAddressSpace(ty: Type, zcu: *const Zcu) std.builtin.AddressSpace { | ... | @@ -711,7 +703,6 @@ pub fn ptrAddressSpace(ty: Type, zcu: *const Zcu) std.builtin.AddressSpace { |
| 711 | } | 703 | } |
| 712 | 704 | ||
| 713 | /// Never returns `none`. Asserts that all necessary type resolution is already done. | 705 | /// Never returns `none`. Asserts that all necessary type resolution is already done. |
| 714 | /// MLUGG TODO: check that it really does never return `.none` | ||
| 715 | pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment { | 706 | pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment { |
| 716 | const ip = &zcu.intern_pool; | 707 | const ip = &zcu.intern_pool; |
| 717 | const target = zcu.getTarget(); | 708 | const target = zcu.getTarget(); |
| ... | @@ -810,7 +801,7 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment { | ... | @@ -810,7 +801,7 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment { |
| 810 | for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| { | 801 | for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| { |
| 811 | if (val != .none) continue; // comptime field | 802 | if (val != .none) continue; // comptime field |
| 812 | const field_align = Type.fromInterned(field_ty).abiAlignment(zcu); | 803 | const field_align = Type.fromInterned(field_ty).abiAlignment(zcu); |
| 813 | big_align = big_align.max(field_align); | 804 | big_align = big_align.maxStrict(field_align); |
| 814 | } | 805 | } |
| 815 | return big_align; | 806 | return big_align; |
| 816 | }, | 807 | }, |
| ... | @@ -818,14 +809,20 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment { | ... | @@ -818,14 +809,20 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment { |
| 818 | const struct_obj = ip.loadStructType(ty.toIntern()); | 809 | const struct_obj = ip.loadStructType(ty.toIntern()); |
| 819 | switch (struct_obj.layout) { | 810 | switch (struct_obj.layout) { |
| 820 | .@"packed" => return Type.fromInterned(struct_obj.packed_backing_int_type).abiAlignment(zcu), | 811 | .@"packed" => return Type.fromInterned(struct_obj.packed_backing_int_type).abiAlignment(zcu), |
| 821 | .auto, .@"extern" => return struct_obj.alignment, | 812 | .auto, .@"extern" => { |
| 813 | assert(struct_obj.alignment != .none); | ||
| 814 | return struct_obj.alignment; | ||
| 815 | }, | ||
| 822 | } | 816 | } |
| 823 | }, | 817 | }, |
| 824 | .union_type => { | 818 | .union_type => { |
| 825 | const union_obj = ip.loadUnionType(ty.toIntern()); | 819 | const union_obj = ip.loadUnionType(ty.toIntern()); |
| 826 | switch (union_obj.layout) { | 820 | switch (union_obj.layout) { |
| 827 | .@"packed" => return Type.fromInterned(union_obj.packed_backing_int_type).abiAlignment(zcu), | 821 | .@"packed" => return Type.fromInterned(union_obj.packed_backing_int_type).abiAlignment(zcu), |
| 828 | .auto, .@"extern" => return getUnionLayout(union_obj, zcu).abi_align, | 822 | .auto, .@"extern" => { |
| 823 | assert(union_obj.alignment != .none); | ||
| 824 | return union_obj.alignment; | ||
| 825 | }, | ||
| 829 | } | 826 | } |
| 830 | }, | 827 | }, |
| 831 | .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).abiAlignment(zcu), | 828 | .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).abiAlignment(zcu), |
| ... | @@ -1277,38 +1274,17 @@ pub fn nullablePtrElem(ty: Type, zcu: *const Zcu) Type { | ... | @@ -1277,38 +1274,17 @@ pub fn nullablePtrElem(ty: Type, zcu: *const Zcu) Type { |
| 1277 | } | 1274 | } |
| 1278 | } | 1275 | } |
| 1279 | 1276 | ||
| 1280 | /// Given that `ty` is an indexable pointer, returns its element type. Specifically: | 1277 | /// Asserts that `ty` is an indexable type, and returns its element type. Tuples (and pointers to |
| 1281 | /// * for `*[n]T`, returns `T` | 1278 | /// tuples) are not supported because they do not have a single element type. |
| 1282 | /// * for `*@Vector(n, T)`, returns `T` | ||
| 1283 | /// * for `[]T`, returns `T` | ||
| 1284 | /// * for `[*]T`, returns `T` | ||
| 1285 | /// * for `[*c]T`, returns `T` | ||
| 1286 | /// | ||
| 1287 | /// Tuples are not supported because they do not have a single element type. | ||
| 1288 | /// | 1279 | /// |
| 1289 | /// MLUGG TODO: should i even have this one? it's a subset of indexableElem | 1280 | /// Returns `T` for each of the following types: |
| 1290 | pub fn indexablePtrElem(ty: Type, zcu: *const Zcu) Type { | 1281 | /// * `[n]T` |
| 1291 | const ip = &zcu.intern_pool; | 1282 | /// * `@Vector(n, T)` |
| 1292 | const ptr_type = ip.indexToKey(ty.toIntern()).ptr_type; | 1283 | /// * `*[n]T` |
| 1293 | return switch (ptr_type.flags.size) { | 1284 | /// * `*@Vector(n, T)` |
| 1294 | .many, .slice, .c => return .fromInterned(ptr_type.child), | 1285 | /// * `[]T` |
| 1295 | .one => switch (ip.indexToKey(ptr_type.child)) { | 1286 | /// * `[*]T` |
| 1296 | inline .array_type, .vector_type => |arr| return .fromInterned(arr.child), | 1287 | /// * `[*c]T` |
| 1297 | else => unreachable, | ||
| 1298 | }, | ||
| 1299 | }; | ||
| 1300 | } | ||
| 1301 | |||
| 1302 | /// Given that `ty` is an indexable type, returns its element type. Specifically: | ||
| 1303 | /// * for `[n]T`, returns `T` | ||
| 1304 | /// * for `@Vector(n, T)`, returns `T` | ||
| 1305 | /// * for `*[n]T`, returns `T` | ||
| 1306 | /// * for `*@Vector(n, T)`, returns `T` | ||
| 1307 | /// * for `[]T`, returns `T` | ||
| 1308 | /// * for `[*]T`, returns `T` | ||
| 1309 | /// * for `[*c]T`, returns `T` | ||
| 1310 | /// | ||
| 1311 | /// Tuples are not supported because they do not have a single element type. | ||
| 1312 | pub fn indexableElem(ty: Type, zcu: *const Zcu) Type { | 1288 | pub fn indexableElem(ty: Type, zcu: *const Zcu) Type { |
| 1313 | const ip = &zcu.intern_pool; | 1289 | const ip = &zcu.intern_pool; |
| 1314 | return switch (ip.indexToKey(ty.toIntern())) { | 1290 | return switch (ip.indexToKey(ty.toIntern())) { |
| ... | @@ -1348,6 +1324,7 @@ pub fn optionalChild(ty: Type, zcu: *const Zcu) Type { | ... | @@ -1348,6 +1324,7 @@ pub fn optionalChild(ty: Type, zcu: *const Zcu) Type { |
| 1348 | /// Returns the tag type of a union, if the type is a union and it has a tag type. | 1324 | /// Returns the tag type of a union, if the type is a union and it has a tag type. |
| 1349 | /// Otherwise, returns `null`. | 1325 | /// Otherwise, returns `null`. |
| 1350 | pub fn unionTagType(ty: Type, zcu: *const Zcu) ?Type { | 1326 | pub fn unionTagType(ty: Type, zcu: *const Zcu) ?Type { |
| 1327 | assertHasLayout(ty, zcu); | ||
| 1351 | const ip = &zcu.intern_pool; | 1328 | const ip = &zcu.intern_pool; |
| 1352 | switch (ip.indexToKey(ty.toIntern())) { | 1329 | switch (ip.indexToKey(ty.toIntern())) { |
| 1353 | .union_type => {}, | 1330 | .union_type => {}, |
| ... | @@ -1363,6 +1340,7 @@ pub fn unionTagType(ty: Type, zcu: *const Zcu) ?Type { | ... | @@ -1363,6 +1340,7 @@ pub fn unionTagType(ty: Type, zcu: *const Zcu) ?Type { |
| 1363 | /// Same as `unionTagType` but includes safety tag. | 1340 | /// Same as `unionTagType` but includes safety tag. |
| 1364 | /// Codegen should use this version. | 1341 | /// Codegen should use this version. |
| 1365 | pub fn unionTagTypeSafety(ty: Type, zcu: *const Zcu) ?Type { | 1342 | pub fn unionTagTypeSafety(ty: Type, zcu: *const Zcu) ?Type { |
| 1343 | assertHasLayout(ty, zcu); | ||
| 1366 | const ip = &zcu.intern_pool; | 1344 | const ip = &zcu.intern_pool; |
| 1367 | return switch (ip.indexToKey(ty.toIntern())) { | 1345 | return switch (ip.indexToKey(ty.toIntern())) { |
| 1368 | .union_type => { | 1346 | .union_type => { |
| ... | @@ -1377,11 +1355,13 @@ pub fn unionTagTypeSafety(ty: Type, zcu: *const Zcu) ?Type { | ... | @@ -1377,11 +1355,13 @@ pub fn unionTagTypeSafety(ty: Type, zcu: *const Zcu) ?Type { |
| 1377 | /// Asserts the type is a union; returns the tag type, even if the tag will | 1355 | /// Asserts the type is a union; returns the tag type, even if the tag will |
| 1378 | /// not be stored at runtime. | 1356 | /// not be stored at runtime. |
| 1379 | pub fn unionTagTypeHypothetical(ty: Type, zcu: *const Zcu) Type { | 1357 | pub fn unionTagTypeHypothetical(ty: Type, zcu: *const Zcu) Type { |
| 1358 | assertHasLayout(ty, zcu); | ||
| 1380 | const union_obj = zcu.typeToUnion(ty).?; | 1359 | const union_obj = zcu.typeToUnion(ty).?; |
| 1381 | return Type.fromInterned(union_obj.enum_tag_type); | 1360 | return Type.fromInterned(union_obj.enum_tag_type); |
| 1382 | } | 1361 | } |
| 1383 | 1362 | ||
| 1384 | pub fn unionFieldType(ty: Type, enum_tag: Value, zcu: *const Zcu) ?Type { | 1363 | pub fn unionFieldType(ty: Type, enum_tag: Value, zcu: *const Zcu) ?Type { |
| 1364 | assertHasLayout(ty, zcu); | ||
| 1385 | const ip = &zcu.intern_pool; | 1365 | const ip = &zcu.intern_pool; |
| 1386 | const union_obj = zcu.typeToUnion(ty).?; | 1366 | const union_obj = zcu.typeToUnion(ty).?; |
| 1387 | const union_fields = union_obj.field_types.get(ip); | 1367 | const union_fields = union_obj.field_types.get(ip); |
| ... | @@ -1390,17 +1370,20 @@ pub fn unionFieldType(ty: Type, enum_tag: Value, zcu: *const Zcu) ?Type { | ... | @@ -1390,17 +1370,20 @@ pub fn unionFieldType(ty: Type, enum_tag: Value, zcu: *const Zcu) ?Type { |
| 1390 | } | 1370 | } |
| 1391 | 1371 | ||
| 1392 | pub fn unionFieldTypeByIndex(ty: Type, index: usize, zcu: *const Zcu) Type { | 1372 | pub fn unionFieldTypeByIndex(ty: Type, index: usize, zcu: *const Zcu) Type { |
| 1373 | assertHasLayout(ty, zcu); | ||
| 1393 | const ip = &zcu.intern_pool; | 1374 | const ip = &zcu.intern_pool; |
| 1394 | const union_obj = zcu.typeToUnion(ty).?; | 1375 | const union_obj = zcu.typeToUnion(ty).?; |
| 1395 | return Type.fromInterned(union_obj.field_types.get(ip)[index]); | 1376 | return Type.fromInterned(union_obj.field_types.get(ip)[index]); |
| 1396 | } | 1377 | } |
| 1397 | 1378 | ||
| 1398 | pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 { | 1379 | pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 { |
| 1380 | assertHasLayout(ty, zcu); | ||
| 1399 | const union_obj = zcu.typeToUnion(ty).?; | 1381 | const union_obj = zcu.typeToUnion(ty).?; |
| 1400 | return zcu.unionTagFieldIndex(union_obj, enum_tag); | 1382 | return zcu.unionTagFieldIndex(union_obj, enum_tag); |
| 1401 | } | 1383 | } |
| 1402 | 1384 | ||
| 1403 | pub fn unionHasAllZeroBitFieldTypes(ty: Type, zcu: *Zcu) bool { | 1385 | pub fn unionHasAllZeroBitFieldTypes(ty: Type, zcu: *Zcu) bool { |
| 1386 | assertHasLayout(ty, zcu); | ||
| 1404 | const ip = &zcu.intern_pool; | 1387 | const ip = &zcu.intern_pool; |
| 1405 | const union_obj = zcu.typeToUnion(ty).?; | 1388 | const union_obj = zcu.typeToUnion(ty).?; |
| 1406 | for (union_obj.field_types.get(ip)) |field_ty| { | 1389 | for (union_obj.field_types.get(ip)) |field_ty| { |
| ... | @@ -1413,14 +1396,17 @@ pub fn unionHasAllZeroBitFieldTypes(ty: Type, zcu: *Zcu) bool { | ... | @@ -1413,14 +1396,17 @@ pub fn unionHasAllZeroBitFieldTypes(ty: Type, zcu: *Zcu) bool { |
| 1413 | /// Asserts the type is either an extern or packed union. | 1396 | /// Asserts the type is either an extern or packed union. |
| 1414 | pub fn unionBackingType(ty: Type, pt: Zcu.PerThread) !Type { | 1397 | pub fn unionBackingType(ty: Type, pt: Zcu.PerThread) !Type { |
| 1415 | const zcu = pt.zcu; | 1398 | const zcu = pt.zcu; |
| 1416 | return switch (ty.containerLayout(zcu)) { | 1399 | assertHasLayout(ty, zcu); |
| 1400 | const loaded_union = zcu.intern_pool.loadUnionType(ty.toIntern()); | ||
| 1401 | return switch (loaded_union.layout) { | ||
| 1417 | .@"extern" => try pt.arrayType(.{ .len = ty.abiSize(zcu), .child = .u8_type }), | 1402 | .@"extern" => try pt.arrayType(.{ .len = ty.abiSize(zcu), .child = .u8_type }), |
| 1418 | .@"packed" => try pt.intType(.unsigned, @intCast(ty.bitSize(zcu))), | 1403 | .@"packed" => .fromInterned(loaded_union.packed_backing_int_type), |
| 1419 | .auto => unreachable, | 1404 | .auto => unreachable, |
| 1420 | }; | 1405 | }; |
| 1421 | } | 1406 | } |
| 1422 | 1407 | ||
| 1423 | pub fn unionGetLayout(ty: Type, zcu: *const Zcu) Zcu.UnionLayout { | 1408 | pub fn unionGetLayout(ty: Type, zcu: *const Zcu) Zcu.UnionLayout { |
| 1409 | assertHasLayout(ty, zcu); | ||
| 1424 | const union_obj = zcu.intern_pool.loadUnionType(ty.toIntern()); | 1410 | const union_obj = zcu.intern_pool.loadUnionType(ty.toIntern()); |
| 1425 | return Type.getUnionLayout(union_obj, zcu); | 1411 | return Type.getUnionLayout(union_obj, zcu); |
| 1426 | } | 1412 | } |
| ... | @@ -1865,11 +1851,8 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value { | ... | @@ -1865,11 +1851,8 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value { |
| 1865 | for (field_vals, 0..) |*field_val, i_usize| { | 1851 | for (field_vals, 0..) |*field_val, i_usize| { |
| 1866 | const i: u32 = @intCast(i_usize); | 1852 | const i: u32 = @intCast(i_usize); |
| 1867 | if (struct_obj.field_is_comptime_bits.get(ip, i)) { | 1853 | if (struct_obj.field_is_comptime_bits.get(ip, i)) { |
| 1868 | // MLUGG TODO: this is kinda a problem... we don't necessarily know the opv field vals! | ||
| 1869 | // for now i'm just not letting structs with comptime fields be opv :) | ||
| 1870 | if (true) return null; | ||
| 1871 | assertHasInits(ty, zcu); | ||
| 1872 | field_val.* = struct_obj.field_defaults.get(ip)[i]; | 1854 | field_val.* = struct_obj.field_defaults.get(ip)[i]; |
| 1855 | assert(field_val.* != .none); | ||
| 1873 | continue; | 1856 | continue; |
| 1874 | } | 1857 | } |
| 1875 | const field_ty = Type.fromInterned(struct_obj.field_types.get(ip)[i]); | 1858 | const field_ty = Type.fromInterned(struct_obj.field_types.get(ip)[i]); |
| ... | @@ -2257,19 +2240,23 @@ pub fn errorSetNames(ty: Type, zcu: *const Zcu) InternPool.NullTerminatedString. | ... | @@ -2257,19 +2240,23 @@ pub fn errorSetNames(ty: Type, zcu: *const Zcu) InternPool.NullTerminatedString. |
| 2257 | } | 2240 | } |
| 2258 | 2241 | ||
| 2259 | pub fn enumFields(ty: Type, zcu: *const Zcu) InternPool.NullTerminatedString.Slice { | 2242 | pub fn enumFields(ty: Type, zcu: *const Zcu) InternPool.NullTerminatedString.Slice { |
| 2243 | assertHasLayout(ty, zcu); | ||
| 2260 | return zcu.intern_pool.loadEnumType(ty.toIntern()).field_names; | 2244 | return zcu.intern_pool.loadEnumType(ty.toIntern()).field_names; |
| 2261 | } | 2245 | } |
| 2262 | 2246 | ||
| 2263 | pub fn enumFieldCount(ty: Type, zcu: *const Zcu) usize { | 2247 | pub fn enumFieldCount(ty: Type, zcu: *const Zcu) usize { |
| 2248 | assertHasLayout(ty, zcu); | ||
| 2264 | return zcu.intern_pool.loadEnumType(ty.toIntern()).field_names.len; | 2249 | return zcu.intern_pool.loadEnumType(ty.toIntern()).field_names.len; |
| 2265 | } | 2250 | } |
| 2266 | 2251 | ||
| 2267 | pub fn enumFieldName(ty: Type, field_index: usize, zcu: *const Zcu) InternPool.NullTerminatedString { | 2252 | pub fn enumFieldName(ty: Type, field_index: usize, zcu: *const Zcu) InternPool.NullTerminatedString { |
| 2253 | assertHasLayout(ty, zcu); | ||
| 2268 | const ip = &zcu.intern_pool; | 2254 | const ip = &zcu.intern_pool; |
| 2269 | return ip.loadEnumType(ty.toIntern()).field_names.get(ip)[field_index]; | 2255 | return ip.loadEnumType(ty.toIntern()).field_names.get(ip)[field_index]; |
| 2270 | } | 2256 | } |
| 2271 | 2257 | ||
| 2272 | pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, zcu: *const Zcu) ?u32 { | 2258 | pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, zcu: *const Zcu) ?u32 { |
| 2259 | assertHasLayout(ty, zcu); | ||
| 2273 | const ip = &zcu.intern_pool; | 2260 | const ip = &zcu.intern_pool; |
| 2274 | const enum_type = ip.loadEnumType(ty.toIntern()); | 2261 | const enum_type = ip.loadEnumType(ty.toIntern()); |
| 2275 | return enum_type.nameIndex(ip, field_name); | 2262 | return enum_type.nameIndex(ip, field_name); |
| ... | @@ -2279,6 +2266,7 @@ pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, zcu | ... | @@ -2279,6 +2266,7 @@ pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, zcu |
| 2279 | /// an integer which represents the enum value. Returns the field index in | 2266 | /// an integer which represents the enum value. Returns the field index in |
| 2280 | /// declaration order, or `null` if `enum_tag` does not match any field. | 2267 | /// declaration order, or `null` if `enum_tag` does not match any field. |
| 2281 | pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 { | 2268 | pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 { |
| 2269 | assertHasLayout(ty, zcu); | ||
| 2282 | const ip = &zcu.intern_pool; | 2270 | const ip = &zcu.intern_pool; |
| 2283 | const enum_type = ip.loadEnumType(ty.toIntern()); | 2271 | const enum_type = ip.loadEnumType(ty.toIntern()); |
| 2284 | const int_tag = switch (ip.indexToKey(enum_tag.toIntern())) { | 2272 | const int_tag = switch (ip.indexToKey(enum_tag.toIntern())) { |
| ... | @@ -2293,28 +2281,40 @@ pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 { | ... | @@ -2293,28 +2281,40 @@ pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 { |
| 2293 | /// Returns none in the case of a tuple which uses the integer index as the field name. | 2281 | /// Returns none in the case of a tuple which uses the integer index as the field name. |
| 2294 | pub fn structFieldName(ty: Type, index: usize, zcu: *const Zcu) InternPool.OptionalNullTerminatedString { | 2282 | pub fn structFieldName(ty: Type, index: usize, zcu: *const Zcu) InternPool.OptionalNullTerminatedString { |
| 2295 | const ip = &zcu.intern_pool; | 2283 | const ip = &zcu.intern_pool; |
| 2296 | return switch (ip.indexToKey(ty.toIntern())) { | 2284 | switch (ip.indexToKey(ty.toIntern())) { |
| 2297 | .struct_type => ip.loadStructType(ty.toIntern()).field_names.get(ip)[index].toOptional(), | 2285 | .struct_type => { |
| 2298 | .tuple_type => .none, | 2286 | assertHasLayout(ty, zcu); |
| 2287 | return ip.loadStructType(ty.toIntern()).field_names.get(ip)[index].toOptional(); | ||
| 2288 | }, | ||
| 2289 | .tuple_type => return .none, | ||
| 2299 | else => unreachable, | 2290 | else => unreachable, |
| 2300 | }; | 2291 | } |
| 2301 | } | 2292 | } |
| 2302 | 2293 | ||
| 2303 | pub fn structFieldCount(ty: Type, zcu: *const Zcu) u32 { | 2294 | pub fn structFieldCount(ty: Type, zcu: *const Zcu) u32 { |
| 2304 | const ip = &zcu.intern_pool; | 2295 | const ip = &zcu.intern_pool; |
| 2305 | return switch (ip.indexToKey(ty.toIntern())) { | 2296 | switch (ip.indexToKey(ty.toIntern())) { |
| 2306 | .struct_type => ip.loadStructType(ty.toIntern()).field_types.len, | 2297 | .struct_type => { |
| 2307 | .tuple_type => |tuple| tuple.types.len, | 2298 | assertHasLayout(ty, zcu); |
| 2299 | return ip.loadStructType(ty.toIntern()).field_types.len; | ||
| 2300 | }, | ||
| 2301 | .tuple_type => |tuple| return tuple.types.len, | ||
| 2308 | else => unreachable, | 2302 | else => unreachable, |
| 2309 | }; | 2303 | } |
| 2310 | } | 2304 | } |
| 2311 | 2305 | ||
| 2312 | /// Returns the field type. Supports structs and unions. | 2306 | /// Returns the field type. Supports structs and unions. |
| 2313 | pub fn fieldType(ty: Type, index: usize, zcu: *const Zcu) Type { | 2307 | pub fn fieldType(ty: Type, index: usize, zcu: *const Zcu) Type { |
| 2314 | const ip = &zcu.intern_pool; | 2308 | const ip = &zcu.intern_pool; |
| 2315 | const types = switch (ip.indexToKey(ty.toIntern())) { | 2309 | const types = switch (ip.indexToKey(ty.toIntern())) { |
| 2316 | .struct_type => ip.loadStructType(ty.toIntern()).field_types, | 2310 | .struct_type => types: { |
| 2317 | .union_type => ip.loadUnionType(ty.toIntern()).field_types, | 2311 | assertHasLayout(ty, zcu); |
| 2312 | break :types ip.loadStructType(ty.toIntern()).field_types; | ||
| 2313 | }, | ||
| 2314 | .union_type => types: { | ||
| 2315 | assertHasLayout(ty, zcu); | ||
| 2316 | break :types ip.loadUnionType(ty.toIntern()).field_types; | ||
| 2317 | }, | ||
| 2318 | .tuple_type => |tuple| tuple.types, | 2318 | .tuple_type => |tuple| tuple.types, |
| 2319 | else => unreachable, | 2319 | else => unreachable, |
| 2320 | }; | 2320 | }; |
| ... | @@ -2335,11 +2335,13 @@ pub fn resolvedFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment | ... | @@ -2335,11 +2335,13 @@ pub fn resolvedFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment |
| 2335 | return switch (ip.indexToKey(ty.toIntern())) { | 2335 | return switch (ip.indexToKey(ty.toIntern())) { |
| 2336 | .tuple_type => |tuple| Type.fromInterned(tuple.types.get(ip)[index]).abiAlignment(zcu), | 2336 | .tuple_type => |tuple| Type.fromInterned(tuple.types.get(ip)[index]).abiAlignment(zcu), |
| 2337 | .struct_type => { | 2337 | .struct_type => { |
| 2338 | assertHasLayout(ty, zcu); | ||
| 2338 | const struct_obj = ip.loadStructType(ty.toIntern()); | 2339 | const struct_obj = ip.loadStructType(ty.toIntern()); |
| 2339 | const field_ty: Type = .fromInterned(struct_obj.field_types.get(ip)[index]); | 2340 | const field_ty: Type = .fromInterned(struct_obj.field_types.get(ip)[index]); |
| 2340 | return field_ty.defaultStructFieldAlignment(struct_obj.layout, zcu); | 2341 | return field_ty.defaultStructFieldAlignment(struct_obj.layout, zcu); |
| 2341 | }, | 2342 | }, |
| 2342 | .union_type => { | 2343 | .union_type => { |
| 2344 | assertHasLayout(ty, zcu); | ||
| 2343 | const union_obj = ip.loadUnionType(ty.toIntern()); | 2345 | const union_obj = ip.loadUnionType(ty.toIntern()); |
| 2344 | const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[index]); | 2346 | const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[index]); |
| 2345 | return field_ty.abiAlignment(zcu); | 2347 | return field_ty.abiAlignment(zcu); |
| ... | @@ -2353,12 +2355,14 @@ pub fn explicitFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment | ... | @@ -2353,12 +2355,14 @@ pub fn explicitFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment |
| 2353 | return switch (ip.indexToKey(ty.toIntern())) { | 2355 | return switch (ip.indexToKey(ty.toIntern())) { |
| 2354 | .tuple_type => .none, | 2356 | .tuple_type => .none, |
| 2355 | .struct_type => { | 2357 | .struct_type => { |
| 2358 | assertHasLayout(ty, zcu); | ||
| 2356 | const struct_obj = ip.loadStructType(ty.toIntern()); | 2359 | const struct_obj = ip.loadStructType(ty.toIntern()); |
| 2357 | assert(struct_obj.layout != .@"packed"); | 2360 | assert(struct_obj.layout != .@"packed"); |
| 2358 | if (struct_obj.field_aligns.len == 0) return .none; | 2361 | if (struct_obj.field_aligns.len == 0) return .none; |
| 2359 | return struct_obj.field_aligns.get(ip)[index]; | 2362 | return struct_obj.field_aligns.get(ip)[index]; |
| 2360 | }, | 2363 | }, |
| 2361 | .union_type => { | 2364 | .union_type => { |
| 2365 | assertHasLayout(ty, zcu); | ||
| 2362 | const union_obj = ip.loadUnionType(ty.toIntern()); | 2366 | const union_obj = ip.loadUnionType(ty.toIntern()); |
| 2363 | assert(union_obj.layout != .@"packed"); | 2367 | assert(union_obj.layout != .@"packed"); |
| 2364 | if (union_obj.field_aligns.len == 0) return .none; | 2368 | if (union_obj.field_aligns.len == 0) return .none; |
| ... | @@ -2413,7 +2417,6 @@ pub fn structFieldValueComptime(ty: Type, pt: Zcu.PerThread, index: usize) !?Val | ... | @@ -2413,7 +2417,6 @@ pub fn structFieldValueComptime(ty: Type, pt: Zcu.PerThread, index: usize) !?Val |
| 2413 | .struct_type => { | 2417 | .struct_type => { |
| 2414 | const struct_type = ip.loadStructType(ty.toIntern()); | 2418 | const struct_type = ip.loadStructType(ty.toIntern()); |
| 2415 | if (struct_type.field_is_comptime_bits.get(ip, index)) { | 2419 | if (struct_type.field_is_comptime_bits.get(ip, index)) { |
| 2416 | assertHasInits(ty, zcu); | ||
| 2417 | return .fromInterned(struct_type.field_defaults.get(ip)[index]); | 2420 | return .fromInterned(struct_type.field_defaults.get(ip)[index]); |
| 2418 | } else { | 2421 | } else { |
| 2419 | return Type.fromInterned(struct_type.field_types.get(ip)[index]).onePossibleValue(pt); | 2422 | return Type.fromInterned(struct_type.field_types.get(ip)[index]).onePossibleValue(pt); |
| ... | @@ -2433,11 +2436,14 @@ pub fn structFieldValueComptime(ty: Type, pt: Zcu.PerThread, index: usize) !?Val | ... | @@ -2433,11 +2436,14 @@ pub fn structFieldValueComptime(ty: Type, pt: Zcu.PerThread, index: usize) !?Val |
| 2433 | 2436 | ||
| 2434 | pub fn structFieldIsComptime(ty: Type, index: usize, zcu: *const Zcu) bool { | 2437 | pub fn structFieldIsComptime(ty: Type, index: usize, zcu: *const Zcu) bool { |
| 2435 | const ip = &zcu.intern_pool; | 2438 | const ip = &zcu.intern_pool; |
| 2436 | return switch (ip.indexToKey(ty.toIntern())) { | 2439 | switch (ip.indexToKey(ty.toIntern())) { |
| 2437 | .struct_type => ip.loadStructType(ty.toIntern()).field_is_comptime_bits.get(ip, index), | 2440 | .struct_type => { |
| 2438 | .tuple_type => |tuple| tuple.values.get(ip)[index] != .none, | 2441 | assertHasLayout(ty, zcu); |
| 2442 | return ip.loadStructType(ty.toIntern()).field_is_comptime_bits.get(ip, index); | ||
| 2443 | }, | ||
| 2444 | .tuple_type => |tuple| return tuple.values.get(ip)[index] != .none, | ||
| 2439 | else => unreachable, | 2445 | else => unreachable, |
| 2440 | }; | 2446 | } |
| 2441 | } | 2447 | } |
| 2442 | 2448 | ||
| 2443 | pub const FieldOffset = struct { | 2449 | pub const FieldOffset = struct { |
| ... | @@ -2850,34 +2856,166 @@ pub fn isNullFromType(ty: Type, zcu: *const Zcu) ?bool { | ... | @@ -2850,34 +2856,166 @@ pub fn isNullFromType(ty: Type, zcu: *const Zcu) ?bool { |
| 2850 | return null; | 2856 | return null; |
| 2851 | } | 2857 | } |
| 2852 | 2858 | ||
| 2853 | /// Returns true if `ty` is allowed in packed types. | 2859 | pub const UnpackableReason = union(enum) { |
| 2854 | pub fn packable(ty: Type, zcu: *const Zcu) bool { | 2860 | comptime_only, |
| 2861 | pointer, | ||
| 2862 | enum_inferred_int_tag: Type, | ||
| 2863 | non_packed_struct: Type, | ||
| 2864 | non_packed_union: Type, | ||
| 2865 | other, | ||
| 2866 | }; | ||
| 2867 | |||
| 2868 | /// Returns `null` iff `ty` is allowed in packed types. | ||
| 2869 | pub fn unpackable(ty: Type, zcu: *const Zcu) ?UnpackableReason { | ||
| 2855 | return switch (ty.zigTypeTag(zcu)) { | 2870 | return switch (ty.zigTypeTag(zcu)) { |
| 2871 | .void, | ||
| 2872 | .bool, | ||
| 2873 | .float, | ||
| 2874 | .int, | ||
| 2875 | => null, | ||
| 2876 | |||
| 2856 | .type, | 2877 | .type, |
| 2857 | .comptime_float, | 2878 | .comptime_float, |
| 2858 | .comptime_int, | 2879 | .comptime_int, |
| 2859 | .enum_literal, | 2880 | .enum_literal, |
| 2860 | .undefined, | 2881 | .undefined, |
| 2861 | .null, | 2882 | .null, |
| 2883 | => .comptime_only, | ||
| 2884 | |||
| 2885 | .noreturn, | ||
| 2886 | .@"opaque", | ||
| 2862 | .error_union, | 2887 | .error_union, |
| 2863 | .error_set, | 2888 | .error_set, |
| 2864 | .frame, | 2889 | .frame, |
| 2865 | .noreturn, | ||
| 2866 | .@"opaque", | ||
| 2867 | .@"anyframe", | 2890 | .@"anyframe", |
| 2868 | .@"fn", | 2891 | .@"fn", |
| 2869 | .array, | 2892 | .array, |
| 2893 | .vector, | ||
| 2894 | => .other, | ||
| 2895 | |||
| 2896 | .optional => if (ty.isPtrLikeOptional(zcu)) | ||
| 2897 | .pointer | ||
| 2898 | else | ||
| 2899 | .other, | ||
| 2900 | |||
| 2901 | .pointer => .pointer, | ||
| 2902 | |||
| 2903 | .@"enum" => switch (zcu.intern_pool.loadEnumType(ty.toIntern()).int_tag_mode) { | ||
| 2904 | .explicit => null, | ||
| 2905 | .auto => .{ .enum_inferred_int_tag = ty }, | ||
| 2906 | }, | ||
| 2907 | |||
| 2908 | .@"struct" => switch (ty.containerLayout(zcu)) { | ||
| 2909 | .@"packed" => null, | ||
| 2910 | .auto, .@"extern" => .{ .non_packed_struct = ty }, | ||
| 2911 | }, | ||
| 2912 | .@"union" => switch (ty.containerLayout(zcu)) { | ||
| 2913 | .@"packed" => null, | ||
| 2914 | .auto, .@"extern" => .{ .non_packed_union = ty }, | ||
| 2915 | }, | ||
| 2916 | }; | ||
| 2917 | } | ||
| 2918 | |||
| 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 | => false, | 2942 | => false, |
| 2871 | .optional => return ty.isPtrLikeOptional(zcu), | 2943 | |
| 2872 | .void, | 2944 | .void => switch (position) { |
| 2945 | .ret_ty, | ||
| 2946 | .union_field, | ||
| 2947 | .struct_field, | ||
| 2948 | .element, | ||
| 2949 | => true, | ||
| 2950 | .param_ty, | ||
| 2951 | .other, | ||
| 2952 | => false, | ||
| 2953 | }, | ||
| 2954 | |||
| 2955 | .noreturn => position == .ret_ty, | ||
| 2956 | |||
| 2957 | .@"opaque", | ||
| 2873 | .bool, | 2958 | .bool, |
| 2874 | .float, | 2959 | .float, |
| 2875 | .int, | 2960 | .@"anyframe", |
| 2876 | .vector, | ||
| 2877 | => true, | 2961 | => true, |
| 2878 | .@"enum" => zcu.intern_pool.loadEnumType(ty.toIntern()).int_tag_is_explicit, | 2962 | |
| 2879 | .pointer => !ty.isSlice(zcu), | 2963 | .pointer => { |
| 2880 | .@"struct", .@"union" => ty.containerLayout(zcu) == .@"packed", | 2964 | if (ty.isSlice(zcu)) return false; |
| 2965 | const child_ty = ty.childType(zcu); | ||
| 2966 | if (child_ty.zigTypeTag(zcu) == .@"fn") { | ||
| 2967 | return ty.isConstPtr(zcu) and child_ty.validateExtern(.other, zcu); | ||
| 2968 | } | ||
| 2969 | return true; | ||
| 2970 | }, | ||
| 2971 | .int => switch (ty.intInfo(zcu).bits) { | ||
| 2972 | 0, 8, 16, 32, 64, 128 => true, | ||
| 2973 | else => false, | ||
| 2974 | }, | ||
| 2975 | .@"fn" => { | ||
| 2976 | if (position != .other) return false; | ||
| 2977 | // For now we want to authorize PTX kernel to use zig objects, even if we end up exposing the ABI. | ||
| 2978 | // The goal is to experiment with more integrated CPU/GPU code. | ||
| 2979 | if (ty.fnCallingConvention(zcu) == .nvptx_kernel) { | ||
| 2980 | return true; | ||
| 2981 | } | ||
| 2982 | return !target_util.fnCallConvAllowsZigTypes(ty.fnCallingConvention(zcu)); | ||
| 2983 | }, | ||
| 2984 | .@"enum" => { | ||
| 2985 | const enum_obj = zcu.intern_pool.loadEnumType(ty.toIntern()); | ||
| 2986 | return switch (enum_obj.int_tag_mode) { | ||
| 2987 | .auto => false, | ||
| 2988 | .explicit => Type.fromInterned(enum_obj.int_tag_type).validateExtern(position, zcu), | ||
| 2989 | }; | ||
| 2990 | }, | ||
| 2991 | .@"struct" => { | ||
| 2992 | const struct_obj = zcu.intern_pool.loadStructType(ty.toIntern()); | ||
| 2993 | return switch (struct_obj.layout) { | ||
| 2994 | .auto => false, | ||
| 2995 | .@"extern" => true, | ||
| 2996 | .@"packed" => switch (struct_obj.packed_backing_mode) { | ||
| 2997 | .auto => false, | ||
| 2998 | .explicit => Type.fromInterned(struct_obj.packed_backing_int_type).validateExtern(position, zcu), | ||
| 2999 | }, | ||
| 3000 | }; | ||
| 3001 | }, | ||
| 3002 | .@"union" => { | ||
| 3003 | const union_obj = zcu.intern_pool.loadUnionType(ty.toIntern()); | ||
| 3004 | return switch (union_obj.layout) { | ||
| 3005 | .auto => false, | ||
| 3006 | .@"extern" => true, | ||
| 3007 | .@"packed" => switch (union_obj.packed_backing_mode) { | ||
| 3008 | .auto => false, | ||
| 3009 | .explicit => Type.fromInterned(union_obj.packed_backing_int_type).validateExtern(position, zcu), | ||
| 3010 | }, | ||
| 3011 | }; | ||
| 3012 | }, | ||
| 3013 | .array => { | ||
| 3014 | if (position == .ret_ty or position == .param_ty) return false; | ||
| 3015 | return ty.childType(zcu).validateExtern(.element, zcu); | ||
| 3016 | }, | ||
| 3017 | .vector => ty.childType(zcu).validateExtern(.element, zcu), | ||
| 3018 | .optional => ty.isPtrLikeOptional(zcu), | ||
| 2881 | }; | 3019 | }; |
| 2882 | } | 3020 | } |
| 2883 | 3021 | ||
| ... | @@ -2889,7 +3027,6 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void { | ... | @@ -2889,7 +3027,6 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void { |
| 2889 | .anyframe_type, | 3027 | .anyframe_type, |
| 2890 | .simple_type, | 3028 | .simple_type, |
| 2891 | .opaque_type, | 3029 | .opaque_type, |
| 2892 | .enum_type, | ||
| 2893 | .error_set_type, | 3030 | .error_set_type, |
| 2894 | .inferred_error_set_type, | 3031 | .inferred_error_set_type, |
| 2895 | => {}, | 3032 | => {}, |
| ... | @@ -2906,12 +3043,11 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void { | ... | @@ -2906,12 +3043,11 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void { |
| 2906 | .tuple_type => |tuple| for (tuple.types.get(&zcu.intern_pool)) |field_ty| { | 3043 | .tuple_type => |tuple| for (tuple.types.get(&zcu.intern_pool)) |field_ty| { |
| 2907 | assertHasLayout(.fromInterned(field_ty), zcu); | 3044 | assertHasLayout(.fromInterned(field_ty), zcu); |
| 2908 | }, | 3045 | }, |
| 2909 | .struct_type, .union_type => { | 3046 | .struct_type, .union_type, .enum_type => { |
| 2910 | const unit: InternPool.AnalUnit = .wrap(.{ .type_layout = ty.toIntern() }); | 3047 | const unit: InternPool.AnalUnit = .wrap(.{ .type_layout = ty.toIntern() }); |
| 2911 | assert(!zcu.outdated.contains(unit)); | 3048 | assert(!zcu.outdated.contains(unit)); |
| 2912 | assert(!zcu.potentially_outdated.contains(unit)); | 3049 | assert(!zcu.potentially_outdated.contains(unit)); |
| 2913 | }, | 3050 | }, |
| 2914 | else => unreachable, // assertion failure; not a struct or union | ||
| 2915 | 3051 | ||
| 2916 | // values, not types | 3052 | // values, not types |
| 2917 | .simple_value, | 3053 | .simple_value, |
| ... | @@ -2930,23 +3066,13 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void { | ... | @@ -2930,23 +3066,13 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void { |
| 2930 | .opt, | 3066 | .opt, |
| 2931 | .aggregate, | 3067 | .aggregate, |
| 2932 | .un, | 3068 | .un, |
| 3069 | .undef, | ||
| 2933 | // memoization, not types | 3070 | // memoization, not types |
| 2934 | .memoized_call, | 3071 | .memoized_call, |
| 2935 | => unreachable, | 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 | /// Recursively walks the type and marks for each subtype how many times it has been seen | 3076 | /// Recursively walks the type and marks for each subtype how many times it has been seen |
| 2951 | fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUnmanaged(Type, u16)) error{OutOfMemory}!void { | 3077 | fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUnmanaged(Type, u16)) error{OutOfMemory}!void { |
| 2952 | const zcu = pt.zcu; | 3078 | const zcu = pt.zcu; |
| ... | @@ -3116,6 +3242,7 @@ pub const Comparison = struct { | ... | @@ -3116,6 +3242,7 @@ pub const Comparison = struct { |
| 3116 | }; | 3242 | }; |
| 3117 | }; | 3243 | }; |
| 3118 | 3244 | ||
| 3245 | pub const @"u0": Type = .{ .ip_index = .u0_type }; | ||
| 3119 | pub const @"u1": Type = .{ .ip_index = .u1_type }; | 3246 | pub const @"u1": Type = .{ .ip_index = .u1_type }; |
| 3120 | pub const @"u8": Type = .{ .ip_index = .u8_type }; | 3247 | pub const @"u8": Type = .{ .ip_index = .u8_type }; |
| 3121 | pub const @"u16": Type = .{ .ip_index = .u16_type }; | 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,7 +2207,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh |
| 2207 | 2207 | ||
| 2208 | const ptr_ty_info = Type.fromInterned(ptr.ty).ptrInfo(zcu); | 2208 | const ptr_ty_info = Type.fromInterned(ptr.ty).ptrInfo(zcu); |
| 2209 | const need_child: Type = .fromInterned(ptr_ty_info.child); | 2209 | const need_child: Type = .fromInterned(ptr_ty_info.child); |
| 2210 | if (need_child.comptimeOnly(zcu)) { | 2210 | if (need_child.comptimeOnly(zcu) or need_child.zigTypeTag(zcu) == .@"opaque") { |
| 2211 | // No refinement can happen - this pointer is presumably invalid. | 2211 | // No refinement can happen - this pointer is presumably invalid. |
| 2212 | // Just offset it. | 2212 | // Just offset it. |
| 2213 | const parent = try arena.create(PointerDeriveStep); | 2213 | const parent = try arena.create(PointerDeriveStep); |
| ... | @@ -2595,8 +2595,8 @@ pub fn uninterpret(val: anytype, ty: Type, pt: Zcu.PerThread) error{ OutOfMemory | ... | @@ -2595,8 +2595,8 @@ pub fn uninterpret(val: anytype, ty: Type, pt: Zcu.PerThread) error{ OutOfMemory |
| 2595 | pub fn doPointersOverlap(ptr_val_a: Value, ptr_val_b: Value, elem_count: u64, zcu: *const Zcu) bool { | 2595 | pub fn doPointersOverlap(ptr_val_a: Value, ptr_val_b: Value, elem_count: u64, zcu: *const Zcu) bool { |
| 2596 | const ip = &zcu.intern_pool; | 2596 | const ip = &zcu.intern_pool; |
| 2597 | 2597 | ||
| 2598 | const a_elem_ty = ptr_val_a.typeOf(zcu).indexablePtrElem(zcu); | 2598 | const a_elem_ty = ptr_val_a.typeOf(zcu).indexableElem(zcu); |
| 2599 | const b_elem_ty = ptr_val_b.typeOf(zcu).indexablePtrElem(zcu); | 2599 | const b_elem_ty = ptr_val_b.typeOf(zcu).indexableElem(zcu); |
| 2600 | 2600 | ||
| 2601 | const a_ptr = ip.indexToKey(ptr_val_a.toIntern()).ptr; | 2601 | const a_ptr = ip.indexToKey(ptr_val_a.toIntern()).ptr; |
| 2602 | const b_ptr = ip.indexToKey(ptr_val_b.toIntern()).ptr; | 2602 | const b_ptr = ip.indexToKey(ptr_val_b.toIntern()).ptr; |
| ... | @@ -2682,3 +2682,58 @@ pub fn eqlScalarNum(lhs: Value, rhs: Value, zcu: *Zcu) bool { | ... | @@ -2682,3 +2682,58 @@ pub fn eqlScalarNum(lhs: Value, rhs: Value, zcu: *Zcu) bool { |
| 2682 | const rhs_bigint = rhs.toBigInt(&rhs_bigint_space, zcu); | 2682 | const rhs_bigint = rhs.toBigInt(&rhs_bigint_space, zcu); |
| 2683 | return lhs_bigint.eql(rhs_bigint); | 2683 | return lhs_bigint.eql(rhs_bigint); |
| 2684 | } | 2684 | } |
| 2685 | |||
| 2686 | /// Asserts the value is an integer, and the destination type is ComptimeInt or Int. | ||
| 2687 | /// Vectors are also accepted. Vector results are reduced with AND. | ||
| 2688 | /// | ||
| 2689 | /// If provided, `vector_index` reports the first element that failed the range check. | ||
| 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,40 +1912,6 @@ pub const SrcLoc = struct { |
| 1912 | const full = tree.fullPtrType(parent_node).?; | 1912 | const full = tree.fullPtrType(parent_node).?; |
| 1913 | return tree.nodeToSpan(full.ast.bit_range_end.unwrap().?); | 1913 | return tree.nodeToSpan(full.ast.bit_range_end.unwrap().?); |
| 1914 | }, | 1914 | }, |
| 1915 | .node_offset_container_tag => |node_off| { | ||
| 1916 | const tree = try src_loc.file_scope.getTree(zcu); | ||
| 1917 | const parent_node = node_off.toAbsolute(src_loc.base_node); | ||
| 1918 | |||
| 1919 | switch (tree.nodeTag(parent_node)) { | ||
| 1920 | .container_decl_arg, .container_decl_arg_trailing => { | ||
| 1921 | const full = tree.containerDeclArg(parent_node); | ||
| 1922 | const arg_node = full.ast.arg.unwrap().?; | ||
| 1923 | return tree.nodeToSpan(arg_node); | ||
| 1924 | }, | ||
| 1925 | .tagged_union_enum_tag, .tagged_union_enum_tag_trailing => { | ||
| 1926 | const full = tree.taggedUnionEnumTag(parent_node); | ||
| 1927 | const arg_node = full.ast.arg.unwrap().?; | ||
| 1928 | |||
| 1929 | return tree.tokensToSpan( | ||
| 1930 | tree.firstToken(arg_node) - 2, | ||
| 1931 | tree.lastToken(arg_node) + 1, | ||
| 1932 | tree.nodeMainToken(arg_node), | ||
| 1933 | ); | ||
| 1934 | }, | ||
| 1935 | else => unreachable, | ||
| 1936 | } | ||
| 1937 | }, | ||
| 1938 | .node_offset_field_default => |node_off| { | ||
| 1939 | const tree = try src_loc.file_scope.getTree(zcu); | ||
| 1940 | const parent_node = node_off.toAbsolute(src_loc.base_node); | ||
| 1941 | |||
| 1942 | const full: Ast.full.ContainerField = switch (tree.nodeTag(parent_node)) { | ||
| 1943 | .container_field => tree.containerField(parent_node), | ||
| 1944 | .container_field_init => tree.containerFieldInit(parent_node), | ||
| 1945 | else => unreachable, | ||
| 1946 | }; | ||
| 1947 | return tree.nodeToSpan(full.ast.value_expr.unwrap().?); | ||
| 1948 | }, | ||
| 1949 | .node_offset_init_ty => |node_off| { | 1915 | .node_offset_init_ty => |node_off| { |
| 1950 | const tree = try src_loc.file_scope.getTree(zcu); | 1916 | const tree = try src_loc.file_scope.getTree(zcu); |
| 1951 | const parent_node = node_off.toAbsolute(src_loc.base_node); | 1917 | const parent_node = node_off.toAbsolute(src_loc.base_node); |
| ... | @@ -2021,6 +1987,14 @@ pub const SrcLoc = struct { | ... | @@ -2021,6 +1987,14 @@ pub const SrcLoc = struct { |
| 2021 | } | 1987 | } |
| 2022 | return tree.nodeToSpan(node); | 1988 | return tree.nodeToSpan(node); |
| 2023 | }, | 1989 | }, |
| 1990 | .container_arg => { | ||
| 1991 | const tree = try src_loc.file_scope.getTree(zcu); | ||
| 1992 | const node = src_loc.base_node; | ||
| 1993 | var buf: [2]Ast.Node.Index = undefined; | ||
| 1994 | const container_decl = tree.fullContainerDecl(&buf, node) orelse return tree.nodeToSpan(node); | ||
| 1995 | const arg_node = container_decl.ast.arg.unwrap() orelse return tree.nodeToSpan(node); | ||
| 1996 | return tree.nodeToSpan(arg_node); | ||
| 1997 | }, | ||
| 2024 | .container_field_name, | 1998 | .container_field_name, |
| 2025 | .container_field_value, | 1999 | .container_field_value, |
| 2026 | .container_field_type, | 2000 | .container_field_type, |
| ... | @@ -2262,7 +2236,11 @@ pub const SrcLoc = struct { | ... | @@ -2262,7 +2236,11 @@ pub const SrcLoc = struct { |
| 2262 | var param_it = full.iterate(tree); | 2236 | var param_it = full.iterate(tree); |
| 2263 | for (0..param_idx) |_| assert(param_it.next() != null); | 2237 | for (0..param_idx) |_| assert(param_it.next() != null); |
| 2264 | const param = param_it.next().?; | 2238 | const param = param_it.next().?; |
| 2265 | return tree.nodeToSpan(param.type_expr.?); | 2239 | if (param.anytype_ellipsis3) |tok| { |
| 2240 | return tree.tokenToSpan(tok); | ||
| 2241 | } else { | ||
| 2242 | return tree.nodeToSpan(param.type_expr.?); | ||
| 2243 | } | ||
| 2266 | }, | 2244 | }, |
| 2267 | } | 2245 | } |
| 2268 | } | 2246 | } |
| ... | @@ -2484,10 +2462,6 @@ pub const LazySrcLoc = struct { | ... | @@ -2484,10 +2462,6 @@ pub const LazySrcLoc = struct { |
| 2484 | node_offset_ptr_bitoffset: Ast.Node.Offset, | 2462 | node_offset_ptr_bitoffset: Ast.Node.Offset, |
| 2485 | /// The source location points to the host size of a pointer. | 2463 | /// The source location points to the host size of a pointer. |
| 2486 | node_offset_ptr_hostsize: Ast.Node.Offset, | 2464 | node_offset_ptr_hostsize: Ast.Node.Offset, |
| 2487 | /// The source location points to the tag type of an union or an enum. | ||
| 2488 | node_offset_container_tag: Ast.Node.Offset, | ||
| 2489 | /// The source location points to the default value of a field. | ||
| 2490 | node_offset_field_default: Ast.Node.Offset, | ||
| 2491 | /// The source location points to the type of an array or struct initializer. | 2465 | /// The source location points to the type of an array or struct initializer. |
| 2492 | node_offset_init_ty: Ast.Node.Offset, | 2466 | node_offset_init_ty: Ast.Node.Offset, |
| 2493 | /// The source location points to the LHS of an assignment (or assign-op, e.g. `+=`). | 2467 | /// The source location points to the LHS of an assignment (or assign-op, e.g. `+=`). |
| ... | @@ -2532,6 +2506,11 @@ pub const LazySrcLoc = struct { | ... | @@ -2532,6 +2506,11 @@ pub const LazySrcLoc = struct { |
| 2532 | fn_proto_param_type: FnProtoParam, | 2506 | fn_proto_param_type: FnProtoParam, |
| 2533 | array_cat_lhs: ArrayCat, | 2507 | array_cat_lhs: ArrayCat, |
| 2534 | array_cat_rhs: ArrayCat, | 2508 | array_cat_rhs: ArrayCat, |
| 2509 | /// The source location points to the backing or tag type expression of | ||
| 2510 | /// the container type declaration at the base node. | ||
| 2511 | /// | ||
| 2512 | /// For 'union(enum(T))', this points to 'T', not 'enum(T)'. | ||
| 2513 | container_arg, | ||
| 2535 | /// The source location points to the name of the field at the given index | 2514 | /// The source location points to the name of the field at the given index |
| 2536 | /// of the container type declaration at the base node. | 2515 | /// of the container type declaration at the base node. |
| 2537 | container_field_name: u32, | 2516 | container_field_name: u32, |
| ... | @@ -3149,7 +3128,7 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void { | ... | @@ -3149,7 +3128,7 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void { |
| 3149 | .nav_val => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_val = nav }), | 3128 | .nav_val => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_val = nav }), |
| 3150 | .nav_ty => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_ty = nav }), | 3129 | .nav_ty => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_ty = nav }), |
| 3151 | .type_layout => |ty| try zcu.markPoDependeeUpToDate(.{ .type_layout = ty }), | 3130 | .type_layout => |ty| try zcu.markPoDependeeUpToDate(.{ .type_layout = ty }), |
| 3152 | .type_inits => |ty| try zcu.markPoDependeeUpToDate(.{ .type_inits = ty }), | 3131 | .struct_defaults => |ty| try zcu.markPoDependeeUpToDate(.{ .struct_defaults = ty }), |
| 3153 | .func => |func| try zcu.markPoDependeeUpToDate(.{ .func_ies = func }), | 3132 | .func => |func| try zcu.markPoDependeeUpToDate(.{ .func_ies = func }), |
| 3154 | .memoized_state => |stage| try zcu.markPoDependeeUpToDate(.{ .memoized_state = stage }), | 3133 | .memoized_state => |stage| try zcu.markPoDependeeUpToDate(.{ .memoized_state = stage }), |
| 3155 | } | 3134 | } |
| ... | @@ -3165,7 +3144,7 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni | ... | @@ -3165,7 +3144,7 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni |
| 3165 | .nav_val => |nav| .{ .nav_val = nav }, | 3144 | .nav_val => |nav| .{ .nav_val = nav }, |
| 3166 | .nav_ty => |nav| .{ .nav_ty = nav }, | 3145 | .nav_ty => |nav| .{ .nav_ty = nav }, |
| 3167 | .type_layout => |ty| .{ .type_layout = ty }, | 3146 | .type_layout => |ty| .{ .type_layout = ty }, |
| 3168 | .type_inits => |ty| .{ .type_inits = ty }, | 3147 | .struct_defaults => |ty| .{ .struct_defaults = ty }, |
| 3169 | .func => |func_index| .{ .func_ies = func_index }, | 3148 | .func => |func_index| .{ .func_ies = func_index }, |
| 3170 | .memoized_state => |stage| .{ .memoized_state = stage }, | 3149 | .memoized_state => |stage| .{ .memoized_state = stage }, |
| 3171 | }; | 3150 | }; |
| ... | @@ -3195,88 +3174,44 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni | ... | @@ -3195,88 +3174,44 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni |
| 3195 | } | 3174 | } |
| 3196 | } | 3175 | } |
| 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 | pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { | 3181 | pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { |
| 3199 | if (!zcu.comp.config.incremental) return null; | 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 | if (zcu.outdated_ready.count() > 0) { | 3184 | if (zcu.outdated_ready.count() > 0) { |
| 3220 | const unit = zcu.outdated_ready.keys()[0]; | 3185 | const unit = zcu.outdated_ready.keys()[0]; |
| 3221 | log.debug("findOutdatedToAnalyze: trivial {f}", .{zcu.fmtAnalUnit(unit)}); | 3186 | log.debug("findOutdatedToAnalyze: {f}", .{zcu.fmtAnalUnit(unit)}); |
| 3222 | return unit; | 3187 | return unit; |
| 3223 | } | 3188 | } |
| 3224 | 3189 | ||
| 3225 | // There is no single AnalUnit which is ready for re-analysis. Instead, we must assume that some | 3190 | // Usually, getting here means that everything is up-to-date, so there is no more work to do. We |
| 3226 | // AnalUnit with PO dependencies is outdated -- e.g. in the above example we arbitrarily pick one of | 3191 | // will see that `zcu.outdated` and `zcu.potentially_outdated` are both empty. |
| 3227 | // A or B. We should definitely not select a function, since a function can't be responsible for the | 3192 | // |
| 3228 | // loop (IES dependencies can't have loops). We should also, of course, not select a `comptime` | 3193 | // However, if a previous update had a dependency loop compile error, there is a cycle in the |
| 3229 | // declaration, since you can't depend on those! | 3194 | // dependency graph (which is usually acyclic), which can cause a scenario where no unit appears |
| 3230 | 3195 | // to be ready, because they're all waiting for the next in the loop to be up-to-date. In that | |
| 3231 | // The choice of this unit could have a big impact on how much total analysis we perform, since | 3196 | // case, we usually have to just bite the bullet and analyze one of them. An exception is if |
| 3232 | // if analysis concludes any dependencies on its result are up-to-date, then other PO AnalUnit | 3197 | // `zcu.outdated` is empty but `zcu.potentially_outdated` is non-empty: in that case, the only |
| 3233 | // may be resolved as up-to-date. To hopefully avoid doing too much work, let's find a unit | 3198 | // possible situation is a cycle where everything is actually up-to-date, so we can clear out |
| 3234 | // which the most things depend on - the idea is that this will resolve a lot of loops (but this | 3199 | // `zcu.potentially_outdated` and we are done. |
| 3235 | // is only a heuristic). | ||
| 3236 | |||
| 3237 | log.debug("findOutdatedToAnalyze: no trivial ready, using heuristic; {d} outdated, {d} PO", .{ | ||
| 3238 | zcu.outdated.count(), | ||
| 3239 | zcu.potentially_outdated.count(), | ||
| 3240 | }); | ||
| 3241 | |||
| 3242 | const ip = &zcu.intern_pool; | ||
| 3243 | |||
| 3244 | var chosen_unit: ?AnalUnit = null; | ||
| 3245 | var chosen_unit_dependers: u32 = undefined; | ||
| 3246 | |||
| 3247 | // MLUGG TODO: i'm 99% sure this is now impossible. check!!! | ||
| 3248 | inline for (.{ zcu.outdated.keys(), zcu.potentially_outdated.keys() }) |outdated_units| { | ||
| 3249 | for (outdated_units) |unit| { | ||
| 3250 | var n: u32 = 0; | ||
| 3251 | var it = ip.dependencyIterator(switch (unit.unwrap()) { | ||
| 3252 | .func => continue, // a `func` definitely can't be causing the loop so it is a bad choice | ||
| 3253 | .@"comptime" => continue, // a `comptime` block can't even be depended on so it is a terrible choice | ||
| 3254 | .type_layout => |ty| .{ .type_layout = ty }, | ||
| 3255 | .type_inits => |ty| .{ .type_inits = ty }, | ||
| 3256 | .nav_val => |nav| .{ .nav_val = nav }, | ||
| 3257 | .nav_ty => |nav| .{ .nav_ty = nav }, | ||
| 3258 | .memoized_state => { | ||
| 3259 | // If we've hit a loop and some `.memoized_state` is outdated, we should make that choice eagerly. | ||
| 3260 | // In general, it's good to resolve this early on, since -- for instance -- almost every function | ||
| 3261 | // references the panic handler. | ||
| 3262 | return unit; | ||
| 3263 | }, | ||
| 3264 | }); | ||
| 3265 | while (it.next()) |_| n += 1; | ||
| 3266 | 3200 | ||
| 3267 | if (chosen_unit == null or n > chosen_unit_dependers) { | 3201 | if (zcu.outdated.count() == 0) { |
| 3268 | chosen_unit = unit; | 3202 | // Everything is up-to-date. There could be lingering entries in `zcu.potentially_outdated` |
| 3269 | chosen_unit_dependers = n; | 3203 | // from a dependency loop on a previous update. |
| 3270 | } | 3204 | zcu.potentially_outdated.clearRetainingCapacity(); |
| 3271 | } | 3205 | log.debug("findOutdatedToAnalyze: all up-to-date", .{}); |
| 3206 | return null; | ||
| 3272 | } | 3207 | } |
| 3273 | 3208 | ||
| 3274 | log.debug("findOutdatedToAnalyze: heuristic returned '{f}' ({d} dependers)", .{ | 3209 | const unit = zcu.outdated.keys()[0]; |
| 3275 | zcu.fmtAnalUnit(chosen_unit.?), | 3210 | log.debug("findOutdatedToAnalyze: dependency loop affecting {d} units, selected {f}", .{ |
| 3276 | chosen_unit_dependers, | 3211 | zcu.outdated.count(), |
| 3212 | zcu.fmtAnalUnit(unit), | ||
| 3277 | }); | 3213 | }); |
| 3278 | 3214 | return unit; | |
| 3279 | return chosen_unit.?; | ||
| 3280 | } | 3215 | } |
| 3281 | 3216 | ||
| 3282 | /// During an incremental update, before semantic analysis, call this to flush all values from | 3217 | /// During an incremental update, before semantic analysis, call this to flush all values from |
| ... | @@ -3356,12 +3291,59 @@ pub fn mapOldZirToNew( | ... | @@ -3356,12 +3291,59 @@ pub fn mapOldZirToNew( |
| 3356 | } | 3291 | } |
| 3357 | 3292 | ||
| 3358 | while (match_stack.pop()) |match_item| { | 3293 | while (match_stack.pop()) |match_item| { |
| 3359 | // First, a check: if the number of captures of this type has changed, we can't map it, because | 3294 | // There are some properties of type declarations which cannot change across incremental |
| 3360 | // we wouldn't know how to correlate type information with the last update. | 3295 | // updates. If they have, we need to ignore this mapping. These properties are essentially |
| 3361 | // Synchronizes with logic in `Zcu.PerThread.recreateStructType` etc. | 3296 | // everything passed into `InternPool.getDeclaredStructType` (likewise for unions, enums, |
| 3362 | if (old_zir.typeCapturesLen(match_item.old_inst) != new_zir.typeCapturesLen(match_item.new_inst)) { | 3297 | // and opaques). |
| 3363 | // Don't map this type or anything within it. | 3298 | const old_tag = old_zir.instructions.items(.data)[@intFromEnum(match_item.old_inst)].extended.opcode; |
| 3364 | continue; | 3299 | const new_tag = new_zir.instructions.items(.data)[@intFromEnum(match_item.new_inst)].extended.opcode; |
| 3300 | if (old_tag != new_tag) continue; | ||
| 3301 | switch (old_tag) { | ||
| 3302 | .struct_decl => { | ||
| 3303 | const old = old_zir.getStructDecl(match_item.old_inst); | ||
| 3304 | const new = new_zir.getStructDecl(match_item.new_inst); | ||
| 3305 | if (old.captures.len != new.captures.len) continue; | ||
| 3306 | if (old.field_names.len != new.field_names.len) continue; | ||
| 3307 | if (old.layout != new.layout) continue; | ||
| 3308 | const old_any_field_aligns = old.field_align_body_lens != null; | ||
| 3309 | const old_any_field_defaults = old.field_default_body_lens != null; | ||
| 3310 | const old_any_comptime_fields = old.field_comptime_bits != null; | ||
| 3311 | const old_explicit_backing_int = old.backing_int_type_body != null; | ||
| 3312 | const new_any_field_aligns = new.field_align_body_lens != null; | ||
| 3313 | const new_any_field_defaults = new.field_default_body_lens != null; | ||
| 3314 | const new_any_comptime_fields = new.field_comptime_bits != null; | ||
| 3315 | const new_explicit_backing_int = new.backing_int_type_body != null; | ||
| 3316 | if (old_any_field_aligns != new_any_field_aligns) continue; | ||
| 3317 | if (old_any_field_defaults != new_any_field_defaults) continue; | ||
| 3318 | if (old_any_comptime_fields != new_any_comptime_fields) continue; | ||
| 3319 | if (old_explicit_backing_int != new_explicit_backing_int) continue; | ||
| 3320 | }, | ||
| 3321 | .union_decl => { | ||
| 3322 | const old = old_zir.getUnionDecl(match_item.old_inst); | ||
| 3323 | const new = new_zir.getUnionDecl(match_item.new_inst); | ||
| 3324 | if (old.captures.len != new.captures.len) continue; | ||
| 3325 | if (old.field_names.len != new.field_names.len) continue; | ||
| 3326 | if (old.kind != new.kind) continue; | ||
| 3327 | const old_any_field_aligns = old.field_align_body_lens != null; | ||
| 3328 | const new_any_field_aligns = new.field_align_body_lens != null; | ||
| 3329 | if (old_any_field_aligns != new_any_field_aligns) continue; | ||
| 3330 | }, | ||
| 3331 | .enum_decl => { | ||
| 3332 | const old = old_zir.getEnumDecl(match_item.old_inst); | ||
| 3333 | const new = new_zir.getEnumDecl(match_item.new_inst); | ||
| 3334 | if (old.captures.len != new.captures.len) continue; | ||
| 3335 | if (old.field_names.len != new.field_names.len) continue; | ||
| 3336 | if (old.nonexhaustive != new.nonexhaustive) continue; | ||
| 3337 | const old_explicit_tag_type = old.tag_type_body != null; | ||
| 3338 | const new_explicit_tag_type = new.tag_type_body != null; | ||
| 3339 | if (old_explicit_tag_type != new_explicit_tag_type) continue; | ||
| 3340 | }, | ||
| 3341 | .opaque_decl => { | ||
| 3342 | const old = old_zir.getOpaqueDecl(match_item.old_inst); | ||
| 3343 | const new = new_zir.getOpaqueDecl(match_item.new_inst); | ||
| 3344 | if (old.captures.len != new.captures.len) continue; | ||
| 3345 | }, | ||
| 3346 | else => unreachable, | ||
| 3365 | } | 3347 | } |
| 3366 | 3348 | ||
| 3367 | // Match the namespace declaration itself | 3349 | // Match the namespace declaration itself |
| ... | @@ -4068,7 +4050,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R | ... | @@ -4068,7 +4050,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R |
| 4068 | } | 4050 | } |
| 4069 | if (has_inits) { | 4051 | if (has_inits) { |
| 4070 | // this should only be referenced by the type | 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 | try units.putNoClobber(gpa, unit, referencer); | 4054 | try units.putNoClobber(gpa, unit, referencer); |
| 4073 | } | 4055 | } |
| 4074 | 4056 | ||
| ... | @@ -4184,7 +4166,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R | ... | @@ -4184,7 +4166,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R |
| 4184 | const other: AnalUnit = .wrap(switch (unit.unwrap()) { | 4166 | const other: AnalUnit = .wrap(switch (unit.unwrap()) { |
| 4185 | .nav_val => |n| .{ .nav_ty = n }, | 4167 | .nav_val => |n| .{ .nav_ty = n }, |
| 4186 | .nav_ty => |n| .{ .nav_val = n }, | 4168 | .nav_ty => |n| .{ .nav_val = n }, |
| 4187 | .@"comptime", .type_layout, .type_inits, .func, .memoized_state => break :queue_paired, | 4169 | .@"comptime", .type_layout, .struct_defaults, .func, .memoized_state => break :queue_paired, |
| 4188 | }); | 4170 | }); |
| 4189 | const gop = try units.getOrPut(gpa, other); | 4171 | const gop = try units.getOrPut(gpa, other); |
| 4190 | if (gop.found_existing) break :queue_paired; | 4172 | if (gop.found_existing) break :queue_paired; |
| ... | @@ -4305,6 +4287,16 @@ pub fn navFileScope(zcu: *Zcu, nav: InternPool.Nav.Index) *File { | ... | @@ -4305,6 +4287,16 @@ pub fn navFileScope(zcu: *Zcu, nav: InternPool.Nav.Index) *File { |
| 4305 | return zcu.fileByIndex(zcu.navFileScopeIndex(nav)); | 4287 | return zcu.fileByIndex(zcu.navFileScopeIndex(nav)); |
| 4306 | } | 4288 | } |
| 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 | pub fn fmtAnalUnit(zcu: *Zcu, unit: AnalUnit) std.fmt.Alt(FormatAnalUnit, formatAnalUnit) { | 4300 | pub fn fmtAnalUnit(zcu: *Zcu, unit: AnalUnit) std.fmt.Alt(FormatAnalUnit, formatAnalUnit) { |
| 4309 | return .{ .data = .{ .unit = unit, .zcu = zcu } }; | 4301 | return .{ .data = .{ .unit = unit, .zcu = zcu } }; |
| 4310 | } | 4302 | } |
| ... | @@ -4331,7 +4323,7 @@ fn formatAnalUnit(data: FormatAnalUnit, writer: *Io.Writer) Io.Writer.Error!void | ... | @@ -4331,7 +4323,7 @@ fn formatAnalUnit(data: FormatAnalUnit, writer: *Io.Writer) Io.Writer.Error!void |
| 4331 | } | 4323 | } |
| 4332 | }, | 4324 | }, |
| 4333 | .nav_val, .nav_ty => |nav, tag| return writer.print("{t}('{f}' [{}])", .{ tag, ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }), | 4325 | .nav_val, .nav_ty => |nav, tag| return writer.print("{t}('{f}' [{}])", .{ tag, ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }), |
| 4334 | .type_layout, .type_inits => |ty, tag| return writer.print("{t}('{f}' [{}])", .{ tag, Type.fromInterned(ty).containerTypeName(ip).fmt(ip), @intFromEnum(ty) }), | 4326 | .type_layout, .struct_defaults => |ty, tag| return writer.print("{t}('{f}' [{}])", .{ tag, Type.fromInterned(ty).containerTypeName(ip).fmt(ip), @intFromEnum(ty) }), |
| 4335 | .func => |func| { | 4327 | .func => |func| { |
| 4336 | const nav = zcu.funcInfo(func).owner_nav; | 4328 | const nav = zcu.funcInfo(func).owner_nav; |
| 4337 | return writer.print("func('{f}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(func) }); | 4329 | return writer.print("func('{f}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(func) }); |
| ... | @@ -4357,7 +4349,7 @@ fn formatDependee(data: FormatDependee, writer: *Io.Writer) Io.Writer.Error!void | ... | @@ -4357,7 +4349,7 @@ fn formatDependee(data: FormatDependee, writer: *Io.Writer) Io.Writer.Error!void |
| 4357 | const fqn = ip.getNav(nav).fqn; | 4349 | const fqn = ip.getNav(nav).fqn; |
| 4358 | return writer.print("{t}('{f}')", .{ tag, fqn.fmt(ip) }); | 4350 | return writer.print("{t}('{f}')", .{ tag, fqn.fmt(ip) }); |
| 4359 | }, | 4351 | }, |
| 4360 | .type_layout, .type_inits => |ip_index, tag| { | 4352 | .type_layout, .struct_defaults => |ip_index, tag| { |
| 4361 | const name = Type.fromInterned(ip_index).containerTypeName(ip); | 4353 | const name = Type.fromInterned(ip_index).containerTypeName(ip); |
| 4362 | return writer.print("{t}('{f}')", .{ tag, name.fmt(ip) }); | 4354 | return writer.print("{t}('{f}')", .{ tag, name.fmt(ip) }); |
| 4363 | }, | 4355 | }, |
src/Zcu/PerThread.zig+67-88| ... | @@ -695,20 +695,46 @@ pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) (Alloca | ... | @@ -695,20 +695,46 @@ pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) (Alloca |
| 695 | .file = file_index, | 695 | .file = file_index, |
| 696 | .inst = .main_struct_inst, | 696 | .inst = .main_struct_inst, |
| 697 | }); | 697 | }); |
| 698 | const file_root_type = try Sema.analyzeStructDecl( | 698 | const wip: InternPool.WipContainerType = switch (try ip.getDeclaredStructType(gpa, io, pt.tid, .{ |
| 699 | pt, | 699 | .zir_index = tracked_inst, |
| 700 | file_index, | 700 | .captures = &.{}, |
| 701 | &file.zir.?, | 701 | .fields_len = @intCast(struct_decl.field_names.len), |
| 702 | .none, | 702 | .layout = struct_decl.layout, |
| 703 | tracked_inst, | 703 | .any_comptime_fields = struct_decl.field_comptime_bits != null, |
| 704 | &struct_decl, | 704 | .any_field_defaults = struct_decl.field_default_body_lens != null, |
| 705 | null, | 705 | .any_field_aligns = struct_decl.field_align_body_lens != null, |
| 706 | &.{}, | 706 | .packed_backing_mode = if (struct_decl.backing_int_type_body != null) .explicit else .auto, |
| 707 | .{ .exact = .{ | 707 | })) { |
| 708 | .name = try file.internFullyQualifiedName(pt), | 708 | .existing => unreachable, // it would have been set as `zcu.fileRootType` already |
| 709 | .nav = .none, | 709 | .wip => |wip| wip, |
| 710 | } }, | 710 | }; |
| 711 | ); | 711 | errdefer wip.cancel(ip, pt.tid); |
| 712 | |||
| 713 | wip.setName(ip, try file.internFullyQualifiedName(pt), .none); | ||
| 714 | const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ | ||
| 715 | .parent = .none, | ||
| 716 | .owner_type = wip.index, | ||
| 717 | .file_scope = file_index, | ||
| 718 | .generation = zcu.generation, | ||
| 719 | }); | ||
| 720 | errdefer pt.destroyNamespace(new_namespace_index); | ||
| 721 | try pt.scanNamespace(new_namespace_index, struct_decl.decls); | ||
| 722 | // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind | ||
| 723 | try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) }); | ||
| 724 | try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .struct_defaults = wip.index }) }); | ||
| 725 | |||
| 726 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); | ||
| 727 | |||
| 728 | try zcu.outdated.ensureUnusedCapacity(gpa, 2); | ||
| 729 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 2); | ||
| 730 | errdefer comptime unreachable; // because we don't remove the `outdated` entries | ||
| 731 | zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); | ||
| 732 | zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .struct_defaults = wip.index }), 0); | ||
| 733 | zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); | ||
| 734 | zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .struct_defaults = wip.index }), {}); | ||
| 735 | |||
| 736 | const file_root_type: Type = .fromInterned(wip.finish(ip, new_namespace_index)); | ||
| 737 | |||
| 712 | zcu.setFileRootType(file_index, file_root_type.toIntern()); | 738 | zcu.setFileRootType(file_index, file_root_type.toIntern()); |
| 713 | if (zcu.comp.time_report) |*tr| tr.stats.n_imported_files += 1; | 739 | if (zcu.comp.time_report) |*tr| tr.stats.n_imported_files += 1; |
| 714 | } | 740 | } |
| ... | @@ -1048,11 +1074,6 @@ pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void | ... | @@ -1048,11 +1074,6 @@ pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void |
| 1048 | 1074 | ||
| 1049 | assert(!zcu.analysis_in_progress.contains(anal_unit)); | 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 | const was_outdated = zcu.outdated.swapRemove(anal_unit) or | 1077 | const was_outdated = zcu.outdated.swapRemove(anal_unit) or |
| 1057 | zcu.potentially_outdated.swapRemove(anal_unit); | 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,17 +1134,11 @@ pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void |
| 1113 | }; | 1134 | }; |
| 1114 | defer sema.deinit(); | 1135 | defer sema.deinit(); |
| 1115 | 1136 | ||
| 1116 | const result = switch (ty.containerLayout(zcu)) { | 1137 | const result = switch (ty.zigTypeTag(zcu)) { |
| 1117 | .auto, .@"extern" => switch (ty.zigTypeTag(zcu)) { | 1138 | .@"enum" => Sema.type_resolution.resolveEnumLayout(&sema, ty), |
| 1118 | .@"struct" => Sema.type_resolution.resolveStructLayout(&sema, ty), | 1139 | .@"struct" => Sema.type_resolution.resolveStructLayout(&sema, ty), |
| 1119 | .@"union" => Sema.type_resolution.resolveUnionLayout(&sema, ty), | 1140 | .@"union" => Sema.type_resolution.resolveUnionLayout(&sema, ty), |
| 1120 | else => unreachable, | 1141 | else => unreachable, |
| 1121 | }, | ||
| 1122 | .@"packed" => switch (ty.zigTypeTag(zcu)) { | ||
| 1123 | .@"struct" => Sema.type_resolution.resolvePackedStructLayout(&sema, ty), | ||
| 1124 | .@"union" => Sema.type_resolution.resolvePackedUnionLayout(&sema, ty), | ||
| 1125 | else => unreachable, | ||
| 1126 | }, | ||
| 1127 | }; | 1142 | }; |
| 1128 | result catch |err| switch (err) { | 1143 | result catch |err| switch (err) { |
| 1129 | error.AnalysisFail => { | 1144 | error.AnalysisFail => { |
| ... | @@ -1145,36 +1160,31 @@ pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void | ... | @@ -1145,36 +1160,31 @@ pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void |
| 1145 | sema.flushExports() catch |err| switch (err) { | 1160 | sema.flushExports() catch |err| switch (err) { |
| 1146 | error.OutOfMemory => |e| return e, | 1161 | error.OutOfMemory => |e| return e, |
| 1147 | }; | 1162 | }; |
| 1148 | |||
| 1149 | codegen_type: { | ||
| 1150 | if (zcu.comp.config.use_llvm) break :codegen_type; | ||
| 1151 | if (file.mod.?.strip) break :codegen_type; | ||
| 1152 | zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); | ||
| 1153 | try zcu.comp.queueJob(.{ .link_type = ty.toIntern() }); | ||
| 1154 | } | ||
| 1155 | } | 1163 | } |
| 1156 | 1164 | ||
| 1157 | /// Ensures that the default/tag values of the given `struct` or `enum` type are fully up-to-date, | 1165 | /// Ensures that the default values of the given "declared" (not reified) `struct` type are fully |
| 1158 | /// performing re-analysis if necessary. Asserts that `ty` is a struct (not a tuple!) or an enum. | 1166 | /// up-to-date, performing re-analysis if necessary. Asserts that `ty` is a struct (not tuple) type. |
| 1159 | /// Returns `error.AnalysisFail` if an analysis error is encountered during resolution; the caller | 1167 | /// Returns `error.AnalysisFail` if an analysis error is encountered while resolving the default |
| 1160 | /// is free to ignore this, since the error is already registered. | 1168 | /// field values; the caller is free to ignore this, since the error is already registered. |
| 1161 | pub fn ensureTypeInitsUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void { | 1169 | pub fn ensureStructDefaultsUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void { |
| 1162 | const tracy = trace(@src()); | 1170 | const tracy = trace(@src()); |
| 1163 | defer tracy.end(); | 1171 | defer tracy.end(); |
| 1164 | 1172 | ||
| 1165 | const zcu = pt.zcu; | 1173 | const zcu = pt.zcu; |
| 1166 | const gpa = zcu.gpa; | 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 | assert(!zcu.analysis_in_progress.contains(anal_unit)); | 1183 | assert(!zcu.analysis_in_progress.contains(anal_unit)); |
| 1173 | 1184 | ||
| 1174 | // Determine whether or not this type is outdated. For this kind of `AnalUnit`, that's | 1185 | // Determine whether or not this type is outdated. For this kind of `AnalUnit`, that's |
| 1175 | // the only indicator as to whether or not analysis is required; when a struct/enum is | 1186 | // the only indicator as to whether or not analysis is required; when a struct/enum is |
| 1176 | // first created, it's marked as outdated. | 1187 | // first created, it's marked as outdated. |
| 1177 | // MLUGG TODO: make that actually true, it's a good strategy here! | ||
| 1178 | 1188 | ||
| 1179 | const was_outdated = zcu.outdated.swapRemove(anal_unit) or | 1189 | const was_outdated = zcu.outdated.swapRemove(anal_unit) or |
| 1180 | zcu.potentially_outdated.swapRemove(anal_unit); | 1190 | zcu.potentially_outdated.swapRemove(anal_unit); |
| ... | @@ -1194,7 +1204,7 @@ pub fn ensureTypeInitsUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void { | ... | @@ -1194,7 +1204,7 @@ pub fn ensureTypeInitsUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void { |
| 1194 | } | 1204 | } |
| 1195 | // For types, we already know that we have to invalidate all dependees. | 1205 | // For types, we already know that we have to invalidate all dependees. |
| 1196 | // TODO: we actually *could* detect whether everything was the same. should we bother? | 1206 | // TODO: we actually *could* detect whether everything was the same. should we bother? |
| 1197 | try zcu.markDependeeOutdated(.marked_po, .{ .type_inits = ty.toIntern() }); | 1207 | try zcu.markDependeeOutdated(.marked_po, .{ .struct_defaults = ty.toIntern() }); |
| 1198 | } else { | 1208 | } else { |
| 1199 | // We can trust the current information about this unit. | 1209 | // We can trust the current information about this unit. |
| 1200 | if (zcu.failed_analysis.contains(anal_unit)) return error.AnalysisFail; | 1210 | if (zcu.failed_analysis.contains(anal_unit)) return error.AnalysisFail; |
| ... | @@ -1236,12 +1246,7 @@ pub fn ensureTypeInitsUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void { | ... | @@ -1236,12 +1246,7 @@ pub fn ensureTypeInitsUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void { |
| 1236 | }; | 1246 | }; |
| 1237 | defer sema.deinit(); | 1247 | defer sema.deinit(); |
| 1238 | 1248 | ||
| 1239 | const result = switch (ty.zigTypeTag(zcu)) { | 1249 | Sema.type_resolution.resolveStructDefaults(&sema, ty) catch |err| switch (err) { |
| 1240 | .@"struct" => Sema.type_resolution.resolveStructDefaults(&sema, ty), | ||
| 1241 | .@"enum" => Sema.type_resolution.resolveEnumValues(&sema, ty), | ||
| 1242 | else => unreachable, | ||
| 1243 | }; | ||
| 1244 | result catch |err| switch (err) { | ||
| 1245 | error.AnalysisFail => { | 1250 | error.AnalysisFail => { |
| 1246 | if (!zcu.failed_analysis.contains(anal_unit)) { | 1251 | if (!zcu.failed_analysis.contains(anal_unit)) { |
| 1247 | // If this unit caused the error, it would have an entry in `failed_analysis`. | 1252 | // If this unit caused the error, it would have an entry in `failed_analysis`. |
| ... | @@ -1270,20 +1275,6 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu | ... | @@ -1270,20 +1275,6 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu |
| 1270 | const tracy = trace(@src()); | 1275 | const tracy = trace(@src()); |
| 1271 | defer tracy.end(); | 1276 | defer tracy.end(); |
| 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 | const zcu = pt.zcu; | 1278 | const zcu = pt.zcu; |
| 1288 | const gpa = zcu.gpa; | 1279 | const gpa = zcu.gpa; |
| 1289 | const ip = &zcu.intern_pool; | 1280 | const ip = &zcu.intern_pool; |
| ... | @@ -3033,7 +3024,7 @@ fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.Sem | ... | @@ -3033,7 +3024,7 @@ fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.Sem |
| 3033 | const zir = file.zir.?; | 3024 | const zir = file.zir.?; |
| 3034 | 3025 | ||
| 3035 | try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, {}); | 3026 | try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, {}); |
| 3036 | errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit); | 3027 | defer assert(zcu.analysis_in_progress.swapRemove(anal_unit)); |
| 3037 | 3028 | ||
| 3038 | func.setAnalyzed(ip, io); | 3029 | func.setAnalyzed(ip, io); |
| 3039 | if (func.analysisUnordered(ip).inferred_error_set) { | 3030 | if (func.analysisUnordered(ip).inferred_error_set) { |
| ... | @@ -3231,9 +3222,6 @@ fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.Sem | ... | @@ -3231,9 +3222,6 @@ fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.Sem |
| 3231 | func.setResolvedErrorSet(ip, io, ies.resolved); | 3222 | func.setResolvedErrorSet(ip, io, ies.resolved); |
| 3232 | } | 3223 | } |
| 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 | try sema.flushExports(); | 3225 | try sema.flushExports(); |
| 3238 | 3226 | ||
| 3239 | defer { | 3227 | defer { |
| ... | @@ -3835,7 +3823,6 @@ pub fn enumValue(pt: Zcu.PerThread, ty: Type, tag_int: InternPool.Index) Allocat | ... | @@ -3835,7 +3823,6 @@ pub fn enumValue(pt: Zcu.PerThread, ty: Type, tag_int: InternPool.Index) Allocat |
| 3835 | /// declaration order. | 3823 | /// declaration order. |
| 3836 | pub fn enumValueFieldIndex(pt: Zcu.PerThread, ty: Type, field_index: u32) Allocator.Error!Value { | 3824 | pub fn enumValueFieldIndex(pt: Zcu.PerThread, ty: Type, field_index: u32) Allocator.Error!Value { |
| 3837 | const ip = &pt.zcu.intern_pool; | 3825 | const ip = &pt.zcu.intern_pool; |
| 3838 | ty.assertHasInits(pt.zcu); | ||
| 3839 | const enum_type = ip.loadEnumType(ty.toIntern()); | 3826 | const enum_type = ip.loadEnumType(ty.toIntern()); |
| 3840 | 3827 | ||
| 3841 | assert(field_index < enum_type.field_names.len); | 3828 | assert(field_index < enum_type.field_names.len); |
| ... | @@ -3859,7 +3846,9 @@ pub fn enumValueFieldIndex(pt: Zcu.PerThread, ty: Type, field_index: u32) Alloca | ... | @@ -3859,7 +3846,9 @@ pub fn enumValueFieldIndex(pt: Zcu.PerThread, ty: Type, field_index: u32) Alloca |
| 3859 | 3846 | ||
| 3860 | pub fn undefValue(pt: Zcu.PerThread, ty: Type) Allocator.Error!Value { | 3847 | pub fn undefValue(pt: Zcu.PerThread, ty: Type) Allocator.Error!Value { |
| 3861 | if (std.debug.runtime_safety) { | 3848 | if (std.debug.runtime_safety) { |
| 3862 | assert(try ty.onePossibleValue(pt) == null); | 3849 | if (try ty.onePossibleValue(pt)) |opv| { |
| 3850 | assert(opv.isUndef(pt.zcu)); | ||
| 3851 | } | ||
| 3863 | } | 3852 | } |
| 3864 | return .fromInterned(try pt.intern(.{ .undef = ty.toIntern() })); | 3853 | return .fromInterned(try pt.intern(.{ .undef = ty.toIntern() })); |
| 3865 | } | 3854 | } |
| ... | @@ -3941,7 +3930,10 @@ pub fn aggregateValue(pt: Zcu.PerThread, ty: Type, elems: []const InternPool.Ind | ... | @@ -3941,7 +3930,10 @@ pub fn aggregateValue(pt: Zcu.PerThread, ty: Type, elems: []const InternPool.Ind |
| 3941 | for (elems) |elem| { | 3930 | for (elems) |elem| { |
| 3942 | if (!Value.fromInterned(elem).isUndef(pt.zcu)) break; | 3931 | if (!Value.fromInterned(elem).isUndef(pt.zcu)) break; |
| 3943 | } else if (elems.len > 0) { | 3932 | } else if (elems.len > 0) { |
| 3944 | return pt.undefValue(ty); // all-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 | return .fromInterned(try pt.intern(.{ .aggregate = .{ | 3938 | return .fromInterned(try pt.intern(.{ .aggregate = .{ |
| 3947 | .ty = ty.toIntern(), | 3939 | .ty = ty.toIntern(), |
| ... | @@ -4096,19 +4088,6 @@ pub fn getExtern(pt: Zcu.PerThread, key: InternPool.Key.Extern) Allocator.Error! | ... | @@ -4096,19 +4088,6 @@ pub fn getExtern(pt: Zcu.PerThread, key: InternPool.Key.Extern) Allocator.Error! |
| 4096 | return result.index; | 4088 | return result.index; |
| 4097 | } | 4089 | } |
| 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 | /// Given a namespace, re-scan its declarations from the type definition if they have not | 4091 | /// Given a namespace, re-scan its declarations from the type definition if they have not |
| 4113 | /// yet been re-scanned on this update. | 4092 | /// yet been re-scanned on this update. |
| 4114 | /// If the type declaration instruction has been lost, returns `error.AnalysisFail`. | 4093 | /// If the type declaration instruction has been lost, returns `error.AnalysisFail`. |
| ... | @@ -4393,7 +4372,7 @@ pub fn resolveTypeForCodegen(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void { | ... | @@ -4393,7 +4372,7 @@ pub fn resolveTypeForCodegen(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void { |
| 4393 | .@"struct" => switch (ip.indexToKey(ty.toIntern())) { | 4372 | .@"struct" => switch (ip.indexToKey(ty.toIntern())) { |
| 4394 | .struct_type => { | 4373 | .struct_type => { |
| 4395 | try pt.ensureTypeLayoutUpToDate(ty); | 4374 | try pt.ensureTypeLayoutUpToDate(ty); |
| 4396 | try pt.ensureTypeInitsUpToDate(ty); | 4375 | try pt.ensureStructDefaultsUpToDate(ty); |
| 4397 | }, | 4376 | }, |
| 4398 | .tuple_type => |tuple| for (0..tuple.types.len) |i| { | 4377 | .tuple_type => |tuple| for (0..tuple.types.len) |i| { |
| 4399 | const field_is_comptime = tuple.values.get(ip)[i] != .none; | 4378 | const field_is_comptime = tuple.values.get(ip)[i] != .none; |
| ... | @@ -4405,7 +4384,7 @@ pub fn resolveTypeForCodegen(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void { | ... | @@ -4405,7 +4384,7 @@ pub fn resolveTypeForCodegen(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void { |
| 4405 | }, | 4384 | }, |
| 4406 | 4385 | ||
| 4407 | .@"union" => try pt.ensureTypeLayoutUpToDate(ty), | 4386 | .@"union" => try pt.ensureTypeLayoutUpToDate(ty), |
| 4408 | .@"enum" => try pt.ensureTypeInitsUpToDate(ty), | 4387 | .@"enum" => try pt.ensureTypeLayoutUpToDate(ty), |
| 4409 | } | 4388 | } |
| 4410 | } | 4389 | } |
| 4411 | pub fn resolveValueTypesForCodegen(pt: Zcu.PerThread, val: Value) Zcu.SemaError!void { | 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,7 +347,6 @@ pub fn generateSymbol( |
| 347 | .void => unreachable, // non-runtime value | 347 | .void => unreachable, // non-runtime value |
| 348 | .null => unreachable, // non-runtime value | 348 | .null => unreachable, // non-runtime value |
| 349 | .@"unreachable" => unreachable, // non-runtime value | 349 | .@"unreachable" => unreachable, // non-runtime value |
| 350 | .empty_tuple => return, | ||
| 351 | .false, .true => try w.writeByte(switch (simple_value) { | 350 | .false, .true => try w.writeByte(switch (simple_value) { |
| 352 | .false => 0, | 351 | .false => 0, |
| 353 | .true => 1, | 352 | .true => 1, |
| ... | @@ -1065,20 +1064,20 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo | ... | @@ -1065,20 +1064,20 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo |
| 1065 | const elem_ty = ty.childType(zcu); | 1064 | const elem_ty = ty.childType(zcu); |
| 1066 | const ptr = ip.indexToKey(val.toIntern()).ptr; | 1065 | const ptr = ip.indexToKey(val.toIntern()).ptr; |
| 1067 | if (ptr.base_addr == .int) return .{ .immediate = ptr.byte_offset }; | 1066 | if (ptr.base_addr == .int) return .{ .immediate = ptr.byte_offset }; |
| 1068 | switch (ptr.base_addr) { | 1067 | if (ptr.byte_offset == 0) switch (ptr.base_addr) { |
| 1069 | .int => unreachable, // handled above | 1068 | .int => unreachable, // handled above |
| 1070 | 1069 | ||
| 1071 | .nav => |nav| if (elem_ty.isFnOrHasRuntimeBits(zcu)) { | 1070 | .nav => |nav| if (elem_ty.isRuntimeFnOrHasRuntimeBits(zcu)) { |
| 1072 | return .{ .lea_nav = nav }; | 1071 | return .{ .lea_nav = nav }; |
| 1073 | } else { | 1072 | } else { |
| 1074 | // Create the 0xaa bit pattern... | 1073 | // Create the 0xaa bit pattern... |
| 1075 | const undef_ptr_bits: u64 = @intCast((@as(u66, 1) << @intCast(target.ptrBitWidth() + 1)) / 3); | 1074 | const undef_ptr_bits: u64 = @intCast((@as(u66, 1) << @intCast(target.ptrBitWidth() + 1)) / 3); |
| 1076 | // ...but align the pointer | 1075 | // ...but align the pointer |
| 1077 | const alignment = pt.navAlignment(nav); | 1076 | const alignment = zcu.navAlignment(nav); |
| 1078 | return .{ .immediate = alignment.forward(undef_ptr_bits) }; | 1077 | return .{ .immediate = alignment.forward(undef_ptr_bits) }; |
| 1079 | }, | 1078 | }, |
| 1080 | 1079 | ||
| 1081 | .uav => |uav| if (elem_ty.isFnOrHasRuntimeBits(zcu)) { | 1080 | .uav => |uav| if (elem_ty.isRuntimeFnOrHasRuntimeBits(zcu)) { |
| 1082 | return .{ .lea_uav = uav }; | 1081 | return .{ .lea_uav = uav }; |
| 1083 | } else { | 1082 | } else { |
| 1084 | // Create the 0xaa bit pattern... | 1083 | // Create the 0xaa bit pattern... |
| ... | @@ -1089,7 +1088,7 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo | ... | @@ -1089,7 +1088,7 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo |
| 1089 | }, | 1088 | }, |
| 1090 | 1089 | ||
| 1091 | else => {}, | 1090 | else => {}, |
| 1092 | } | 1091 | }; |
| 1093 | }, | 1092 | }, |
| 1094 | }, | 1093 | }, |
| 1095 | .int => { | 1094 | .int => { |
src/codegen/aarch64/Select.zig+7-7| ... | @@ -6594,7 +6594,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, | ... | @@ -6594,7 +6594,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, |
| 6594 | if (try isel.hasRepeatedByteRepr(.fromInterned(fill_val))) |fill_byte| | 6594 | if (try isel.hasRepeatedByteRepr(.fromInterned(fill_val))) |fill_byte| |
| 6595 | break :fill_byte .{ .constant = fill_byte }; | 6595 | break :fill_byte .{ .constant = fill_byte }; |
| 6596 | } | 6596 | } |
| 6597 | switch (dst_ty.indexablePtrElem(zcu).abiSize(zcu)) { | 6597 | switch (dst_ty.indexableElem(zcu).abiSize(zcu)) { |
| 6598 | 0 => unreachable, | 6598 | 0 => unreachable, |
| 6599 | 1 => break :fill_byte .{ .value = bin_op.rhs }, | 6599 | 1 => break :fill_byte .{ .value = bin_op.rhs }, |
| 6600 | 2, 4, 8 => |size| { | 6600 | 2, 4, 8 => |size| { |
| ... | @@ -7217,7 +7217,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, | ... | @@ -7217,7 +7217,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, |
| 7217 | const ptr_ra = try ptr_vi.value.defReg(isel) orelse break :unused; | 7217 | const ptr_ra = try ptr_vi.value.defReg(isel) orelse break :unused; |
| 7218 | 7218 | ||
| 7219 | const ty_nav = air.data(air.inst_index).ty_nav; | 7219 | const ty_nav = air.data(air.inst_index).ty_nav; |
| 7220 | if (ZigType.fromInterned(ip.getNav(ty_nav.nav).typeOf(ip)).isFnOrHasRuntimeBits(zcu)) switch (true) { | 7220 | if (ZigType.fromInterned(ip.getNav(ty_nav.nav).typeOf(ip)).isRuntimeFnOrHasRuntimeBits(zcu)) switch (true) { |
| 7221 | false => { | 7221 | false => { |
| 7222 | try isel.nav_relocs.append(gpa, .{ | 7222 | try isel.nav_relocs.append(gpa, .{ |
| 7223 | .nav = ty_nav.nav, | 7223 | .nav = ty_nav.nav, |
| ... | @@ -7240,7 +7240,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, | ... | @@ -7240,7 +7240,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, |
| 7240 | }); | 7240 | }); |
| 7241 | try isel.emit(.adrp(ptr_ra.x(), 0)); | 7241 | try isel.emit(.adrp(ptr_ra.x(), 0)); |
| 7242 | }, | 7242 | }, |
| 7243 | } else try isel.movImmediate(ptr_ra.x(), isel.pt.navAlignment(ty_nav.nav).forward(0xaaaaaaaaaaaaaaaa)); | 7243 | } else try isel.movImmediate(ptr_ra.x(), zcu.navAlignment(ty_nav.nav).forward(0xaaaaaaaaaaaaaaaa)); |
| 7244 | } | 7244 | } |
| 7245 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | 7245 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; |
| 7246 | }, | 7246 | }, |
| ... | @@ -10738,7 +10738,7 @@ pub const Value = struct { | ... | @@ -10738,7 +10738,7 @@ pub const Value = struct { |
| 10738 | } }), | 10738 | } }), |
| 10739 | }), | 10739 | }), |
| 10740 | .simple_value => |simple_value| switch (simple_value) { | 10740 | .simple_value => |simple_value| switch (simple_value) { |
| 10741 | .undefined, .void, .null, .empty_tuple, .@"unreachable" => unreachable, | 10741 | .undefined, .void, .null, .@"unreachable" => unreachable, |
| 10742 | .true => continue :constant_key .{ .int = .{ | 10742 | .true => continue :constant_key .{ .int = .{ |
| 10743 | .ty = .bool_type, | 10743 | .ty = .bool_type, |
| 10744 | .storage = .{ .u64 = 1 }, | 10744 | .storage = .{ .u64 = 1 }, |
| ... | @@ -10931,7 +10931,7 @@ pub const Value = struct { | ... | @@ -10931,7 +10931,7 @@ pub const Value = struct { |
| 10931 | .ptr => |ptr| { | 10931 | .ptr => |ptr| { |
| 10932 | assert(offset == 0 and size == 8); | 10932 | assert(offset == 0 and size == 8); |
| 10933 | break :free switch (ptr.base_addr) { | 10933 | break :free switch (ptr.base_addr) { |
| 10934 | .nav => |nav| if (ZigType.fromInterned(ip.getNav(nav).typeOf(ip)).isFnOrHasRuntimeBits(zcu)) switch (true) { | 10934 | .nav => |nav| if (ZigType.fromInterned(ip.getNav(nav).typeOf(ip)).isRuntimeFnOrHasRuntimeBits(zcu)) switch (true) { |
| 10935 | false => { | 10935 | false => { |
| 10936 | try isel.nav_relocs.append(zcu.gpa, .{ | 10936 | try isel.nav_relocs.append(zcu.gpa, .{ |
| 10937 | .nav = nav, | 10937 | .nav = nav, |
| ... | @@ -10965,9 +10965,9 @@ pub const Value = struct { | ... | @@ -10965,9 +10965,9 @@ pub const Value = struct { |
| 10965 | }, | 10965 | }, |
| 10966 | } else continue :constant_key .{ .int = .{ | 10966 | } else continue :constant_key .{ .int = .{ |
| 10967 | .ty = .usize_type, | 10967 | .ty = .usize_type, |
| 10968 | .storage = .{ .u64 = isel.pt.navAlignment(nav).forward(0xaaaaaaaaaaaaaaaa) }, | 10968 | .storage = .{ .u64 = zcu.navAlignment(nav).forward(0xaaaaaaaaaaaaaaaa) }, |
| 10969 | } }, | 10969 | } }, |
| 10970 | .uav => |uav| if (ZigType.fromInterned(ip.typeOf(uav.val)).isFnOrHasRuntimeBits(zcu)) switch (true) { | 10970 | .uav => |uav| if (ZigType.fromInterned(ip.typeOf(uav.val)).isRuntimeFnOrHasRuntimeBits(zcu)) switch (true) { |
| 10971 | false => { | 10971 | false => { |
| 10972 | try isel.uav_relocs.append(zcu.gpa, .{ | 10972 | try isel.uav_relocs.append(zcu.gpa, .{ |
| 10973 | .uav = uav, | 10973 | .uav = uav, |
src/codegen/c.zig+8-9| ... | @@ -789,7 +789,7 @@ pub const DeclGen = struct { | ... | @@ -789,7 +789,7 @@ pub const DeclGen = struct { |
| 789 | 789 | ||
| 790 | // Render an undefined pointer if we have a pointer to a zero-bit or comptime type. | 790 | // Render an undefined pointer if we have a pointer to a zero-bit or comptime type. |
| 791 | const ptr_ty: Type = .fromInterned(uav.orig_ty); | 791 | const ptr_ty: Type = .fromInterned(uav.orig_ty); |
| 792 | if (ptr_ty.isPtrAtRuntime(zcu) and !uav_ty.isFnOrHasRuntimeBits(zcu)) { | 792 | if (ptr_ty.isPtrAtRuntime(zcu) and !uav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) { |
| 793 | return dg.writeCValue(w, .{ .undef = ptr_ty }); | 793 | return dg.writeCValue(w, .{ .undef = ptr_ty }); |
| 794 | } | 794 | } |
| 795 | 795 | ||
| ... | @@ -862,7 +862,7 @@ pub const DeclGen = struct { | ... | @@ -862,7 +862,7 @@ pub const DeclGen = struct { |
| 862 | // Render an undefined pointer if we have a pointer to a zero-bit or comptime type. | 862 | // Render an undefined pointer if we have a pointer to a zero-bit or comptime type. |
| 863 | const nav_ty: Type = .fromInterned(ip.getNav(owner_nav).typeOf(ip)); | 863 | const nav_ty: Type = .fromInterned(ip.getNav(owner_nav).typeOf(ip)); |
| 864 | const ptr_ty = try pt.navPtrType(owner_nav); | 864 | const ptr_ty = try pt.navPtrType(owner_nav); |
| 865 | if (!nav_ty.isFnOrHasRuntimeBits(zcu)) { | 865 | if (!nav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) { |
| 866 | return dg.writeCValue(w, .{ .undef = ptr_ty }); | 866 | return dg.writeCValue(w, .{ .undef = ptr_ty }); |
| 867 | } | 867 | } |
| 868 | 868 | ||
| ... | @@ -1043,7 +1043,6 @@ pub const DeclGen = struct { | ... | @@ -1043,7 +1043,6 @@ pub const DeclGen = struct { |
| 1043 | .undefined => unreachable, | 1043 | .undefined => unreachable, |
| 1044 | .void => unreachable, | 1044 | .void => unreachable, |
| 1045 | .null => unreachable, | 1045 | .null => unreachable, |
| 1046 | .empty_tuple => unreachable, | ||
| 1047 | .@"unreachable" => unreachable, | 1046 | .@"unreachable" => unreachable, |
| 1048 | 1047 | ||
| 1049 | .false => try w.writeAll("false"), | 1048 | .false => try w.writeAll("false"), |
| ... | @@ -3077,7 +3076,7 @@ pub fn genDecl(o: *Object) Error!void { | ... | @@ -3077,7 +3076,7 @@ pub fn genDecl(o: *Object) Error!void { |
| 3077 | const nav = ip.getNav(o.dg.pass.nav); | 3076 | const nav = ip.getNav(o.dg.pass.nav); |
| 3078 | const nav_ty: Type = .fromInterned(nav.typeOf(ip)); | 3077 | const nav_ty: Type = .fromInterned(nav.typeOf(ip)); |
| 3079 | 3078 | ||
| 3080 | if (!nav_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return; | 3079 | if (!nav_ty.hasRuntimeBits(zcu)) return; |
| 3081 | switch (ip.indexToKey(nav.status.fully_resolved.val)) { | 3080 | switch (ip.indexToKey(nav.status.fully_resolved.val)) { |
| 3082 | .@"extern" => |@"extern"| { | 3081 | .@"extern" => |@"extern"| { |
| 3083 | if (!ip.isFunctionType(nav_ty.toIntern())) return o.dg.renderFwdDecl(o.dg.pass.nav, .{ | 3082 | if (!ip.isFunctionType(nav_ty.toIntern())) return o.dg.renderFwdDecl(o.dg.pass.nav, .{ |
| ... | @@ -3676,7 +3675,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3676,7 +3675,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3676 | 3675 | ||
| 3677 | const inst_ty = f.typeOfIndex(inst); | 3676 | const inst_ty = f.typeOfIndex(inst); |
| 3678 | const ptr_ty = f.typeOf(bin_op.lhs); | 3677 | const ptr_ty = f.typeOf(bin_op.lhs); |
| 3679 | const elem_has_bits = ptr_ty.indexablePtrElem(zcu).hasRuntimeBitsIgnoreComptime(zcu); | 3678 | const elem_has_bits = ptr_ty.indexableElem(zcu).hasRuntimeBitsIgnoreComptime(zcu); |
| 3680 | 3679 | ||
| 3681 | const ptr = try f.resolveInst(bin_op.lhs); | 3680 | const ptr = try f.resolveInst(bin_op.lhs); |
| 3682 | const index = try f.resolveInst(bin_op.rhs); | 3681 | const index = try f.resolveInst(bin_op.rhs); |
| ... | @@ -3792,7 +3791,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3792,7 +3791,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3792 | const zcu = pt.zcu; | 3791 | const zcu = pt.zcu; |
| 3793 | const inst_ty = f.typeOfIndex(inst); | 3792 | const inst_ty = f.typeOfIndex(inst); |
| 3794 | const elem_ty = inst_ty.childType(zcu); | 3793 | const elem_ty = inst_ty.childType(zcu); |
| 3795 | if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return .{ .undef = inst_ty }; | 3794 | if (!elem_ty.hasRuntimeBits(zcu)) return .{ .undef = inst_ty }; |
| 3796 | 3795 | ||
| 3797 | const local = try f.allocLocalValue(.{ | 3796 | const local = try f.allocLocalValue(.{ |
| 3798 | .ctype = try f.ctypeFromType(elem_ty, .complete), | 3797 | .ctype = try f.ctypeFromType(elem_ty, .complete), |
| ... | @@ -3829,7 +3828,7 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3829,7 +3828,7 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3829 | const zcu = pt.zcu; | 3828 | const zcu = pt.zcu; |
| 3830 | const inst_ty = f.typeOfIndex(inst); | 3829 | const inst_ty = f.typeOfIndex(inst); |
| 3831 | const elem_ty = inst_ty.childType(zcu); | 3830 | const elem_ty = inst_ty.childType(zcu); |
| 3832 | if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return .{ .undef = inst_ty }; | 3831 | if (!elem_ty.hasRuntimeBits(zcu)) return .{ .undef = inst_ty }; |
| 3833 | 3832 | ||
| 3834 | const local = try f.allocLocalValue(.{ | 3833 | const local = try f.allocLocalValue(.{ |
| 3835 | .ctype = try f.ctypeFromType(elem_ty, .complete), | 3834 | .ctype = try f.ctypeFromType(elem_ty, .complete), |
| ... | @@ -4502,7 +4501,7 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue { | ... | @@ -4502,7 +4501,7 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue { |
| 4502 | 4501 | ||
| 4503 | const inst_ty = f.typeOfIndex(inst); | 4502 | const inst_ty = f.typeOfIndex(inst); |
| 4504 | const inst_scalar_ty = inst_ty.scalarType(zcu); | 4503 | const inst_scalar_ty = inst_ty.scalarType(zcu); |
| 4505 | const elem_ty = inst_scalar_ty.indexablePtrElem(zcu); | 4504 | const elem_ty = inst_scalar_ty.indexableElem(zcu); |
| 4506 | if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) return f.moveCValue(inst, inst_ty, lhs); | 4505 | if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) return f.moveCValue(inst, inst_ty, lhs); |
| 4507 | const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete); | 4506 | const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete); |
| 4508 | 4507 | ||
| ... | @@ -7037,7 +7036,7 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index, function_paren: []const u8) !CV | ... | @@ -7037,7 +7036,7 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index, function_paren: []const u8) !CV |
| 7037 | try w.writeAll(", "); | 7036 | try w.writeAll(", "); |
| 7038 | try writeArrayLen(f, dest_ptr, dest_ty); | 7037 | try writeArrayLen(f, dest_ptr, dest_ty); |
| 7039 | try w.writeAll(" * sizeof("); | 7038 | try w.writeAll(" * sizeof("); |
| 7040 | try f.renderType(w, dest_ty.indexablePtrElem(zcu)); | 7039 | try f.renderType(w, dest_ty.indexableElem(zcu)); |
| 7041 | try w.writeAll("));"); | 7040 | try w.writeAll("));"); |
| 7042 | try f.object.newline(); | 7041 | try f.object.newline(); |
| 7043 | 7042 |
src/codegen/llvm.zig+7-8| ... | @@ -3725,7 +3725,6 @@ pub const Object = struct { | ... | @@ -3725,7 +3725,6 @@ pub const Object = struct { |
| 3725 | .undefined => unreachable, // non-runtime value | 3725 | .undefined => unreachable, // non-runtime value |
| 3726 | .void => unreachable, // non-runtime value | 3726 | .void => unreachable, // non-runtime value |
| 3727 | .null => unreachable, // non-runtime value | 3727 | .null => unreachable, // non-runtime value |
| 3728 | .empty_tuple => unreachable, // non-runtime value | ||
| 3729 | .@"unreachable" => unreachable, // non-runtime value | 3728 | .@"unreachable" => unreachable, // non-runtime value |
| 3730 | 3729 | ||
| 3731 | .false => .false, | 3730 | .false => .false, |
| ... | @@ -4604,7 +4603,7 @@ pub const NavGen = struct { | ... | @@ -4604,7 +4603,7 @@ pub const NavGen = struct { |
| 4604 | _ = try o.resolveLlvmFunction(pt, owner_nav); | 4603 | _ = try o.resolveLlvmFunction(pt, owner_nav); |
| 4605 | } else { | 4604 | } else { |
| 4606 | const variable_index = try o.resolveGlobalNav(pt, nav_index); | 4605 | const variable_index = try o.resolveGlobalNav(pt, nav_index); |
| 4607 | variable_index.setAlignment(pt.navAlignment(nav_index).toLlvm(), &o.builder); | 4606 | variable_index.setAlignment(zcu.navAlignment(nav_index).toLlvm(), &o.builder); |
| 4608 | if (resolved.@"linksection".toSlice(ip)) |section| | 4607 | if (resolved.@"linksection".toSlice(ip)) |section| |
| 4609 | variable_index.setSection(try o.builder.string(section), &o.builder); | 4608 | variable_index.setSection(try o.builder.string(section), &o.builder); |
| 4610 | if (is_const) variable_index.setMutability(.constant, &o.builder); | 4609 | if (is_const) variable_index.setMutability(.constant, &o.builder); |
| ... | @@ -5953,7 +5952,7 @@ pub const FuncGen = struct { | ... | @@ -5953,7 +5952,7 @@ pub const FuncGen = struct { |
| 5953 | return .none; | 5952 | return .none; |
| 5954 | } | 5953 | } |
| 5955 | 5954 | ||
| 5956 | const have_block_result = inst_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu); | 5955 | const have_block_result = inst_ty.hasRuntimeBits(zcu); |
| 5957 | 5956 | ||
| 5958 | var breaks: BreakList = if (have_block_result) .{ .list = .{} } else .{ .len = 0 }; | 5957 | var breaks: BreakList = if (have_block_result) .{ .list = .{} } else .{ .len = 0 }; |
| 5959 | defer if (have_block_result) breaks.list.deinit(self.gpa); | 5958 | defer if (have_block_result) breaks.list.deinit(self.gpa); |
| ... | @@ -6000,7 +5999,7 @@ pub const FuncGen = struct { | ... | @@ -6000,7 +5999,7 @@ pub const FuncGen = struct { |
| 6000 | 5999 | ||
| 6001 | // Add the values to the lists only if the break provides a value. | 6000 | // Add the values to the lists only if the break provides a value. |
| 6002 | const operand_ty = self.typeOf(branch.operand); | 6001 | const operand_ty = self.typeOf(branch.operand); |
| 6003 | if (operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) { | 6002 | if (operand_ty.hasRuntimeBits(zcu)) { |
| 6004 | const val = try self.resolveInst(branch.operand); | 6003 | const val = try self.resolveInst(branch.operand); |
| 6005 | 6004 | ||
| 6006 | // For the phi node, we need the basic blocks and the values of the | 6005 | // For the phi node, we need the basic blocks and the values of the |
| ... | @@ -9581,7 +9580,7 @@ pub const FuncGen = struct { | ... | @@ -9581,7 +9580,7 @@ pub const FuncGen = struct { |
| 9581 | const zcu = pt.zcu; | 9580 | const zcu = pt.zcu; |
| 9582 | const ptr_ty = self.typeOfIndex(inst); | 9581 | const ptr_ty = self.typeOfIndex(inst); |
| 9583 | const pointee_type = ptr_ty.childType(zcu); | 9582 | const pointee_type = ptr_ty.childType(zcu); |
| 9584 | if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) | 9583 | if (!pointee_type.hasRuntimeBits(zcu)) |
| 9585 | return (try o.lowerPtrToVoid(pt, ptr_ty)).toValue(); | 9584 | return (try o.lowerPtrToVoid(pt, ptr_ty)).toValue(); |
| 9586 | 9585 | ||
| 9587 | const pointee_llvm_ty = try o.lowerType(pt, pointee_type); | 9586 | const pointee_llvm_ty = try o.lowerType(pt, pointee_type); |
| ... | @@ -9595,7 +9594,7 @@ pub const FuncGen = struct { | ... | @@ -9595,7 +9594,7 @@ pub const FuncGen = struct { |
| 9595 | const zcu = pt.zcu; | 9594 | const zcu = pt.zcu; |
| 9596 | const ptr_ty = self.typeOfIndex(inst); | 9595 | const ptr_ty = self.typeOfIndex(inst); |
| 9597 | const ret_ty = ptr_ty.childType(zcu); | 9596 | const ret_ty = ptr_ty.childType(zcu); |
| 9598 | if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) | 9597 | if (!ret_ty.hasRuntimeBits(zcu)) |
| 9599 | return (try o.lowerPtrToVoid(pt, ptr_ty)).toValue(); | 9598 | return (try o.lowerPtrToVoid(pt, ptr_ty)).toValue(); |
| 9600 | if (self.ret_ptr != .none) return self.ret_ptr; | 9599 | if (self.ret_ptr != .none) return self.ret_ptr; |
| 9601 | const ret_llvm_ty = try o.lowerType(pt, ret_ty); | 9600 | const ret_llvm_ty = try o.lowerType(pt, ret_ty); |
| ... | @@ -9897,7 +9896,7 @@ pub const FuncGen = struct { | ... | @@ -9897,7 +9896,7 @@ pub const FuncGen = struct { |
| 9897 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 9896 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 9898 | const ptr_ty = self.typeOf(bin_op.lhs); | 9897 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 9899 | const operand_ty = ptr_ty.childType(zcu); | 9898 | const operand_ty = ptr_ty.childType(zcu); |
| 9900 | if (!operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return .none; | 9899 | if (!operand_ty.hasRuntimeBits(zcu)) return .none; |
| 9901 | const ptr = try self.resolveInst(bin_op.lhs); | 9900 | const ptr = try self.resolveInst(bin_op.lhs); |
| 9902 | var element = try self.resolveInst(bin_op.rhs); | 9901 | var element = try self.resolveInst(bin_op.rhs); |
| 9903 | const llvm_abi_ty = try o.getAtomicAbiType(pt, operand_ty, false); | 9902 | const llvm_abi_ty = try o.getAtomicAbiType(pt, operand_ty, false); |
| ... | @@ -11478,7 +11477,7 @@ pub const FuncGen = struct { | ... | @@ -11478,7 +11477,7 @@ pub const FuncGen = struct { |
| 11478 | const zcu = pt.zcu; | 11477 | const zcu = pt.zcu; |
| 11479 | const info = ptr_ty.ptrInfo(zcu); | 11478 | const info = ptr_ty.ptrInfo(zcu); |
| 11480 | const elem_ty = Type.fromInterned(info.child); | 11479 | const elem_ty = Type.fromInterned(info.child); |
| 11481 | if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) { | 11480 | if (!elem_ty.hasRuntimeBits(zcu)) { |
| 11482 | return; | 11481 | return; |
| 11483 | } | 11482 | } |
| 11484 | const ptr_alignment = ptr_ty.ptrAlignment(zcu).toLlvm(); | 11483 | const ptr_alignment = ptr_ty.ptrAlignment(zcu).toLlvm(); |
src/codegen/riscv64/CodeGen.zig+2-2| ... | @@ -2673,7 +2673,7 @@ fn genBinOp( | ... | @@ -2673,7 +2673,7 @@ fn genBinOp( |
| 2673 | defer func.register_manager.unlockReg(tmp_lock); | 2673 | defer func.register_manager.unlockReg(tmp_lock); |
| 2674 | 2674 | ||
| 2675 | // RISC-V has no immediate mul, so we copy the size to a temporary register | 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 | const elem_size_reg = try func.copyToTmpRegister(Type.u64, .{ .immediate = elem_size }); | 2677 | const elem_size_reg = try func.copyToTmpRegister(Type.u64, .{ .immediate = elem_size }); |
| 2678 | 2678 | ||
| 2679 | try func.genBinOp( | 2679 | try func.genBinOp( |
| ... | @@ -3913,7 +3913,7 @@ fn airPtrElemVal(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3913,7 +3913,7 @@ fn airPtrElemVal(func: *Func, inst: Air.Inst.Index) !void { |
| 3913 | const base_ptr_ty = func.typeOf(bin_op.lhs); | 3913 | const base_ptr_ty = func.typeOf(bin_op.lhs); |
| 3914 | 3914 | ||
| 3915 | const result: MCValue = if (!is_volatile and func.liveness.isUnused(inst)) .unreach else result: { | 3915 | const result: MCValue = if (!is_volatile and func.liveness.isUnused(inst)) .unreach else result: { |
| 3916 | const elem_ty = base_ptr_ty.indexablePtrElem(zcu); | 3916 | const elem_ty = base_ptr_ty.indexableElem(zcu); |
| 3917 | if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none; | 3917 | if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none; |
| 3918 | const base_ptr_mcv = try func.resolveInst(bin_op.lhs); | 3918 | const base_ptr_mcv = try func.resolveInst(bin_op.lhs); |
| 3919 | const base_ptr_lock: ?RegisterLock = switch (base_ptr_mcv) { | 3919 | const base_ptr_lock: ?RegisterLock = switch (base_ptr_mcv) { |
src/codegen/spirv/CodeGen.zig+6-7| ... | @@ -821,7 +821,6 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id { | ... | @@ -821,7 +821,6 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id { |
| 821 | .undefined, | 821 | .undefined, |
| 822 | .void, | 822 | .void, |
| 823 | .null, | 823 | .null, |
| 824 | .empty_tuple, | ||
| 825 | .@"unreachable", | 824 | .@"unreachable", |
| 826 | => unreachable, // non-runtime values | 825 | => unreachable, // non-runtime values |
| 827 | 826 | ||
| ... | @@ -1150,7 +1149,7 @@ fn constantUavRef( | ... | @@ -1150,7 +1149,7 @@ fn constantUavRef( |
| 1150 | } | 1149 | } |
| 1151 | 1150 | ||
| 1152 | // const is_fn_body = decl_ty.zigTypeTag(zcu) == .@"fn"; | 1151 | // const is_fn_body = decl_ty.zigTypeTag(zcu) == .@"fn"; |
| 1153 | if (!uav_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) { | 1152 | if (!uav_ty.hasRuntimeBits(zcu)) { |
| 1154 | // Pointer to nothing - return undefined | 1153 | // Pointer to nothing - return undefined |
| 1155 | return cg.module.constUndef(ty_id); | 1154 | return cg.module.constUndef(ty_id); |
| 1156 | } | 1155 | } |
| ... | @@ -1196,7 +1195,7 @@ fn constantNavRef(cg: *CodeGen, ty: Type, nav_index: InternPool.Nav.Index) !Id { | ... | @@ -1196,7 +1195,7 @@ fn constantNavRef(cg: *CodeGen, ty: Type, nav_index: InternPool.Nav.Index) !Id { |
| 1196 | }, | 1195 | }, |
| 1197 | } | 1196 | } |
| 1198 | 1197 | ||
| 1199 | if (!nav_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) { | 1198 | if (!nav_ty.hasRuntimeBits(zcu)) { |
| 1200 | // Pointer to nothing - return undefined. | 1199 | // Pointer to nothing - return undefined. |
| 1201 | return cg.module.constUndef(ty_id); | 1200 | return cg.module.constUndef(ty_id); |
| 1202 | } | 1201 | } |
| ... | @@ -4381,7 +4380,7 @@ fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -4381,7 +4380,7 @@ fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 4381 | fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id { | 4380 | fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id { |
| 4382 | const zcu = cg.module.zcu; | 4381 | const zcu = cg.module.zcu; |
| 4383 | // Construct new pointer type for the resulting pointer | 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 | const elem_ty_id = try cg.resolveType(elem_ty, .indirect); | 4384 | const elem_ty_id = try cg.resolveType(elem_ty, .indirect); |
| 4386 | const elem_ptr_ty_id = try cg.module.ptrType(elem_ty_id, cg.module.storageClass(ptr_ty.ptrAddressSpace(zcu))); | 4385 | const elem_ptr_ty_id = try cg.module.ptrType(elem_ty_id, cg.module.storageClass(ptr_ty.ptrAddressSpace(zcu))); |
| 4387 | if (ptr_ty.isSinglePointer(zcu)) { | 4386 | if (ptr_ty.isSinglePointer(zcu)) { |
| ... | @@ -5028,7 +5027,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index) | ... | @@ -5028,7 +5027,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index) |
| 5028 | const gpa = cg.module.gpa; | 5027 | const gpa = cg.module.gpa; |
| 5029 | const zcu = cg.module.zcu; | 5028 | const zcu = cg.module.zcu; |
| 5030 | const ty = cg.typeOfIndex(inst); | 5029 | const ty = cg.typeOfIndex(inst); |
| 5031 | const have_block_result = ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu); | 5030 | const have_block_result = ty.hasRuntimeBits(zcu); |
| 5032 | 5031 | ||
| 5033 | const cf = switch (cg.control_flow) { | 5032 | const cf = switch (cg.control_flow) { |
| 5034 | .structured => |*cf| cf, | 5033 | .structured => |*cf| cf, |
| ... | @@ -5166,7 +5165,7 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void { | ... | @@ -5166,7 +5165,7 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void { |
| 5166 | 5165 | ||
| 5167 | switch (cg.control_flow) { | 5166 | switch (cg.control_flow) { |
| 5168 | .structured => |*cf| { | 5167 | .structured => |*cf| { |
| 5169 | if (operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) { | 5168 | if (operand_ty.hasRuntimeBits(zcu)) { |
| 5170 | const operand_id = try cg.resolve(br.operand); | 5169 | const operand_id = try cg.resolve(br.operand); |
| 5171 | const block_result_var_id = cf.block_results.get(br.block_inst).?; | 5170 | const block_result_var_id = cf.block_results.get(br.block_inst).?; |
| 5172 | try cg.store(operand_ty, block_result_var_id, operand_id, .{}); | 5171 | try cg.store(operand_ty, block_result_var_id, operand_id, .{}); |
| ... | @@ -5177,7 +5176,7 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void { | ... | @@ -5177,7 +5176,7 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void { |
| 5177 | }, | 5176 | }, |
| 5178 | .unstructured => |cf| { | 5177 | .unstructured => |cf| { |
| 5179 | const block = cf.blocks.get(br.block_inst).?; | 5178 | const block = cf.blocks.get(br.block_inst).?; |
| 5180 | if (operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) { | 5179 | if (operand_ty.hasRuntimeBits(zcu)) { |
| 5181 | const operand_id = try cg.resolve(br.operand); | 5180 | const operand_id = try cg.resolve(br.operand); |
| 5182 | // block_label should not be undefined here, lest there | 5181 | // block_label should not be undefined here, lest there |
| 5183 | // is a br or br_void in the function's body. | 5182 | // is a br or br_void in the function's body. |
src/codegen/wasm/CodeGen.zig+1-2| ... | @@ -2099,7 +2099,7 @@ fn airRetPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -2099,7 +2099,7 @@ fn airRetPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2099 | const child_type = cg.typeOfIndex(inst).childType(zcu); | 2099 | const child_type = cg.typeOfIndex(inst).childType(zcu); |
| 2100 | 2100 | ||
| 2101 | const result = result: { | 2101 | const result = result: { |
| 2102 | if (!child_type.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) { | 2102 | if (!child_type.hasRuntimeBits(zcu)) { |
| 2103 | break :result try cg.allocStack(Type.usize); // create pointer to void | 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,7 +3161,6 @@ fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue { |
| 3161 | .undefined, | 3161 | .undefined, |
| 3162 | .void, | 3162 | .void, |
| 3163 | .null, | 3163 | .null, |
| 3164 | .empty_tuple, | ||
| 3165 | .@"unreachable", | 3164 | .@"unreachable", |
| 3166 | => unreachable, // non-runtime values | 3165 | => unreachable, // non-runtime values |
| 3167 | .false, .true => return .{ .imm32 = switch (simple_value) { | 3166 | .false, .true => return .{ .imm32 = switch (simple_value) { |
src/codegen/x86_64/CodeGen.zig+7-7| ... | @@ -104121,7 +104121,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -104121,7 +104121,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 104121 | }, | 104121 | }, |
| 104122 | .slice_elem_val, .ptr_elem_val => { | 104122 | .slice_elem_val, .ptr_elem_val => { |
| 104123 | const bin_op = air_datas[@intFromEnum(inst)].bin_op; | 104123 | const bin_op = air_datas[@intFromEnum(inst)].bin_op; |
| 104124 | const res_ty = cg.typeOf(bin_op.lhs).indexablePtrElem(zcu); | 104124 | const res_ty = cg.typeOf(bin_op.lhs).indexableElem(zcu); |
| 104125 | var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs }); | 104125 | var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs }); |
| 104126 | try ops[0].toSlicePtr(cg); | 104126 | try ops[0].toSlicePtr(cg); |
| 104127 | var res: [1]Temp = undefined; | 104127 | var res: [1]Temp = undefined; |
| ... | @@ -188179,8 +188179,8 @@ const Select = struct { | ... | @@ -188179,8 +188179,8 @@ const Select = struct { |
| 188179 | .signed => false, | 188179 | .signed => false, |
| 188180 | .unsigned => size.bitSize(cg.target) >= int_info.bits, | 188180 | .unsigned => size.bitSize(cg.target) >= int_info.bits, |
| 188181 | } else false, | 188181 | } else false, |
| 188182 | .elem_size_is => |size| size == ty.indexablePtrElem(zcu).abiSize(zcu), | 188182 | .elem_size_is => |size| size == ty.indexableElem(zcu).abiSize(zcu), |
| 188183 | .po2_elem_size => std.math.isPowerOfTwo(ty.indexablePtrElem(zcu).abiSize(zcu)), | 188183 | .po2_elem_size => std.math.isPowerOfTwo(ty.indexableElem(zcu).abiSize(zcu)), |
| 188184 | }; | 188184 | }; |
| 188185 | } | 188185 | } |
| 188186 | }; | 188186 | }; |
| ... | @@ -189941,9 +189941,9 @@ const Select = struct { | ... | @@ -189941,9 +189941,9 @@ const Select = struct { |
| 189941 | op.flags.base.ref.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu), | 189941 | op.flags.base.ref.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu), |
| 189942 | @divExact(op.flags.base.size.bitSize(s.cg.target), 8), | 189942 | @divExact(op.flags.base.size.bitSize(s.cg.target), 8), |
| 189943 | )), | 189943 | )), |
| 189944 | .elem_size => @intCast(op.flags.base.ref.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)), | 189944 | .elem_size => @intCast(op.flags.base.ref.typeOf(s).indexableElem(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)), |
| 189945 | .src0_elem_size => @intCast(Select.Operand.Ref.src0.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)), | 189945 | .src0_elem_size => @intCast(Select.Operand.Ref.src0.typeOf(s).indexableElem(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)), |
| 189946 | .dst0_elem_size => @intCast(Select.Operand.Ref.dst0.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)), | 189946 | .dst0_elem_size => @intCast(Select.Operand.Ref.dst0.typeOf(s).indexableElem(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)), |
| 189947 | .src0_elem_size_mul_src1 => @intCast(Select.Operand.Ref.src0.typeOf(s).indexableElem(s.cg.pt.zcu).abiSize(s.cg.pt.zcu) * | 189947 | .src0_elem_size_mul_src1 => @intCast(Select.Operand.Ref.src0.typeOf(s).indexableElem(s.cg.pt.zcu).abiSize(s.cg.pt.zcu) * |
| 189948 | Select.Operand.Ref.src1.valueOf(s).immediate), | 189948 | Select.Operand.Ref.src1.valueOf(s).immediate), |
| 189949 | .vector_index => switch (op.flags.base.ref.typeOf(s).ptrInfo(s.cg.pt.zcu).flags.vector_index) { | 189949 | .vector_index => switch (op.flags.base.ref.typeOf(s).ptrInfo(s.cg.pt.zcu).flags.vector_index) { |
| ... | @@ -189953,7 +189953,7 @@ const Select = struct { | ... | @@ -189953,7 +189953,7 @@ const Select = struct { |
| 189953 | .src1 => @intCast(Select.Operand.Ref.src1.valueOf(s).immediate), | 189953 | .src1 => @intCast(Select.Operand.Ref.src1.valueOf(s).immediate), |
| 189954 | .src1_sub_bit_size => @as(SignedImm, @intCast(Select.Operand.Ref.src1.valueOf(s).immediate)) - | 189954 | .src1_sub_bit_size => @as(SignedImm, @intCast(Select.Operand.Ref.src1.valueOf(s).immediate)) - |
| 189955 | @as(SignedImm, @intCast(s.cg.nonBoolScalarBitSize(op.flags.base.ref.typeOf(s)))), | 189955 | @as(SignedImm, @intCast(s.cg.nonBoolScalarBitSize(op.flags.base.ref.typeOf(s)))), |
| 189956 | .log2_src0_elem_size => @intCast(std.math.log2(Select.Operand.Ref.src0.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu))), | 189956 | .log2_src0_elem_size => @intCast(std.math.log2(Select.Operand.Ref.src0.typeOf(s).indexableElem(s.cg.pt.zcu).abiSize(s.cg.pt.zcu))), |
| 189957 | .elem_mask => @as(u8, std.math.maxInt(u8)) >> @intCast( | 189957 | .elem_mask => @as(u8, std.math.maxInt(u8)) >> @intCast( |
| 189958 | 8 - ((s.cg.unalignedSize(op.flags.base.ref.typeOf(s)) - 1) % | 189958 | 8 - ((s.cg.unalignedSize(op.flags.base.ref.typeOf(s)) - 1) % |
| 189959 | @divExact(op.flags.base.size.bitSize(s.cg.target), 8) + 1 >> | 189959 | @divExact(op.flags.base.size.bitSize(s.cg.target), 8) + 1 >> |
src/link/Coff.zig+1-1| ... | @@ -1552,7 +1552,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde | ... | @@ -1552,7 +1552,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde |
| 1552 | const sec_si = try coff.navSection(zcu, nav.status.fully_resolved); | 1552 | const sec_si = try coff.navSection(zcu, nav.status.fully_resolved); |
| 1553 | try coff.nodes.ensureUnusedCapacity(gpa, 1); | 1553 | try coff.nodes.ensureUnusedCapacity(gpa, 1); |
| 1554 | const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{ | 1554 | const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{ |
| 1555 | .alignment = pt.navAlignment(nav_index).toStdMem(), | 1555 | .alignment = zcu.navAlignment(nav_index).toStdMem(), |
| 1556 | .moved = true, | 1556 | .moved = true, |
| 1557 | }); | 1557 | }); |
| 1558 | coff.nodes.appendAssumeCapacity(.{ .nav = nmi }); | 1558 | coff.nodes.appendAssumeCapacity(.{ .nav = nmi }); |
src/link/Elf/ZigObject.zig+1-1| ... | @@ -1479,7 +1479,7 @@ fn updateTlv( | ... | @@ -1479,7 +1479,7 @@ fn updateTlv( |
| 1479 | 1479 | ||
| 1480 | log.debug("updateTlv {f}({d})", .{ nav.fqn.fmt(ip), nav_index }); | 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 | const sym = self.symbol(sym_index); | 1484 | const sym = self.symbol(sym_index); |
| 1485 | const esym = &self.symtab.items(.elf_sym)[sym.esym_index]; | 1485 | const esym = &self.symtab.items(.elf_sym)[sym.esym_index]; |
src/link/Elf2.zig+1-1| ... | @@ -2906,7 +2906,7 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) | ... | @@ -2906,7 +2906,7 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) |
| 2906 | try elf.nodes.ensureUnusedCapacity(gpa, 1); | 2906 | try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 2907 | const sec_si = elf.navSection(ip, nav.status.fully_resolved); | 2907 | const sec_si = elf.navSection(ip, nav.status.fully_resolved); |
| 2908 | const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{ | 2908 | const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{ |
| 2909 | .alignment = pt.navAlignment(nav_index).toStdMem(), | 2909 | .alignment = zcu.navAlignment(nav_index).toStdMem(), |
| 2910 | .moved = true, | 2910 | .moved = true, |
| 2911 | }); | 2911 | }); |
| 2912 | elf.nodes.appendAssumeCapacity(.{ .nav = nmi }); | 2912 | elf.nodes.appendAssumeCapacity(.{ .nav = nmi }); |
src/link/MachO/ZigObject.zig+4-4| ... | @@ -925,7 +925,7 @@ pub fn updateNav( | ... | @@ -925,7 +925,7 @@ pub fn updateNav( |
| 925 | 925 | ||
| 926 | const sect_index = try self.getNavOutputSection(macho_file, zcu, nav_index, code); | 926 | const sect_index = try self.getNavOutputSection(macho_file, zcu, nav_index, code); |
| 927 | if (isThreadlocal(macho_file, nav_index)) | 927 | if (isThreadlocal(macho_file, nav_index)) |
| 928 | try self.updateTlv(macho_file, pt, nav_index, sym_index, sect_index, code) | 928 | try self.updateTlv(macho_file, zcu, nav_index, sym_index, sect_index, code) |
| 929 | else | 929 | else |
| 930 | try self.updateNavCode(macho_file, pt, nav_index, sym_index, sect_index, code); | 930 | try self.updateNavCode(macho_file, pt, nav_index, sym_index, sect_index, code); |
| 931 | 931 | ||
| ... | @@ -1030,13 +1030,13 @@ fn updateNavCode( | ... | @@ -1030,13 +1030,13 @@ fn updateNavCode( |
| 1030 | fn updateTlv( | 1030 | fn updateTlv( |
| 1031 | self: *ZigObject, | 1031 | self: *ZigObject, |
| 1032 | macho_file: *MachO, | 1032 | macho_file: *MachO, |
| 1033 | pt: Zcu.PerThread, | 1033 | zcu: *Zcu, |
| 1034 | nav_index: InternPool.Nav.Index, | 1034 | nav_index: InternPool.Nav.Index, |
| 1035 | sym_index: Symbol.Index, | 1035 | sym_index: Symbol.Index, |
| 1036 | sect_index: u8, | 1036 | sect_index: u8, |
| 1037 | code: []const u8, | 1037 | code: []const u8, |
| 1038 | ) !void { | 1038 | ) !void { |
| 1039 | const ip = &pt.zcu.intern_pool; | 1039 | const ip = &zcu.intern_pool; |
| 1040 | const nav = ip.getNav(nav_index); | 1040 | const nav = ip.getNav(nav_index); |
| 1041 | 1041 | ||
| 1042 | log.debug("updateTlv {f} (0x{x})", .{ nav.fqn.fmt(ip), nav_index }); | 1042 | log.debug("updateTlv {f} (0x{x})", .{ nav.fqn.fmt(ip), nav_index }); |
| ... | @@ -1045,7 +1045,7 @@ fn updateTlv( | ... | @@ -1045,7 +1045,7 @@ fn updateTlv( |
| 1045 | const init_sym_index = try self.createTlvInitializer( | 1045 | const init_sym_index = try self.createTlvInitializer( |
| 1046 | macho_file, | 1046 | macho_file, |
| 1047 | nav.fqn.toSlice(ip), | 1047 | nav.fqn.toSlice(ip), |
| 1048 | pt.navAlignment(nav_index), | 1048 | zcu.navAlignment(nav_index), |
| 1049 | sect_index, | 1049 | sect_index, |
| 1050 | code, | 1050 | code, |
| 1051 | ); | 1051 | ); |
src/print_value.zig+26-12| ... | @@ -72,8 +72,13 @@ pub fn print( | ... | @@ -72,8 +72,13 @@ pub fn print( |
| 72 | .undef => try writer.writeAll("undefined"), | 72 | .undef => try writer.writeAll("undefined"), |
| 73 | .simple_value => |simple_value| switch (simple_value) { | 73 | .simple_value => |simple_value| switch (simple_value) { |
| 74 | .void => try writer.writeAll("{}"), | 74 | .void => try writer.writeAll("{}"), |
| 75 | .empty_tuple => try writer.writeAll(".{}"), | 75 | |
| 76 | else => try writer.writeAll(@tagName(simple_value)), | 76 | .undefined, |
| 77 | .null, | ||
| 78 | .true, | ||
| 79 | .false, | ||
| 80 | .@"unreachable", | ||
| 81 | => try writer.writeAll(@tagName(simple_value)), | ||
| 77 | }, | 82 | }, |
| 78 | .variable => try writer.writeAll("(variable)"), | 83 | .variable => try writer.writeAll("(variable)"), |
| 79 | .@"extern" => |e| try writer.print("(extern '{f}')", .{e.name.fmt(ip)}), | 84 | .@"extern" => |e| try writer.print("(extern '{f}')", .{e.name.fmt(ip)}), |
| ... | @@ -248,17 +253,26 @@ fn printAggregate( | ... | @@ -248,17 +253,26 @@ fn printAggregate( |
| 248 | const len = ty.arrayLen(zcu); | 253 | const len = ty.arrayLen(zcu); |
| 249 | 254 | ||
| 250 | if (is_ref) try writer.writeByte('&'); | 255 | if (is_ref) try writer.writeByte('&'); |
| 251 | try writer.writeAll(".{ "); | 256 | switch (len) { |
| 252 | 257 | 0 => try writer.writeAll(".{}"), | |
| 253 | const max_len = @min(len, max_aggregate_items); | 258 | 1 => { |
| 254 | for (0..max_len) |i| { | 259 | try writer.writeAll(".{"); |
| 255 | if (i != 0) try writer.writeAll(", "); | 260 | try print(try val.fieldValue(pt, 0), writer, level - 1, pt, opt_sema); |
| 256 | try print(try val.fieldValue(pt, i), writer, level - 1, pt, opt_sema); | 261 | try writer.writeByte('}'); |
| 257 | } | 262 | }, |
| 258 | if (len > max_aggregate_items) { | 263 | else => { |
| 259 | try writer.writeAll(", ..."); | 264 | try writer.writeAll(".{ "); |
| 265 | const max_len = @min(len, max_aggregate_items); | ||
| 266 | for (0..max_len) |i| { | ||
| 267 | if (i != 0) try writer.writeAll(", "); | ||
| 268 | try print(try val.fieldValue(pt, i), writer, level - 1, pt, opt_sema); | ||
| 269 | } | ||
| 270 | if (len > max_aggregate_items) { | ||
| 271 | try writer.writeAll(", ..."); | ||
| 272 | } | ||
| 273 | try writer.writeAll(" }"); | ||
| 274 | }, | ||
| 260 | } | 275 | } |
| 261 | return writer.writeAll(" }"); | ||
| 262 | } | 276 | } |
| 263 | 277 | ||
| 264 | fn printPtr( | 278 | fn printPtr( |
src/print_zir.zig+15-11| ... | @@ -1439,10 +1439,10 @@ const Writer = struct { | ... | @@ -1439,10 +1439,10 @@ const Writer = struct { |
| 1439 | 1439 | ||
| 1440 | try stream.print("{s}, ", .{@tagName(struct_decl.name_strategy)}); | 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 | assert(struct_decl.layout == .@"packed"); | 1443 | assert(struct_decl.layout == .@"packed"); |
| 1444 | try stream.writeAll("packed("); | 1444 | try stream.writeAll("packed("); |
| 1445 | try self.writeInstRef(stream, struct_decl.backing_int_type); | 1445 | try self.writeBracedDecl(stream, backing_int_type_body); |
| 1446 | try stream.writeAll("), "); | 1446 | try stream.writeAll("), "); |
| 1447 | } else { | 1447 | } else { |
| 1448 | try stream.print("{s}, ", .{@tagName(struct_decl.layout)}); | 1448 | try stream.print("{s}, ", .{@tagName(struct_decl.layout)}); |
| ... | @@ -1507,18 +1507,18 @@ const Writer = struct { | ... | @@ -1507,18 +1507,18 @@ const Writer = struct { |
| 1507 | .@"packed" => try stream.writeAll("packed, "), | 1507 | .@"packed" => try stream.writeAll("packed, "), |
| 1508 | .packed_explicit => { | 1508 | .packed_explicit => { |
| 1509 | try stream.writeAll("packed("); | 1509 | try stream.writeAll("packed("); |
| 1510 | try self.writeInstRef(stream, union_decl.arg_type); | 1510 | try self.writeBracedDecl(stream, union_decl.arg_type_body.?); |
| 1511 | try stream.writeAll("), "); | 1511 | try stream.writeAll("), "); |
| 1512 | }, | 1512 | }, |
| 1513 | .tagged_explicit => { | 1513 | .tagged_explicit => { |
| 1514 | try stream.writeAll("auto("); | 1514 | try stream.writeAll("tagged("); |
| 1515 | try self.writeInstRef(stream, union_decl.arg_type); | 1515 | try self.writeBracedDecl(stream, union_decl.arg_type_body.?); |
| 1516 | try stream.writeAll("), "); | 1516 | try stream.writeAll("), "); |
| 1517 | }, | 1517 | }, |
| 1518 | .tagged_enum => try stream.writeAll("auto(enum)"), | 1518 | .tagged_enum => try stream.writeAll("tagged(enum), "), |
| 1519 | .tagged_enum_explicit => { | 1519 | .tagged_enum_explicit => { |
| 1520 | try stream.writeAll("auto(enum("); | 1520 | try stream.writeAll("tagged(enum("); |
| 1521 | try self.writeInstRef(stream, union_decl.arg_type); | 1521 | try self.writeBracedDecl(stream, union_decl.arg_type_body.?); |
| 1522 | try stream.writeAll(")), "); | 1522 | try stream.writeAll(")), "); |
| 1523 | }, | 1523 | }, |
| 1524 | } | 1524 | } |
| ... | @@ -1577,7 +1577,11 @@ const Writer = struct { | ... | @@ -1577,7 +1577,11 @@ const Writer = struct { |
| 1577 | 1577 | ||
| 1578 | try stream.print("{s}, ", .{@tagName(enum_decl.name_strategy)}); | 1578 | try stream.print("{s}, ", .{@tagName(enum_decl.name_strategy)}); |
| 1579 | try self.writeFlag(stream, "nonexhaustive, ", enum_decl.nonexhaustive); | 1579 | try self.writeFlag(stream, "nonexhaustive, ", enum_decl.nonexhaustive); |
| 1580 | try self.writeInstRef(stream, enum_decl.tag_type); | 1580 | if (enum_decl.tag_type_body) |tag_type_body| { |
| 1581 | try stream.writeAll("tag("); | ||
| 1582 | try self.writeBracedDecl(stream, tag_type_body); | ||
| 1583 | try stream.writeAll("), "); | ||
| 1584 | } | ||
| 1581 | 1585 | ||
| 1582 | try self.writeCaptures(stream, enum_decl.captures, enum_decl.capture_names); | 1586 | try self.writeCaptures(stream, enum_decl.captures, enum_decl.capture_names); |
| 1583 | try stream.writeAll(", "); | 1587 | try stream.writeAll(", "); |
| ... | @@ -1585,9 +1589,9 @@ const Writer = struct { | ... | @@ -1585,9 +1589,9 @@ const Writer = struct { |
| 1585 | try stream.writeAll(", "); | 1589 | try stream.writeAll(", "); |
| 1586 | 1590 | ||
| 1587 | if (enum_decl.field_names.len == 0) { | 1591 | if (enum_decl.field_names.len == 0) { |
| 1588 | try stream.writeAll(", {}) "); | 1592 | try stream.writeAll("{}) "); |
| 1589 | } else { | 1593 | } else { |
| 1590 | try stream.writeAll(", {\n"); | 1594 | try stream.writeAll("{\n"); |
| 1591 | self.indent += 2; | 1595 | self.indent += 2; |
| 1592 | 1596 | ||
| 1593 | var it = enum_decl.iterateFields(); | 1597 | var it = enum_decl.iterateFields(); |