authorgravatar for topolarity@tapscott.meCody Tapscott <topolarity@tapscott.me> 2022-07-08 15:09:56-07:00
committergravatar for topolarity@tapscott.meCody Tapscott <topolarity@tapscott.me> 2022-07-08 19:50:28-07:00
log2fff25fd220632cc6943680d3d6bbb1f21fa141f
treec4d7be35ec022324c46761db643e2f28418cccb4
parent6f0807f50f4e946bb850e746beaa5d6556cf7750

stage2: Support initializing anonymous struct type

This commit adds support for initializing `.anon_struct` types. There is also some follow-up work to do for both tuples and structs regarding comptime fields, so this also adds some tests to keep track of that work.

3 files changed, 204 insertions(+), 129 deletions(-)

src/Sema.zig+128-129
...@@ -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}
...@@ -19059,7 +19049,7 @@ fn structFieldPtr(...@@ -19059,7 +19049,7 @@ fn structFieldPtr(
19059 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name);19049 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name);
19060 const field_index = @intCast(u32, field_index_big);19050 const field_index = @intCast(u32, field_index_big);
1906119051
19062 return sema.structFieldPtrByIndex(block, src, struct_ptr, field_index, struct_obj, field_name_src);19052 return sema.structFieldPtrByIndex(block, src, struct_ptr, field_index, field_name_src, struct_ty);
19063}19053}
1906419054
19065fn structFieldPtrByIndex(19055fn structFieldPtrByIndex(
...@@ -19068,9 +19058,14 @@ fn structFieldPtrByIndex(...@@ -19068,9 +19058,14 @@ fn structFieldPtrByIndex(
19068 src: LazySrcLoc,19058 src: LazySrcLoc,
19069 struct_ptr: Air.Inst.Ref,19059 struct_ptr: Air.Inst.Ref,
19070 field_index: u32,19060 field_index: u32,
19071 struct_obj: *Module.Struct,
19072 field_src: LazySrcLoc,19061 field_src: LazySrcLoc,
19062 struct_ty: Type,
19073) CompileError!Air.Inst.Ref {19063) CompileError!Air.Inst.Ref {
19064 if (struct_ty.isAnonStruct()) {
19065 return sema.tupleFieldPtr(block, src, struct_ptr, field_src, field_index);
19066 }
19067
19068 const struct_obj = struct_ty.castTag(.@"struct").?.data;
19074 const field = struct_obj.fields.values()[field_index];19069 const field = struct_obj.fields.values()[field_index];
19075 const struct_ptr_ty = sema.typeOf(struct_ptr);19070 const struct_ptr_ty = sema.typeOf(struct_ptr);
19076 const struct_ptr_ty_info = struct_ptr_ty.ptrInfo().data;19071 const struct_ptr_ty_info = struct_ptr_ty.ptrInfo().data;
...@@ -20356,7 +20351,7 @@ fn coerce(...@@ -20356,7 +20351,7 @@ fn coerce(
20356 },20351 },
20357 .Struct => {20352 .Struct => {
20358 if (inst == .empty_struct) {20353 if (inst == .empty_struct) {
20359 return structInitEmpty(sema, block, dest_ty, dest_ty_src, inst_src);20354 return sema.structInitEmpty(block, dest_ty, dest_ty_src, inst_src);
20360 }20355 }
20361 if (inst_ty.isTupleOrAnonStruct()) {20356 if (inst_ty.isTupleOrAnonStruct()) {
20362 return sema.coerceTupleToStruct(block, dest_ty, dest_ty_src, inst, inst_src);20357 return sema.coerceTupleToStruct(block, dest_ty, dest_ty_src, inst, inst_src);
...@@ -25754,10 +25749,14 @@ fn structFieldIndex(...@@ -25754,10 +25749,14 @@ fn structFieldIndex(
25754 field_src: LazySrcLoc,25749 field_src: LazySrcLoc,
25755) !u32 {25750) !u32 {
25756 const struct_ty = try sema.resolveTypeFields(block, field_src, unresolved_struct_ty);25751 const struct_ty = try sema.resolveTypeFields(block, field_src, unresolved_struct_ty);
25757 const struct_obj = struct_ty.castTag(.@"struct").?.data;25752 if (struct_ty.isAnonStruct()) {
25758 const field_index_usize = struct_obj.fields.getIndex(field_name) orelse25753 return sema.anonStructFieldIndex(block, struct_ty, field_name, field_src);
25759 return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);25754 } else {
25760 return @intCast(u32, field_index_usize);25755 const struct_obj = struct_ty.castTag(.@"struct").?.data;
25756 const field_index_usize = struct_obj.fields.getIndex(field_name) orelse
25757 return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);
25758 return @intCast(u32, field_index_usize);
25759 }
25761}25760}
2576225761
25763fn anonStructFieldIndex(25762fn anonStructFieldIndex(
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 != .stage1) return error.SkipZigTest;
209
210 var x: u32 = 0;
211 const tuple = .{ x, x };
212 try testing.expect(&tuple == @fieldParentPtr(@TypeOf(tuple), "1", &tuple[1]));
213}
214
215test "fieldParentPtr of anon struct" {
216 if (builtin.zig_backend != .stage1) return error.SkipZigTest;
217
218 var x: u32 = 0;
219 const anon_st = .{ .foo = x, .bar = x };
220 try testing.expect(&anon_st == @fieldParentPtr(@TypeOf(anon_st), "bar", &anon_st.bar));
221}
222
223test "offsetOf tuple" {
224 if (builtin.zig_backend != .stage1) return error.SkipZigTest;
225
226 var x: u32 = 0;
227 const T = @TypeOf(.{ x, x });
228
229 _ = @offsetOf(T, "1");
230}
231
232test "offsetOf anon struct" {
233 if (builtin.zig_backend != .stage1) return error.SkipZigTest;
234
235 var x: u32 = 0;
236 const T = @TypeOf(.{ .foo = x, .bar = x });
237
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}