authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-28 14:58:20+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-29 10:12:36+03:00
logfdaf9c40d6a351477aacb1af27871f3de12d485e
tree1060d38a06a0889cd89eed6bd0522d487772d37c
parent9e0a930ce3be01923602adbfee13b50842da08b7

stage2: handle tuple init edge cases


7 files changed, 192 insertions(+), 25 deletions(-)

src/AstGen.zig+4-1
...@@ -1349,7 +1349,10 @@ fn arrayInitExpr(...@@ -1349,7 +1349,10 @@ fn arrayInitExpr(
1349 }1349 }
1350 }1350 }
1351 const array_type_inst = try typeExpr(gz, scope, array_init.ast.type_expr);1351 const array_type_inst = try typeExpr(gz, scope, array_init.ast.type_expr);
1352 _ = try gz.addUnNode(.validate_array_init_ty, array_type_inst, array_init.ast.type_expr);1352 _ = try gz.addPlNode(.validate_array_init_ty, node, Zir.Inst.ArrayInit{
1353 .ty = array_type_inst,
1354 .init_count = @intCast(u32, array_init.ast.elements.len),
1355 });
1353 break :inst .{1356 break :inst .{
1354 .array = array_type_inst,1357 .array = array_type_inst,
1355 .elem = .none,1358 .elem = .none,
src/Module.zig+19
...@@ -2728,6 +2728,21 @@ pub const SrcLoc = struct {...@@ -2728,6 +2728,21 @@ pub const SrcLoc = struct {
2728 };2728 };
2729 return nodeToSpan(tree, full.ast.value_expr);2729 return nodeToSpan(tree, full.ast.value_expr);
2730 },2730 },
2731 .node_offset_init_ty => |node_off| {
2732 const tree = try src_loc.file_scope.getTree(gpa);
2733 const node_tags = tree.nodes.items(.tag);
2734 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
2735
2736 var buf: [2]Ast.Node.Index = undefined;
2737 const full: Ast.full.ArrayInit = switch (node_tags[parent_node]) {
2738 .array_init_one, .array_init_one_comma => tree.arrayInitOne(buf[0..1], parent_node),
2739 .array_init_dot_two, .array_init_dot_two_comma => tree.arrayInitDotTwo(&buf, parent_node),
2740 .array_init_dot, .array_init_dot_comma => tree.arrayInitDot(parent_node),
2741 .array_init, .array_init_comma => tree.arrayInit(parent_node),
2742 else => unreachable,
2743 };
2744 return nodeToSpan(tree, full.ast.type_expr);
2745 },
2731 }2746 }
2732 }2747 }
27332748
...@@ -3048,6 +3063,9 @@ pub const LazySrcLoc = union(enum) {...@@ -3048,6 +3063,9 @@ pub const LazySrcLoc = union(enum) {
3048 /// The source location points to the default value of a field.3063 /// The source location points to the default value of a field.
3049 /// The Decl is determined contextually.3064 /// The Decl is determined contextually.
3050 node_offset_field_default: i32,3065 node_offset_field_default: i32,
3066 /// The source location points to the type of an array or struct initializer.
3067 /// The Decl is determined contextually.
3068 node_offset_init_ty: i32,
30513069
3052 pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease;3070 pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease;
30533071
...@@ -3126,6 +3144,7 @@ pub const LazySrcLoc = union(enum) {...@@ -3126,6 +3144,7 @@ pub const LazySrcLoc = union(enum) {
3126 .node_offset_ptr_hostsize,3144 .node_offset_ptr_hostsize,
3127 .node_offset_container_tag,3145 .node_offset_container_tag,
3128 .node_offset_field_default,3146 .node_offset_field_default,
3147 .node_offset_init_ty,
3129 => .{3148 => .{
3130 .file_scope = decl.getFileScope(),3149 .file_scope = decl.getFileScope(),
3131 .parent_decl_node = decl.src_node,3150 .parent_decl_node = decl.src_node,
src/Sema.zig+105-21
...@@ -3493,19 +3493,43 @@ fn validateArrayInitTy(...@@ -3493,19 +3493,43 @@ fn validateArrayInitTy(
3493 block: *Block,3493 block: *Block,
3494 inst: Zir.Inst.Index,3494 inst: Zir.Inst.Index,
3495) CompileError!void {3495) CompileError!void {
3496 const inst_data = sema.code.instructions.items(.data)[inst].un_node;3496 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
3497 const src = inst_data.src();3497 const src = inst_data.src();
3498 const ty = try sema.resolveType(block, src, inst_data.operand);3498 const ty_src: LazySrcLoc = .{ .node_offset_init_ty = inst_data.src_node };
3499 const extra = sema.code.extraData(Zir.Inst.ArrayInit, inst_data.payload_index).data;
3500 const ty = try sema.resolveType(block, ty_src, extra.ty);
34993501
3500 switch (ty.zigTypeTag()) {3502 switch (ty.zigTypeTag()) {
3501 .Array, .Vector => return,3503 .Array => {
3504 const array_len = ty.arrayLen();
3505 if (extra.init_count != array_len) {
3506 return sema.fail(block, src, "expected {d} array elements; found {d}", .{
3507 array_len, extra.init_count,
3508 });
3509 }
3510 return;
3511 },
3512 .Vector => {
3513 const array_len = ty.arrayLen();
3514 if (extra.init_count != array_len) {
3515 return sema.fail(block, src, "expected {d} vector elements; found {d}", .{
3516 array_len, extra.init_count,
3517 });
3518 }
3519 return;
3520 },
3502 .Struct => if (ty.isTuple()) {3521 .Struct => if (ty.isTuple()) {
3503 // TODO validate element count3522 const array_len = ty.arrayLen();
3523 if (extra.init_count > array_len) {
3524 return sema.fail(block, src, "expected at most {d} tuple fields; found {d}", .{
3525 array_len, extra.init_count,
3526 });
3527 }
3504 return;3528 return;
3505 },3529 },
3506 else => {},3530 else => {},
3507 }3531 }
3508 return sema.failWithArrayInitNotSupported(block, src, ty);3532 return sema.failWithArrayInitNotSupported(block, ty_src, ty);
3509}3533}
35103534
3511fn validateStructInitTy(3535fn validateStructInitTy(
...@@ -3741,6 +3765,15 @@ fn validateStructInit(...@@ -3741,6 +3765,15 @@ fn validateStructInit(
37413765
3742 const default_val = struct_ty.structFieldDefaultValue(i);3766 const default_val = struct_ty.structFieldDefaultValue(i);
3743 if (default_val.tag() == .unreachable_value) {3767 if (default_val.tag() == .unreachable_value) {
3768 if (struct_ty.isTuple()) {
3769 const template = "missing tuple field with index {d}";
3770 if (root_msg) |msg| {
3771 try sema.errNote(block, init_src, msg, template, .{i});
3772 } else {
3773 root_msg = try sema.errMsg(block, init_src, template, .{i});
3774 }
3775 continue;
3776 }
3744 const field_name = struct_ty.structFieldName(i);3777 const field_name = struct_ty.structFieldName(i);
3745 const template = "missing struct field: {s}";3778 const template = "missing struct field: {s}";
3746 const args = .{field_name};3779 const args = .{field_name};
...@@ -3753,7 +3786,10 @@ fn validateStructInit(...@@ -3753,7 +3786,10 @@ fn validateStructInit(
3753 }3786 }
37543787
3755 const field_src = init_src; // TODO better source location3788 const field_src = init_src; // TODO better source location
3756 const default_field_ptr = try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true);3789 const default_field_ptr = if (struct_ty.isTuple())
3790 try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(u32, i), true)
3791 else
3792 try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true);
3757 const field_ty = sema.typeOf(default_field_ptr).childType();3793 const field_ty = sema.typeOf(default_field_ptr).childType();
3758 const init = try sema.addConstant(field_ty, default_val);3794 const init = try sema.addConstant(field_ty, default_val);
3759 try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);3795 try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);
...@@ -3868,6 +3904,15 @@ fn validateStructInit(...@@ -3868,6 +3904,15 @@ fn validateStructInit(
38683904
3869 const default_val = struct_ty.structFieldDefaultValue(i);3905 const default_val = struct_ty.structFieldDefaultValue(i);
3870 if (default_val.tag() == .unreachable_value) {3906 if (default_val.tag() == .unreachable_value) {
3907 if (struct_ty.isTuple()) {
3908 const template = "missing tuple field with index {d}";
3909 if (root_msg) |msg| {
3910 try sema.errNote(block, init_src, msg, template, .{i});
3911 } else {
3912 root_msg = try sema.errMsg(block, init_src, template, .{i});
3913 }
3914 continue;
3915 }
3871 const field_name = struct_ty.structFieldName(i);3916 const field_name = struct_ty.structFieldName(i);
3872 const template = "missing struct field: {s}";3917 const template = "missing struct field: {s}";
3873 const args = .{field_name};3918 const args = .{field_name};
...@@ -3911,7 +3956,10 @@ fn validateStructInit(...@@ -3911,7 +3956,10 @@ fn validateStructInit(
3911 if (field_ptr != 0) continue;3956 if (field_ptr != 0) continue;
39123957
3913 const field_src = init_src; // TODO better source location3958 const field_src = init_src; // TODO better source location
3914 const default_field_ptr = try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true);3959 const default_field_ptr = if (struct_ty.isTuple())
3960 try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(u32, i), true)
3961 else
3962 try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true);
3915 const field_ty = sema.typeOf(default_field_ptr).childType();3963 const field_ty = sema.typeOf(default_field_ptr).childType();
3916 const init = try sema.addConstant(field_ty, field_values[i]);3964 const init = try sema.addConstant(field_ty, field_values[i]);
3917 try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);3965 try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);
...@@ -3934,15 +3982,24 @@ fn zirValidateArrayInit(...@@ -3934,15 +3982,24 @@ fn zirValidateArrayInit(
3934 const array_ty = sema.typeOf(array_ptr).childType();3982 const array_ty = sema.typeOf(array_ptr).childType();
3935 const array_len = array_ty.arrayLen();3983 const array_len = array_ty.arrayLen();
39363984
3937 if (instrs.len != array_len) {3985 if (instrs.len != array_len and array_ty.isTuple()) {
3938 if (array_ty.zigTypeTag() == .Array) {3986 const struct_obj = array_ty.castTag(.tuple).?.data;
3939 return sema.fail(block, init_src, "expected {d} array elements; found {d}", .{3987 var root_msg: ?*Module.ErrorMsg = null;
3940 array_len, instrs.len,3988 for (struct_obj.values) |default_val, i| {
3941 });3989 if (i < instrs.len) continue;
3942 } else {3990
3943 return sema.fail(block, init_src, "expected {d} vector elements; found {d}", .{3991 if (default_val.tag() == .unreachable_value) {
3944 array_len, instrs.len,3992 const template = "missing tuple field with index {d}";
3945 });3993 if (root_msg) |msg| {
3994 try sema.errNote(block, init_src, msg, template, .{i});
3995 } else {
3996 root_msg = try sema.errMsg(block, init_src, template, .{i});
3997 }
3998 }
3999 }
4000
4001 if (root_msg) |msg| {
4002 return sema.failWithOwnedErrorMsg(block, msg);
3946 }4003 }
3947 }4004 }
39484005
...@@ -3995,10 +4052,17 @@ fn zirValidateArrayInit(...@@ -3995,10 +4052,17 @@ fn zirValidateArrayInit(
3995 }4052 }
3996 first_block_index = @minimum(first_block_index, block_index);4053 first_block_index = @minimum(first_block_index, block_index);
39974054
3998 // Array has one possible value, so value is always comptime-known4055 if (array_ty.isTuple()) {
3999 if (opt_opv) |opv| {4056 if (array_ty.structFieldValueComptime(i)) |opv| {
4000 element_vals[i] = opv;4057 element_vals[i] = opv;
4001 continue;4058 continue;
4059 }
4060 } else {
4061 // Array has one possible value, so value is always comptime-known
4062 if (opt_opv) |opv| {
4063 element_vals[i] = opv;
4064 continue;
4065 }
4002 }4066 }
40034067
4004 // If the next instructon is a store with a comptime operand, this element4068 // If the next instructon is a store with a comptime operand, this element
...@@ -14710,6 +14774,22 @@ fn finishStructInit(...@@ -14710,6 +14774,22 @@ fn finishStructInit(
14710 field_inits[i] = try sema.addConstant(struct_obj.types[i], default_val);14774 field_inits[i] = try sema.addConstant(struct_obj.types[i], default_val);
14711 }14775 }
14712 }14776 }
14777 } else if (struct_ty.isTuple()) {
14778 const struct_obj = struct_ty.castTag(.tuple).?.data;
14779 for (struct_obj.values) |default_val, i| {
14780 if (field_inits[i] != .none) continue;
14781
14782 if (default_val.tag() == .unreachable_value) {
14783 const template = "missing tuple field with index {d}";
14784 if (root_msg) |msg| {
14785 try sema.errNote(block, init_src, msg, template, .{i});
14786 } else {
14787 root_msg = try sema.errMsg(block, init_src, template, .{i});
14788 }
14789 } else {
14790 field_inits[i] = try sema.addConstant(struct_obj.types[i], default_val);
14791 }
14792 }
14713 } else {14793 } else {
14714 const struct_obj = struct_ty.castTag(.@"struct").?.data;14794 const struct_obj = struct_ty.castTag(.@"struct").?.data;
14715 for (struct_obj.fields.values()) |field, i| {14795 for (struct_obj.fields.values()) |field, i| {
...@@ -20255,7 +20335,7 @@ fn tupleFieldVal(...@@ -20255,7 +20335,7 @@ fn tupleFieldVal(
20255 return tupleFieldValByIndex(sema, block, src, tuple_byval, field_index, tuple_ty);20335 return tupleFieldValByIndex(sema, block, src, tuple_byval, field_index, tuple_ty);
20256}20336}
2025720337
20258/// Don't forget to check for "len" before calling this.20338/// Asserts that `field_name` is not "len".
20259fn tupleFieldIndex(20339fn tupleFieldIndex(
20260 sema: *Sema,20340 sema: *Sema,
20261 block: *Block,20341 block: *Block,
...@@ -20263,8 +20343,12 @@ fn tupleFieldIndex(...@@ -20263,8 +20343,12 @@ fn tupleFieldIndex(
20263 field_name: []const u8,20343 field_name: []const u8,
20264 field_name_src: LazySrcLoc,20344 field_name_src: LazySrcLoc,
20265) CompileError!u32 {20345) CompileError!u32 {
20346 assert(!std.mem.eql(u8, field_name, "len"));
20266 if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| {20347 if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| {
20267 if (field_index < tuple_ty.structFieldCount()) return field_index;20348 if (field_index < tuple_ty.structFieldCount()) return field_index;
20349 return sema.fail(block, field_name_src, "index '{s}' out of bounds of tuple '{}'", .{
20350 field_name, tuple_ty.fmt(sema.mod),
20351 });
20268 } else |_| {}20352 } else |_| {}
2026920353
20270 return sema.fail(block, field_name_src, "no field named '{s}' in tuple '{}'", .{20354 return sema.fail(block, field_name_src, "no field named '{s}' in tuple '{}'", .{
src/Zir.zig+6-1
...@@ -1709,7 +1709,7 @@ pub const Inst = struct {...@@ -1709,7 +1709,7 @@ pub const Inst = struct {
1709 .switch_capture_multi_ref = .switch_capture,1709 .switch_capture_multi_ref = .switch_capture,
1710 .array_base_ptr = .un_node,1710 .array_base_ptr = .un_node,
1711 .field_base_ptr = .un_node,1711 .field_base_ptr = .un_node,
1712 .validate_array_init_ty = .un_node,1712 .validate_array_init_ty = .pl_node,
1713 .validate_struct_init_ty = .un_node,1713 .validate_struct_init_ty = .un_node,
1714 .validate_struct_init = .pl_node,1714 .validate_struct_init = .pl_node,
1715 .validate_struct_init_comptime = .pl_node,1715 .validate_struct_init_comptime = .pl_node,
...@@ -3543,6 +3543,11 @@ pub const Inst = struct {...@@ -3543,6 +3543,11 @@ pub const Inst = struct {
3543 line: u32,3543 line: u32,
3544 column: u32,3544 column: u32,
3545 };3545 };
3546
3547 pub const ArrayInit = struct {
3548 ty: Ref,
3549 init_count: u32,
3550 };
3546};3551};
35473552
3548pub const SpecialProng = enum { none, @"else", under };3553pub const SpecialProng = enum { none, @"else", under };
src/print_zir.zig+13-1
...@@ -229,7 +229,6 @@ const Writer = struct {...@@ -229,7 +229,6 @@ const Writer = struct {
229 .switch_cond_ref,229 .switch_cond_ref,
230 .array_base_ptr,230 .array_base_ptr,
231 .field_base_ptr,231 .field_base_ptr,
232 .validate_array_init_ty,
233 .validate_struct_init_ty,232 .validate_struct_init_ty,
234 .make_ptr_const,233 .make_ptr_const,
235 .validate_deref,234 .validate_deref,
...@@ -246,6 +245,7 @@ const Writer = struct {...@@ -246,6 +245,7 @@ const Writer = struct {
246 .bool_br_or,245 .bool_br_or,
247 => try self.writeBoolBr(stream, inst),246 => try self.writeBoolBr(stream, inst),
248247
248 .validate_array_init_ty => try self.writeValidateArrayInitTy(stream, inst),
249 .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst),249 .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst),
250 .param_type => try self.writeParamType(stream, inst),250 .param_type => try self.writeParamType(stream, inst),
251 .ptr_type => try self.writePtrType(stream, inst),251 .ptr_type => try self.writePtrType(stream, inst),
...@@ -577,6 +577,18 @@ const Writer = struct {...@@ -577,6 +577,18 @@ const Writer = struct {
577 try self.writeSrc(stream, inst_data.src());577 try self.writeSrc(stream, inst_data.src());
578 }578 }
579579
580 fn writeValidateArrayInitTy(
581 self: *Writer,
582 stream: anytype,
583 inst: Zir.Inst.Index,
584 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
585 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
586 const extra = self.code.extraData(Zir.Inst.ArrayInit, inst_data.payload_index).data;
587 try self.writeInstRef(stream, extra.ty);
588 try stream.print(", {d}) ", .{extra.init_count});
589 try self.writeSrc(stream, inst_data.src());
590 }
591
580 fn writeArrayTypeSentinel(592 fn writeArrayTypeSentinel(
581 self: *Writer,593 self: *Writer,
582 stream: anytype,594 stream: anytype,
test/cases/compile_errors/tuple_init_edge_cases.zig created+44
...@@ -0,0 +1,44 @@
1pub export fn entry1() void {
2 const T = @TypeOf(.{ 123, 3 });
3 var b = T{ .@"1" = 3 }; _ = b;
4 var c = T{ 123, 3 }; _ = c;
5 var d = T{}; _ = d;
6}
7pub export fn entry2() void {
8 var a: u32 = 2;
9 const T = @TypeOf(.{ 123, a });
10 var b = T{ .@"1" = 3 }; _ = b;
11 var c = T{ 123, 3 }; _ = c;
12 var d = T{}; _ = d;
13}
14pub export fn entry3() void {
15 var a: u32 = 2;
16 const T = @TypeOf(.{ 123, a });
17 var b = T{ .@"0" = 123 }; _ = b;
18}
19comptime {
20 var a: u32 = 2;
21 const T = @TypeOf(.{ 123, a });
22 var b = T{ .@"0" = 123 }; _ = b;
23 var c = T{ 123, 2 }; _ = c;
24 var d = T{}; _ = d;
25}
26pub export fn entry4() void {
27 var a: u32 = 2;
28 const T = @TypeOf(.{ 123, a });
29 var b = T{ 123, 4, 5 }; _ = b;
30}
31pub export fn entry5() void {
32 var a: u32 = 2;
33 const T = @TypeOf(.{ 123, a });
34 var b = T{ .@"0" = 123, .@"2" = 123, .@"1" = 123 }; _ = b;
35}
36
37// error
38// backend=stage2
39// target=native
40//
41// :12:14: error: missing tuple field with index 1
42// :17:14: error: missing tuple field with index 1
43// :29:14: error: expected at most 2 tuple fields; found 3
44// :34:30: error: index '2' out of bounds of tuple 'tuple{comptime comptime_int = 123, u32}'
test/cases/compile_errors/wrong_size_to_an_array_literal.zig+1-1
...@@ -7,4 +7,4 @@ comptime {...@@ -7,4 +7,4 @@ comptime {
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :2:31: error: index 2 outside array of length 210// :2:24: error: expected 2 array elements; found 3