| ... | @@ -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); |
| 3499 | | 3501 | |
| 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 count | 3522 | 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 | } |
| 3510 | | 3534 | |
| 3511 | fn validateStructInitTy( | 3535 | fn validateStructInitTy( |
| ... | @@ -3741,6 +3765,15 @@ fn validateStructInit( | ... | @@ -3741,6 +3765,15 @@ fn validateStructInit( |
| 3741 | | 3765 | |
| 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 | } |
| 3754 | | 3787 | |
| 3755 | const field_src = init_src; // TODO better source location | 3788 | 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( |
| 3868 | | 3904 | |
| 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; |
| 3912 | | 3957 | |
| 3913 | const field_src = init_src; // TODO better source location | 3958 | 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(); |
| 3936 | | 3984 | |
| 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 | } |
| 3948 | | 4005 | |
| ... | @@ -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); |
| 3997 | | 4054 | |
| 3998 | // Array has one possible value, so value is always comptime-known | 4055 | 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 | } |
| 4003 | | 4067 | |
| 4004 | // If the next instructon is a store with a comptime operand, this element | 4068 | // 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 | } |
| 20257 | | 20337 | |
| 20258 | /// Don't forget to check for "len" before calling this. | 20338 | /// Asserts that `field_name` is not "len". |
| 20259 | fn tupleFieldIndex( | 20339 | fn 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 |_| {} |
| 20269 | | 20353 | |
| 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 '{}'", .{ |