authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-09 18:30:07+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-07-09 18:30:07+03:00
log3f11d1d56d9747de974b00eab1c880bea7972c01
tree7fb48132677490336cafff1875797dee13c44c43
parent13d58258a8d24136016e01e02ea84966d5fc66c3
parent5b36b0ed0c6d9f6dbe7ec7261cef7802283eaa82
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #12050 from topolarity/anon-struct-init

stage2: Support initializing anonymous struct type

4 files changed, 247 insertions(+), 183 deletions(-)

src/Sema.zig+170-182
...@@ -3326,7 +3326,7 @@ fn zirValidateStructInit(...@@ -3326,7 +3326,7 @@ fn zirValidateStructInit(
3326 switch (agg_ty.zigTypeTag()) {3326 switch (agg_ty.zigTypeTag()) {
3327 .Struct => return sema.validateStructInit(3327 .Struct => return sema.validateStructInit(
3328 block,3328 block,
3329 agg_ty.castTag(.@"struct").?.data,3329 agg_ty,
3330 init_src,3330 init_src,
3331 instrs,3331 instrs,
3332 is_comptime,3332 is_comptime,
...@@ -3470,7 +3470,7 @@ fn validateUnionInit(...@@ -3470,7 +3470,7 @@ fn validateUnionInit(
3470fn validateStructInit(3470fn validateStructInit(
3471 sema: *Sema,3471 sema: *Sema,
3472 block: *Block,3472 block: *Block,
3473 struct_obj: *Module.Struct,3473 struct_ty: Type,
3474 init_src: LazySrcLoc,3474 init_src: LazySrcLoc,
3475 instrs: []const Zir.Inst.Index,3475 instrs: []const Zir.Inst.Index,
3476 is_comptime: bool,3476 is_comptime: bool,
...@@ -3478,7 +3478,7 @@ fn validateStructInit(...@@ -3478,7 +3478,7 @@ fn validateStructInit(
3478 const gpa = sema.gpa;3478 const gpa = sema.gpa;
34793479
3480 // Maps field index to field_ptr index of where it was already initialized.3480 // Maps field index to field_ptr index of where it was already initialized.
3481 const found_fields = try gpa.alloc(Zir.Inst.Index, struct_obj.fields.count());3481 const found_fields = try gpa.alloc(Zir.Inst.Index, struct_ty.structFieldCount());
3482 defer gpa.free(found_fields);3482 defer gpa.free(found_fields);
3483 mem.set(Zir.Inst.Index, found_fields, 0);3483 mem.set(Zir.Inst.Index, found_fields, 0);
34843484
...@@ -3490,8 +3490,7 @@ fn validateStructInit(...@@ -3490,8 +3490,7 @@ fn validateStructInit(
3490 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;3490 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
3491 struct_ptr_zir_ref = field_ptr_extra.lhs;3491 struct_ptr_zir_ref = field_ptr_extra.lhs;
3492 const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start);3492 const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start);
3493 const field_index = struct_obj.fields.getIndex(field_name) orelse3493 const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src);
3494 return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);
3495 if (found_fields[field_index] != 0) {3494 if (found_fields[field_index] != 0) {
3496 const other_field_ptr = found_fields[field_index];3495 const other_field_ptr = found_fields[field_index];
3497 const other_field_ptr_data = sema.code.instructions.items(.data)[other_field_ptr].pl_node;3496 const other_field_ptr_data = sema.code.instructions.items(.data)[other_field_ptr].pl_node;
...@@ -3509,10 +3508,7 @@ fn validateStructInit(...@@ -3509,10 +3508,7 @@ fn validateStructInit(
35093508
3510 var root_msg: ?*Module.ErrorMsg = null;3509 var root_msg: ?*Module.ErrorMsg = null;
35113510
3512 const fields = struct_obj.fields.values();
3513 const struct_ptr = try sema.resolveInst(struct_ptr_zir_ref);3511 const struct_ptr = try sema.resolveInst(struct_ptr_zir_ref);
3514 const struct_ty = sema.typeOf(struct_ptr).childType();
3515
3516 if ((is_comptime or block.is_comptime) and3512 if ((is_comptime or block.is_comptime) and
3517 (try sema.resolveDefinedValue(block, init_src, struct_ptr)) != null)3513 (try sema.resolveDefinedValue(block, init_src, struct_ptr)) != null)
3518 {3514 {
...@@ -3522,10 +3518,9 @@ fn validateStructInit(...@@ -3522,10 +3518,9 @@ fn validateStructInit(
3522 for (found_fields) |field_ptr, i| {3518 for (found_fields) |field_ptr, i| {
3523 if (field_ptr != 0) continue;3519 if (field_ptr != 0) continue;
35243520
3525 const field = fields[i];3521 const default_val = struct_ty.structFieldDefaultValue(i);
3526 const field_name = struct_obj.fields.keys()[i];3522 if (default_val.tag() == .unreachable_value) {
35273523 const field_name = struct_ty.structFieldName(i);
3528 if (field.default_val.tag() == .unreachable_value) {
3529 const template = "missing struct field: {s}";3524 const template = "missing struct field: {s}";
3530 const args = .{field_name};3525 const args = .{field_name};
3531 if (root_msg) |msg| {3526 if (root_msg) |msg| {
...@@ -3536,22 +3531,25 @@ fn validateStructInit(...@@ -3536,22 +3531,25 @@ fn validateStructInit(
3536 continue;3531 continue;
3537 }3532 }
35383533
3539 const default_field_ptr = try sema.structFieldPtr(block, init_src, struct_ptr, field_name, init_src, struct_ty);
3540 const init = try sema.addConstant(field.ty, field.default_val);
3541 const field_src = init_src; // TODO better source location3534 const field_src = init_src; // TODO better source location
3535 const default_field_ptr = try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty);
3536 const field_ty = sema.typeOf(default_field_ptr).childType();
3537 const init = try sema.addConstant(field_ty, default_val);
3542 try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);3538 try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);
3543 }3539 }
35443540
3545 if (root_msg) |msg| {3541 if (root_msg) |msg| {
3546 const mod = sema.mod;3542 if (struct_ty.castTag(.@"struct")) |struct_obj| {
3547 const fqn = try struct_obj.getFullyQualifiedName(mod);3543 const mod = sema.mod;
3548 defer gpa.free(fqn);3544 const fqn = try struct_obj.data.getFullyQualifiedName(mod);
3549 try mod.errNoteNonLazy(3545 defer gpa.free(fqn);
3550 struct_obj.srcLoc(mod),3546 try mod.errNoteNonLazy(
3551 msg,3547 struct_obj.data.srcLoc(mod),
3552 "struct '{s}' declared here",3548 msg,
3553 .{fqn},3549 "struct '{s}' declared here",
3554 );3550 .{fqn},
3551 );
3552 }
3555 return sema.failWithOwnedErrorMsg(block, msg);3553 return sema.failWithOwnedErrorMsg(block, msg);
3556 }3554 }
35573555
...@@ -3566,17 +3564,16 @@ fn validateStructInit(...@@ -3566,17 +3564,16 @@ fn validateStructInit(
35663564
3567 // We collect the comptime field values in case the struct initialization3565 // We collect the comptime field values in case the struct initialization
3568 // ends up being comptime-known.3566 // ends up being comptime-known.
3569 const field_values = try sema.arena.alloc(Value, fields.len);3567 const field_values = try sema.arena.alloc(Value, struct_ty.structFieldCount());
35703568
3571 field: for (found_fields) |field_ptr, i| {3569 field: for (found_fields) |field_ptr, i| {
3572 const field = fields[i];
3573
3574 if (field_ptr != 0) {3570 if (field_ptr != 0) {
3575 const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node;3571 const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node;
3576 const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_ptr_data.src_node };3572 const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_ptr_data.src_node };
35773573
3578 // Determine whether the value stored to this pointer is comptime-known.3574 // Determine whether the value stored to this pointer is comptime-known.
3579 if (try sema.typeHasOnePossibleValue(block, field_src, field.ty)) |opv| {3575 const field_ty = struct_ty.structFieldType(i);
3576 if (try sema.typeHasOnePossibleValue(block, field_src, field_ty)) |opv| {
3580 field_values[i] = opv;3577 field_values[i] = opv;
3581 continue;3578 continue;
3582 }3579 }
...@@ -3648,9 +3645,9 @@ fn validateStructInit(...@@ -3648,9 +3645,9 @@ fn validateStructInit(
3648 continue :field;3645 continue :field;
3649 }3646 }
36503647
3651 const field_name = struct_obj.fields.keys()[i];3648 const default_val = struct_ty.structFieldDefaultValue(i);
36523649 if (default_val.tag() == .unreachable_value) {
3653 if (field.default_val.tag() == .unreachable_value) {3650 const field_name = struct_ty.structFieldName(i);
3654 const template = "missing struct field: {s}";3651 const template = "missing struct field: {s}";
3655 const args = .{field_name};3652 const args = .{field_name};
3656 if (root_msg) |msg| {3653 if (root_msg) |msg| {
...@@ -3660,17 +3657,20 @@ fn validateStructInit(...@@ -3660,17 +3657,20 @@ fn validateStructInit(
3660 }3657 }
3661 continue;3658 continue;
3662 }3659 }
3660 field_values[i] = default_val;
3663 }3661 }
36643662
3665 if (root_msg) |msg| {3663 if (root_msg) |msg| {
3666 const fqn = try struct_obj.getFullyQualifiedName(sema.mod);3664 if (struct_ty.castTag(.@"struct")) |struct_obj| {
3667 defer gpa.free(fqn);3665 const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);
3668 try sema.mod.errNoteNonLazy(3666 defer gpa.free(fqn);
3669 struct_obj.srcLoc(sema.mod),3667 try sema.mod.errNoteNonLazy(
3670 msg,3668 struct_obj.data.srcLoc(sema.mod),
3671 "struct '{s}' declared here",3669 msg,
3672 .{fqn},3670 "struct '{s}' declared here",
3673 );3671 .{fqn},
3672 );
3673 }
3674 return sema.failWithOwnedErrorMsg(block, msg);3674 return sema.failWithOwnedErrorMsg(block, msg);
3675 }3675 }
36763676
...@@ -3679,15 +3679,6 @@ fn validateStructInit(...@@ -3679,15 +3679,6 @@ fn validateStructInit(
3679 // instead a single `store` to the struct_ptr with a comptime struct value.3679 // instead a single `store` to the struct_ptr with a comptime struct value.
36803680
3681 block.instructions.shrinkRetainingCapacity(first_block_index);3681 block.instructions.shrinkRetainingCapacity(first_block_index);
3682
3683 // The `field_values` array has been populated for all the non-default struct
3684 // fields. Here we fill in the default field values.
3685 for (found_fields) |field_ptr, i| {
3686 if (field_ptr != 0) continue;
3687
3688 field_values[i] = fields[i].default_val;
3689 }
3690
3691 const struct_val = try Value.Tag.aggregate.create(sema.arena, field_values);3682 const struct_val = try Value.Tag.aggregate.create(sema.arena, field_values);
3692 const struct_init = try sema.addConstant(struct_ty, struct_val);3683 const struct_init = try sema.addConstant(struct_ty, struct_val);
3693 try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store);3684 try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store);
...@@ -3695,16 +3686,13 @@ fn validateStructInit(...@@ -3695,16 +3686,13 @@ fn validateStructInit(
3695 }3686 }
36963687
3697 // Our task is to insert `store` instructions for all the default field values.3688 // Our task is to insert `store` instructions for all the default field values.
3698
3699 for (found_fields) |field_ptr, i| {3689 for (found_fields) |field_ptr, i| {
3700 if (field_ptr != 0) continue;3690 if (field_ptr != 0) continue;
37013691
3702 const field = fields[i];
3703 const field_name = struct_obj.fields.keys()[i];
3704 const default_field_ptr = try sema.structFieldPtr(block, init_src, struct_ptr, field_name, init_src, struct_ty);
3705
3706 const init = try sema.addConstant(field.ty, field.default_val);
3707 const field_src = init_src; // TODO better source location3692 const field_src = init_src; // TODO better source location
3693 const default_field_ptr = try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty);
3694 const field_ty = sema.typeOf(default_field_ptr).childType();
3695 const init = try sema.addConstant(field_ty, field_values[i]);
3708 try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);3696 try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);
3709 }3697 }
3710}3698}
...@@ -13827,7 +13815,7 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -13827,7 +13815,7 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
13827 const obj_ty = try sema.resolveType(block, src, inst_data.operand);13815 const obj_ty = try sema.resolveType(block, src, inst_data.operand);
1382813816
13829 switch (obj_ty.zigTypeTag()) {13817 switch (obj_ty.zigTypeTag()) {
13830 .Struct => return structInitEmpty(sema, block, obj_ty, src, src),13818 .Struct => return sema.structInitEmpty(block, obj_ty, src, src),
13831 .Array => return arrayInitEmpty(sema, obj_ty),13819 .Array => return arrayInitEmpty(sema, obj_ty),
13832 .Void => return sema.addConstant(obj_ty, Value.void),13820 .Void => return sema.addConstant(obj_ty, Value.void),
13833 else => return sema.failWithArrayInitNotSupported(block, src, obj_ty),13821 else => return sema.failWithArrayInitNotSupported(block, src, obj_ty),
...@@ -13844,29 +13832,13 @@ fn structInitEmpty(...@@ -13844,29 +13832,13 @@ fn structInitEmpty(
13844 const gpa = sema.gpa;13832 const gpa = sema.gpa;
13845 // This logic must be synchronized with that in `zirStructInit`.13833 // This logic must be synchronized with that in `zirStructInit`.
13846 const struct_ty = try sema.resolveTypeFields(block, dest_src, obj_ty);13834 const struct_ty = try sema.resolveTypeFields(block, dest_src, obj_ty);
13847 const struct_obj = struct_ty.castTag(.@"struct").?.data;
1384813835
13849 // The init values to use for the struct instance.13836 // The init values to use for the struct instance.
13850 const field_inits = try gpa.alloc(Air.Inst.Ref, struct_obj.fields.count());13837 const field_inits = try gpa.alloc(Air.Inst.Ref, struct_ty.structFieldCount());
13851 defer gpa.free(field_inits);13838 defer gpa.free(field_inits);
13839 mem.set(Air.Inst.Ref, field_inits, .none);
1385213840
13853 var root_msg: ?*Module.ErrorMsg = null;13841 return sema.finishStructInit(block, init_src, dest_src, field_inits, struct_ty, false);
13854
13855 for (struct_obj.fields.values()) |field, i| {
13856 if (field.default_val.tag() == .unreachable_value) {
13857 const field_name = struct_obj.fields.keys()[i];
13858 const template = "missing struct field: {s}";
13859 const args = .{field_name};
13860 if (root_msg) |msg| {
13861 try sema.errNote(block, init_src, msg, template, args);
13862 } else {
13863 root_msg = try sema.errMsg(block, init_src, template, args);
13864 }
13865 } else {
13866 field_inits[i] = try sema.addConstant(field.ty, field.default_val);
13867 }
13868 }
13869 return sema.finishStructInit(block, dest_src, field_inits, root_msg, struct_obj, struct_ty, false);
13870}13842}
1387113843
13872fn arrayInitEmpty(sema: *Sema, obj_ty: Type) CompileError!Air.Inst.Ref {13844fn arrayInitEmpty(sema: *Sema, obj_ty: Type) CompileError!Air.Inst.Ref {
...@@ -13936,19 +13908,18 @@ fn zirStructInit(...@@ -13936,19 +13908,18 @@ fn zirStructInit(
13936 const unresolved_struct_type = try sema.resolveType(block, src, first_field_type_extra.container_type);13908 const unresolved_struct_type = try sema.resolveType(block, src, first_field_type_extra.container_type);
13937 const resolved_ty = try sema.resolveTypeFields(block, src, unresolved_struct_type);13909 const resolved_ty = try sema.resolveTypeFields(block, src, unresolved_struct_type);
1393813910
13939 if (resolved_ty.castTag(.@"struct")) |struct_payload| {13911 if (resolved_ty.zigTypeTag() == .Struct) {
13940 // This logic must be synchronized with that in `zirStructInitEmpty`.13912 // This logic must be synchronized with that in `zirStructInitEmpty`.
13941 const struct_obj = struct_payload.data;
1394213913
13943 // Maps field index to field_type index of where it was already initialized.13914 // Maps field index to field_type index of where it was already initialized.
13944 // For making sure all fields are accounted for and no fields are duplicated.13915 // For making sure all fields are accounted for and no fields are duplicated.
13945 const found_fields = try gpa.alloc(Zir.Inst.Index, struct_obj.fields.count());13916 const found_fields = try gpa.alloc(Zir.Inst.Index, resolved_ty.structFieldCount());
13946 defer gpa.free(found_fields);13917 defer gpa.free(found_fields);
13947 mem.set(Zir.Inst.Index, found_fields, 0);
1394813918
13949 // The init values to use for the struct instance.13919 // The init values to use for the struct instance.
13950 const field_inits = try gpa.alloc(Air.Inst.Ref, struct_obj.fields.count());13920 const field_inits = try gpa.alloc(Air.Inst.Ref, resolved_ty.structFieldCount());
13951 defer gpa.free(field_inits);13921 defer gpa.free(field_inits);
13922 mem.set(Air.Inst.Ref, field_inits, .none);
1395213923
13953 var field_i: u32 = 0;13924 var field_i: u32 = 0;
13954 var extra_index = extra.end;13925 var extra_index = extra.end;
...@@ -13961,9 +13932,8 @@ fn zirStructInit(...@@ -13961,9 +13932,8 @@ fn zirStructInit(
13961 const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_type_data.src_node };13932 const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_type_data.src_node };
13962 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;13933 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
13963 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);13934 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
13964 const field_index = struct_obj.fields.getIndex(field_name) orelse13935 const field_index = try sema.structFieldIndex(block, resolved_ty, field_name, field_src);
13965 return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);13936 if (field_inits[field_index] != .none) {
13966 if (found_fields[field_index] != 0) {
13967 const other_field_type = found_fields[field_index];13937 const other_field_type = found_fields[field_index];
13968 const other_field_type_data = zir_datas[other_field_type].pl_node;13938 const other_field_type_data = zir_datas[other_field_type].pl_node;
13969 const other_field_src: LazySrcLoc = .{ .node_offset_back2tok = other_field_type_data.src_node };13939 const other_field_src: LazySrcLoc = .{ .node_offset_back2tok = other_field_type_data.src_node };
...@@ -13979,27 +13949,7 @@ fn zirStructInit(...@@ -13979,27 +13949,7 @@ fn zirStructInit(
13979 field_inits[field_index] = try sema.resolveInst(item.data.init);13949 field_inits[field_index] = try sema.resolveInst(item.data.init);
13980 }13950 }
1398113951
13982 var root_msg: ?*Module.ErrorMsg = null;13952 return sema.finishStructInit(block, src, src, field_inits, resolved_ty, is_ref);
13983
13984 for (found_fields) |field_type_inst, i| {
13985 if (field_type_inst != 0) continue;
13986
13987 // Check if the field has a default init.
13988 const field = struct_obj.fields.values()[i];
13989 if (field.default_val.tag() == .unreachable_value) {
13990 const field_name = struct_obj.fields.keys()[i];
13991 const template = "missing struct field: {s}";
13992 const args = .{field_name};
13993 if (root_msg) |msg| {
13994 try sema.errNote(block, src, msg, template, args);
13995 } else {
13996 root_msg = try sema.errMsg(block, src, template, args);
13997 }
13998 } else {
13999 field_inits[i] = try sema.addConstant(field.ty, field.default_val);
14000 }
14001 }
14002 return sema.finishStructInit(block, src, field_inits, root_msg, struct_obj, resolved_ty, is_ref);
14003 } else if (resolved_ty.zigTypeTag() == .Union) {13953 } else if (resolved_ty.zigTypeTag() == .Union) {
14004 if (extra.data.fields_len != 1) {13954 if (extra.data.fields_len != 1) {
14005 return sema.fail(block, src, "union initialization expects exactly one field", .{});13955 return sema.fail(block, src, "union initialization expects exactly one field", .{});
...@@ -14051,29 +14001,69 @@ fn zirStructInit(...@@ -14051,29 +14001,69 @@ fn zirStructInit(
14051fn finishStructInit(14001fn finishStructInit(
14052 sema: *Sema,14002 sema: *Sema,
14053 block: *Block,14003 block: *Block,
14054 src: LazySrcLoc,14004 init_src: LazySrcLoc,
14055 field_inits: []const Air.Inst.Ref,14005 dest_src: LazySrcLoc,
14056 root_msg: ?*Module.ErrorMsg,14006 field_inits: []Air.Inst.Ref,
14057 struct_obj: *Module.Struct,
14058 struct_ty: Type,14007 struct_ty: Type,
14059 is_ref: bool,14008 is_ref: bool,
14060) !Air.Inst.Ref {14009) CompileError!Air.Inst.Ref {
14061 const gpa = sema.gpa;14010 const gpa = sema.gpa;
1406214011
14012 var root_msg: ?*Module.ErrorMsg = null;
14013 if (struct_ty.isAnonStruct()) {
14014 const struct_obj = struct_ty.castTag(.anon_struct).?.data;
14015 for (struct_obj.values) |default_val, i| {
14016 if (field_inits[i] != .none) continue;
14017
14018 if (default_val.tag() == .unreachable_value) {
14019 const field_name = struct_obj.names[i];
14020 const template = "missing struct field: {s}";
14021 const args = .{field_name};
14022 if (root_msg) |msg| {
14023 try sema.errNote(block, init_src, msg, template, args);
14024 } else {
14025 root_msg = try sema.errMsg(block, init_src, template, args);
14026 }
14027 } else {
14028 field_inits[i] = try sema.addConstant(struct_obj.types[i], default_val);
14029 }
14030 }
14031 } else {
14032 const struct_obj = struct_ty.castTag(.@"struct").?.data;
14033 for (struct_obj.fields.values()) |field, i| {
14034 if (field_inits[i] != .none) continue;
14035
14036 if (field.default_val.tag() == .unreachable_value) {
14037 const field_name = struct_obj.fields.keys()[i];
14038 const template = "missing struct field: {s}";
14039 const args = .{field_name};
14040 if (root_msg) |msg| {
14041 try sema.errNote(block, init_src, msg, template, args);
14042 } else {
14043 root_msg = try sema.errMsg(block, init_src, template, args);
14044 }
14045 } else {
14046 field_inits[i] = try sema.addConstant(field.ty, field.default_val);
14047 }
14048 }
14049 }
14050
14063 if (root_msg) |msg| {14051 if (root_msg) |msg| {
14064 const fqn = try struct_obj.getFullyQualifiedName(sema.mod);14052 if (struct_ty.castTag(.@"struct")) |struct_obj| {
14065 defer gpa.free(fqn);14053 const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);
14066 try sema.mod.errNoteNonLazy(14054 defer gpa.free(fqn);
14067 struct_obj.srcLoc(sema.mod),14055 try sema.mod.errNoteNonLazy(
14068 msg,14056 struct_obj.data.srcLoc(sema.mod),
14069 "struct '{s}' declared here",14057 msg,
14070 .{fqn},14058 "struct '{s}' declared here",
14071 );14059 .{fqn},
14060 );
14061 }
14072 return sema.failWithOwnedErrorMsg(block, msg);14062 return sema.failWithOwnedErrorMsg(block, msg);
14073 }14063 }
1407414064
14075 const is_comptime = for (field_inits) |field_init| {14065 const is_comptime = for (field_inits) |field_init| {
14076 if (!(try sema.isComptimeKnown(block, src, field_init))) {14066 if (!(try sema.isComptimeKnown(block, dest_src, field_init))) {
14077 break false;14067 break false;
14078 }14068 }
14079 } else true;14069 } else true;
...@@ -14081,10 +14071,10 @@ fn finishStructInit(...@@ -14081,10 +14071,10 @@ fn finishStructInit(
14081 if (is_comptime) {14071 if (is_comptime) {
14082 const values = try sema.arena.alloc(Value, field_inits.len);14072 const values = try sema.arena.alloc(Value, field_inits.len);
14083 for (field_inits) |field_init, i| {14073 for (field_inits) |field_init, i| {
14084 values[i] = (sema.resolveMaybeUndefVal(block, src, field_init) catch unreachable).?;14074 values[i] = (sema.resolveMaybeUndefVal(block, dest_src, field_init) catch unreachable).?;
14085 }14075 }
14086 const struct_val = try Value.Tag.aggregate.create(sema.arena, values);14076 const struct_val = try Value.Tag.aggregate.create(sema.arena, values);
14087 return sema.addConstantMaybeRef(block, src, struct_ty, struct_val, is_ref);14077 return sema.addConstantMaybeRef(block, dest_src, struct_ty, struct_val, is_ref);
14088 }14078 }
1408914079
14090 if (is_ref) {14080 if (is_ref) {
...@@ -14096,15 +14086,15 @@ fn finishStructInit(...@@ -14096,15 +14086,15 @@ fn finishStructInit(
14096 const alloc = try block.addTy(.alloc, alloc_ty);14086 const alloc = try block.addTy(.alloc, alloc_ty);
14097 for (field_inits) |field_init, i_usize| {14087 for (field_inits) |field_init, i_usize| {
14098 const i = @intCast(u32, i_usize);14088 const i = @intCast(u32, i_usize);
14099 const field_src = src;14089 const field_src = dest_src;
14100 const field_ptr = try sema.structFieldPtrByIndex(block, src, alloc, i, struct_obj, field_src);14090 const field_ptr = try sema.structFieldPtrByIndex(block, dest_src, alloc, i, field_src, struct_ty);
14101 try sema.storePtr(block, src, field_ptr, field_init);14091 try sema.storePtr(block, dest_src, field_ptr, field_init);
14102 }14092 }
1410314093
14104 return alloc;14094 return alloc;
14105 }14095 }
1410614096
14107 try sema.requireRuntimeBlock(block, src);14097 try sema.requireRuntimeBlock(block, dest_src);
14108 try sema.queueFullTypeResolution(struct_ty);14098 try sema.queueFullTypeResolution(struct_ty);
14109 return block.addAggregateInit(struct_ty, field_inits);14099 return block.addAggregateInit(struct_ty, field_inits);
14110}14100}
...@@ -15872,7 +15862,8 @@ fn zirOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -15872,7 +15862,8 @@ fn zirOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1587215862
15873fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u64 {15863fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u64 {
15874 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;15864 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
15875 sema.src = .{ .node_offset_bin_op = inst_data.src_node };15865 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
15866 sema.src = src;
15876 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };15867 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
15877 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };15868 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
15878 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;15869 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
...@@ -15882,50 +15873,38 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6...@@ -15882,50 +15873,38 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6
15882 const target = sema.mod.getTarget();15873 const target = sema.mod.getTarget();
1588315874
15884 try sema.resolveTypeLayout(block, lhs_src, ty);15875 try sema.resolveTypeLayout(block, lhs_src, ty);
15885 if (ty.tag() != .@"struct") {15876 switch (ty.tag()) {
15886 const msg = msg: {15877 .@"struct", .tuple, .anon_struct => {},
15887 const msg = try sema.errMsg(block, lhs_src, "expected struct type, found '{}'", .{ty.fmt(sema.mod)});15878 else => {
15888 errdefer msg.destroy(sema.gpa);15879 const msg = msg: {
15889 try sema.addDeclaredHereNote(msg, ty);15880 const msg = try sema.errMsg(block, lhs_src, "expected struct type, found '{}'", .{ty.fmt(sema.mod)});
15890 break :msg msg;15881 errdefer msg.destroy(sema.gpa);
15891 };15882 try sema.addDeclaredHereNote(msg, ty);
15892 return sema.failWithOwnedErrorMsg(block, msg);15883 break :msg msg;
15884 };
15885 return sema.failWithOwnedErrorMsg(block, msg);
15886 },
15893 }15887 }
1589415888
15895 const fields = ty.structFields();15889 const field_index = if (ty.isTuple()) blk: {
15896 const index = fields.getIndex(field_name) orelse {15890 if (mem.eql(u8, field_name, "len")) {
15897 const msg = msg: {15891 return sema.fail(block, src, "no offset available for 'len' field of tuple", .{});
15898 const msg = try sema.errMsg(15892 }
15899 block,15893 break :blk try sema.tupleFieldIndex(block, ty, field_name, rhs_src);
15900 rhs_src,15894 } else try sema.structFieldIndex(block, ty, field_name, rhs_src);
15901 "struct '{}' has no field '{s}'",
15902 .{ ty.fmt(sema.mod), field_name },
15903 );
15904 errdefer msg.destroy(sema.gpa);
15905 try sema.addDeclaredHereNote(msg, ty);
15906 break :msg msg;
15907 };
15908 return sema.failWithOwnedErrorMsg(block, msg);
15909 };
1591015895
15911 switch (ty.containerLayout()) {15896 switch (ty.containerLayout()) {
15912 .Packed => {15897 .Packed => {
15913 var bit_sum: u64 = 0;15898 var bit_sum: u64 = 0;
15899 const fields = ty.structFields();
15914 for (fields.values()) |field, i| {15900 for (fields.values()) |field, i| {
15915 if (i == index) {15901 if (i == field_index) {
15916 return bit_sum;15902 return bit_sum;
15917 }15903 }
15918 bit_sum += field.ty.bitSize(target);15904 bit_sum += field.ty.bitSize(target);
15919 } else unreachable;15905 } else unreachable;
15920 },15906 },
15921 else => {15907 else => return ty.structFieldOffset(field_index, target) * 8,
15922 var it = ty.iterateStructOffsets(target);
15923 while (it.next()) |field_offset| {
15924 if (field_offset.field == index) {
15925 return field_offset.offset * 8;
15926 }
15927 } else unreachable;
15928 },
15929 }15908 }
15930}15909}
1593115910
...@@ -17193,24 +17172,28 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -17193,24 +17172,28 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
17193 }17172 }
17194 try sema.resolveTypeLayout(block, ty_src, struct_ty);17173 try sema.resolveTypeLayout(block, ty_src, struct_ty);
1719517174
17196 const struct_obj = struct_ty.castTag(.@"struct").?.data;17175 const field_index = if (struct_ty.isTuple()) blk: {
17197 const field_index = struct_obj.fields.getIndex(field_name) orelse17176 if (mem.eql(u8, field_name, "len")) {
17198 return sema.failWithBadStructFieldAccess(block, struct_obj, name_src, field_name);17177 return sema.fail(block, src, "cannot get @fieldParentPtr of 'len' field of tuple", .{});
17178 }
17179 break :blk try sema.tupleFieldIndex(block, struct_ty, field_name, name_src);
17180 } else try sema.structFieldIndex(block, struct_ty, field_name, name_src);
1719917181
17200 try sema.checkPtrOperand(block, ptr_src, field_ptr_ty);17182 try sema.checkPtrOperand(block, ptr_src, field_ptr_ty);
17201 const field = struct_obj.fields.values()[field_index];
17202 const field_ptr_ty_info = field_ptr_ty.ptrInfo().data;17183 const field_ptr_ty_info = field_ptr_ty.ptrInfo().data;
1720317184
17204 var ptr_ty_data: Type.Payload.Pointer.Data = .{17185 var ptr_ty_data: Type.Payload.Pointer.Data = .{
17205 .pointee_type = field.ty,17186 .pointee_type = struct_ty.structFieldType(field_index),
17206 .mutable = field_ptr_ty_info.mutable,17187 .mutable = field_ptr_ty_info.mutable,
17207 .@"addrspace" = field_ptr_ty_info.@"addrspace",17188 .@"addrspace" = field_ptr_ty_info.@"addrspace",
17208 };17189 };
1720917190
17210 if (struct_obj.layout == .Packed) {17191 if (struct_ty.containerLayout() == .Packed) {
17211 return sema.fail(block, src, "TODO handle packed structs with @fieldParentPtr", .{});17192 return sema.fail(block, src, "TODO handle packed structs with @fieldParentPtr", .{});
17212 } else {17193 } else {
17213 ptr_ty_data.@"align" = field.abi_align;17194 ptr_ty_data.@"align" = if (struct_ty.castTag(.@"struct")) |struct_obj| b: {
17195 break :b struct_obj.data.fields.values()[field_index].abi_align;
17196 } else 0;
17214 }17197 }
1721517198
17216 const actual_field_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_ty_data);17199 const actual_field_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_ty_data);
...@@ -19059,7 +19042,7 @@ fn structFieldPtr(...@@ -19059,7 +19042,7 @@ fn structFieldPtr(
19059 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name);19042 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name);
19060 const field_index = @intCast(u32, field_index_big);19043 const field_index = @intCast(u32, field_index_big);
1906119044
19062 return sema.structFieldPtrByIndex(block, src, struct_ptr, field_index, struct_obj, field_name_src);19045 return sema.structFieldPtrByIndex(block, src, struct_ptr, field_index, field_name_src, struct_ty);
19063}19046}
1906419047
19065fn structFieldPtrByIndex(19048fn structFieldPtrByIndex(
...@@ -19068,9 +19051,14 @@ fn structFieldPtrByIndex(...@@ -19068,9 +19051,14 @@ fn structFieldPtrByIndex(
19068 src: LazySrcLoc,19051 src: LazySrcLoc,
19069 struct_ptr: Air.Inst.Ref,19052 struct_ptr: Air.Inst.Ref,
19070 field_index: u32,19053 field_index: u32,
19071 struct_obj: *Module.Struct,
19072 field_src: LazySrcLoc,19054 field_src: LazySrcLoc,
19055 struct_ty: Type,
19073) CompileError!Air.Inst.Ref {19056) CompileError!Air.Inst.Ref {
19057 if (struct_ty.isAnonStruct()) {
19058 return sema.tupleFieldPtr(block, src, struct_ptr, field_src, field_index);
19059 }
19060
19061 const struct_obj = struct_ty.castTag(.@"struct").?.data;
19074 const field = struct_obj.fields.values()[field_index];19062 const field = struct_obj.fields.values()[field_index];
19075 const struct_ptr_ty = sema.typeOf(struct_ptr);19063 const struct_ptr_ty = sema.typeOf(struct_ptr);
19076 const struct_ptr_ty_info = struct_ptr_ty.ptrInfo().data;19064 const struct_ptr_ty_info = struct_ptr_ty.ptrInfo().data;
...@@ -19231,17 +19219,13 @@ fn tupleFieldIndex(...@@ -19231,17 +19219,13 @@ fn tupleFieldIndex(
19231 field_name: []const u8,19219 field_name: []const u8,
19232 field_name_src: LazySrcLoc,19220 field_name_src: LazySrcLoc,
19233) CompileError!u32 {19221) CompileError!u32 {
19234 const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch |err| {19222 if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| {
19235 return sema.fail(block, field_name_src, "tuple '{}' has no such field '{s}': {s}", .{19223 if (field_index < tuple_ty.structFieldCount()) return field_index;
19236 tuple_ty.fmt(sema.mod), field_name, @errorName(err),19224 } else |_| {}
19237 });19225
19238 };19226 return sema.fail(block, field_name_src, "no field named '{s}' in tuple '{}'", .{
19239 if (field_index >= tuple_ty.structFieldCount()) {19227 field_name, tuple_ty.fmt(sema.mod),
19240 return sema.fail(block, field_name_src, "tuple '{}' has no such field '{s}'", .{19228 });
19241 tuple_ty.fmt(sema.mod), field_name,
19242 });
19243 }
19244 return field_index;
19245}19229}
1924619230
19247fn tupleFieldValByIndex(19231fn tupleFieldValByIndex(
...@@ -20356,7 +20340,7 @@ fn coerce(...@@ -20356,7 +20340,7 @@ fn coerce(
20356 },20340 },
20357 .Struct => {20341 .Struct => {
20358 if (inst == .empty_struct) {20342 if (inst == .empty_struct) {
20359 return structInitEmpty(sema, block, dest_ty, dest_ty_src, inst_src);20343 return sema.structInitEmpty(block, dest_ty, dest_ty_src, inst_src);
20360 }20344 }
20361 if (inst_ty.isTupleOrAnonStruct()) {20345 if (inst_ty.isTupleOrAnonStruct()) {
20362 return sema.coerceTupleToStruct(block, dest_ty, dest_ty_src, inst, inst_src);20346 return sema.coerceTupleToStruct(block, dest_ty, dest_ty_src, inst, inst_src);
...@@ -25754,10 +25738,14 @@ fn structFieldIndex(...@@ -25754,10 +25738,14 @@ fn structFieldIndex(
25754 field_src: LazySrcLoc,25738 field_src: LazySrcLoc,
25755) !u32 {25739) !u32 {
25756 const struct_ty = try sema.resolveTypeFields(block, field_src, unresolved_struct_ty);25740 const struct_ty = try sema.resolveTypeFields(block, field_src, unresolved_struct_ty);
25757 const struct_obj = struct_ty.castTag(.@"struct").?.data;25741 if (struct_ty.isAnonStruct()) {
25758 const field_index_usize = struct_obj.fields.getIndex(field_name) orelse25742 return sema.anonStructFieldIndex(block, struct_ty, field_name, field_src);
25759 return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);25743 } else {
25760 return @intCast(u32, field_index_usize);25744 const struct_obj = struct_ty.castTag(.@"struct").?.data;
25745 const field_index_usize = struct_obj.fields.getIndex(field_name) orelse
25746 return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);
25747 return @intCast(u32, field_index_usize);
25748 }
25761}25749}
2576225750
25763fn anonStructFieldIndex(25751fn anonStructFieldIndex(
...@@ -25773,8 +25761,8 @@ fn anonStructFieldIndex(...@@ -25773,8 +25761,8 @@ fn anonStructFieldIndex(
25773 return @intCast(u32, i);25761 return @intCast(u32, i);
25774 }25762 }
25775 }25763 }
25776 return sema.fail(block, field_src, "anonymous struct '{}' has no such field '{s}'", .{25764 return sema.fail(block, field_src, "no field named '{s}' in anonymous struct '{}'", .{
25777 struct_ty.fmt(sema.mod), field_name,25765 field_name, struct_ty.fmt(sema.mod),
25778 });25766 });
25779}25767}
2578025768
src/type.zig+18
...@@ -5432,6 +5432,24 @@ pub const Type = extern union {...@@ -5432,6 +5432,24 @@ pub const Type = extern union {
5432 }5432 }
5433 }5433 }
54345434
5435 pub fn structFieldDefaultValue(ty: Type, index: usize) Value {
5436 switch (ty.tag()) {
5437 .@"struct" => {
5438 const struct_obj = ty.castTag(.@"struct").?.data;
5439 return struct_obj.fields.values()[index].default_val;
5440 },
5441 .tuple => {
5442 const tuple = ty.castTag(.tuple).?.data;
5443 return tuple.values[index];
5444 },
5445 .anon_struct => {
5446 const struct_obj = ty.castTag(.anon_struct).?.data;
5447 return struct_obj.values[index];
5448 },
5449 else => unreachable,
5450 }
5451 }
5452
5435 pub fn structFieldValueComptime(ty: Type, index: usize) ?Value {5453 pub fn structFieldValueComptime(ty: Type, index: usize) ?Value {
5436 switch (ty.tag()) {5454 switch (ty.tag()) {
5437 .@"struct" => {5455 .@"struct" => {
test/behavior/tuple.zig+58
...@@ -197,3 +197,61 @@ test "initializing tuple with explicit type" {...@@ -197,3 +197,61 @@ test "initializing tuple with explicit type" {
197 var a = T{ 0, 0 };197 var a = T{ 0, 0 };
198 _ = a;198 _ = a;
199}199}
200
201test "initializing anon struct with explicit type" {
202 const T = @TypeOf(.{ .foo = @as(i32, 1), .bar = @as(i32, 2) });
203 var a = T{ .foo = 1, .bar = 2 };
204 _ = a;
205}
206
207test "fieldParentPtr of tuple" {
208 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
209 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
210 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
211 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
212
213 var x: u32 = 0;
214 const tuple = .{ x, x };
215 try testing.expect(&tuple == @fieldParentPtr(@TypeOf(tuple), "1", &tuple[1]));
216}
217
218test "fieldParentPtr of anon struct" {
219 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
220 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
221 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
222 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
223
224 var x: u32 = 0;
225 const anon_st = .{ .foo = x, .bar = x };
226 try testing.expect(&anon_st == @fieldParentPtr(@TypeOf(anon_st), "bar", &anon_st.bar));
227}
228
229test "offsetOf tuple" {
230 var x: u32 = 0;
231 const T = @TypeOf(.{ x, x });
232 _ = @offsetOf(T, "1");
233}
234
235test "offsetOf anon struct" {
236 var x: u32 = 0;
237 const T = @TypeOf(.{ .foo = x, .bar = x });
238 _ = @offsetOf(T, "bar");
239}
240
241test "initializing tuple with mixed comptime-runtime fields" {
242 if (true) return error.SkipZigTest; // TODO
243
244 var x: u32 = 15;
245 const T = @TypeOf(.{ @as(i32, -1234), @as(u32, 5678), x });
246 var a: T = .{ -1234, 5678, x + 1 };
247 _ = a;
248}
249
250test "initializing anon struct with mixed comptime-runtime fields" {
251 if (true) return error.SkipZigTest; // TODO
252
253 var x: u32 = 15;
254 const T = @TypeOf(.{ .foo = @as(i32, -1234), .bar = x });
255 var a: T = .{ .foo = -1234, .bar = x + 1 };
256 _ = a;
257}
test/cases/compile_errors/offsetOf-bad_field_name.zig+1-1
...@@ -9,5 +9,5 @@ export fn foo() usize {...@@ -9,5 +9,5 @@ export fn foo() usize {
9// backend=stage29// backend=stage2
10// target=native10// target=native
11//11//
12// :5:27: error: struct 'tmp.Foo' has no field 'a'12// :5:27: error: no field named 'a' in struct 'tmp.Foo'
13// :1:13: note: struct declared here13// :1:13: note: struct declared here