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(
33263326 switch (agg_ty.zigTypeTag()) {
33273327 .Struct => return sema.validateStructInit(
33283328 block,
3329 agg_ty.castTag(.@"struct").?.data,
3329 agg_ty,
33303330 init_src,
33313331 instrs,
33323332 is_comptime,
......@@ -3470,7 +3470,7 @@ fn validateUnionInit(
34703470fn validateStructInit(
34713471 sema: *Sema,
34723472 block: *Block,
3473 struct_obj: *Module.Struct,
3473 struct_ty: Type,
34743474 init_src: LazySrcLoc,
34753475 instrs: []const Zir.Inst.Index,
34763476 is_comptime: bool,
......@@ -3478,7 +3478,7 @@ fn validateStructInit(
34783478 const gpa = sema.gpa;
34793479
34803480 // 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());
34823482 defer gpa.free(found_fields);
34833483 mem.set(Zir.Inst.Index, found_fields, 0);
34843484
......@@ -3490,8 +3490,7 @@ fn validateStructInit(
34903490 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
34913491 struct_ptr_zir_ref = field_ptr_extra.lhs;
34923492 const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start);
3493 const field_index = struct_obj.fields.getIndex(field_name) orelse
3494 return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);
3493 const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src);
34953494 if (found_fields[field_index] != 0) {
34963495 const other_field_ptr = found_fields[field_index];
34973496 const other_field_ptr_data = sema.code.instructions.items(.data)[other_field_ptr].pl_node;
......@@ -3509,10 +3508,7 @@ fn validateStructInit(
35093508
35103509 var root_msg: ?*Module.ErrorMsg = null;
35113510
3512 const fields = struct_obj.fields.values();
35133511 const struct_ptr = try sema.resolveInst(struct_ptr_zir_ref);
3514 const struct_ty = sema.typeOf(struct_ptr).childType();
3515
35163512 if ((is_comptime or block.is_comptime) and
35173513 (try sema.resolveDefinedValue(block, init_src, struct_ptr)) != null)
35183514 {
......@@ -3522,10 +3518,9 @@ fn validateStructInit(
35223518 for (found_fields) |field_ptr, i| {
35233519 if (field_ptr != 0) continue;
35243520
3525 const field = fields[i];
3526 const field_name = struct_obj.fields.keys()[i];
3527
3528 if (field.default_val.tag() == .unreachable_value) {
3521 const default_val = struct_ty.structFieldDefaultValue(i);
3522 if (default_val.tag() == .unreachable_value) {
3523 const field_name = struct_ty.structFieldName(i);
35293524 const template = "missing struct field: {s}";
35303525 const args = .{field_name};
35313526 if (root_msg) |msg| {
......@@ -3536,22 +3531,25 @@ fn validateStructInit(
35363531 continue;
35373532 }
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);
35413534 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);
35423538 try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);
35433539 }
35443540
35453541 if (root_msg) |msg| {
3546 const mod = sema.mod;
3547 const fqn = try struct_obj.getFullyQualifiedName(mod);
3548 defer gpa.free(fqn);
3549 try mod.errNoteNonLazy(
3550 struct_obj.srcLoc(mod),
3551 msg,
3552 "struct '{s}' declared here",
3553 .{fqn},
3554 );
3542 if (struct_ty.castTag(.@"struct")) |struct_obj| {
3543 const mod = sema.mod;
3544 const fqn = try struct_obj.data.getFullyQualifiedName(mod);
3545 defer gpa.free(fqn);
3546 try mod.errNoteNonLazy(
3547 struct_obj.data.srcLoc(mod),
3548 msg,
3549 "struct '{s}' declared here",
3550 .{fqn},
3551 );
3552 }
35553553 return sema.failWithOwnedErrorMsg(block, msg);
35563554 }
35573555
......@@ -3566,17 +3564,16 @@ fn validateStructInit(
35663564
35673565 // We collect the comptime field values in case the struct initialization
35683566 // 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
35713569 field: for (found_fields) |field_ptr, i| {
3572 const field = fields[i];
3573
35743570 if (field_ptr != 0) {
35753571 const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node;
35763572 const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_ptr_data.src_node };
35773573
35783574 // 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| {
35803577 field_values[i] = opv;
35813578 continue;
35823579 }
......@@ -3648,9 +3645,9 @@ fn validateStructInit(
36483645 continue :field;
36493646 }
36503647
3651 const field_name = struct_obj.fields.keys()[i];
3652
3653 if (field.default_val.tag() == .unreachable_value) {
3648 const default_val = struct_ty.structFieldDefaultValue(i);
3649 if (default_val.tag() == .unreachable_value) {
3650 const field_name = struct_ty.structFieldName(i);
36543651 const template = "missing struct field: {s}";
36553652 const args = .{field_name};
36563653 if (root_msg) |msg| {
......@@ -3660,17 +3657,20 @@ fn validateStructInit(
36603657 }
36613658 continue;
36623659 }
3660 field_values[i] = default_val;
36633661 }
36643662
36653663 if (root_msg) |msg| {
3666 const fqn = try struct_obj.getFullyQualifiedName(sema.mod);
3667 defer gpa.free(fqn);
3668 try sema.mod.errNoteNonLazy(
3669 struct_obj.srcLoc(sema.mod),
3670 msg,
3671 "struct '{s}' declared here",
3672 .{fqn},
3673 );
3664 if (struct_ty.castTag(.@"struct")) |struct_obj| {
3665 const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);
3666 defer gpa.free(fqn);
3667 try sema.mod.errNoteNonLazy(
3668 struct_obj.data.srcLoc(sema.mod),
3669 msg,
3670 "struct '{s}' declared here",
3671 .{fqn},
3672 );
3673 }
36743674 return sema.failWithOwnedErrorMsg(block, msg);
36753675 }
36763676
......@@ -3679,15 +3679,6 @@ fn validateStructInit(
36793679 // instead a single `store` to the struct_ptr with a comptime struct value.
36803680
36813681 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
36913682 const struct_val = try Value.Tag.aggregate.create(sema.arena, field_values);
36923683 const struct_init = try sema.addConstant(struct_ty, struct_val);
36933684 try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store);
......@@ -3695,16 +3686,13 @@ fn validateStructInit(
36953686 }
36963687
36973688 // Our task is to insert `store` instructions for all the default field values.
3698
36993689 for (found_fields) |field_ptr, i| {
37003690 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);
37073692 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]);
37083696 try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);
37093697 }
37103698}
......@@ -13827,7 +13815,7 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
1382713815 const obj_ty = try sema.resolveType(block, src, inst_data.operand);
1382813816
1382913817 switch (obj_ty.zigTypeTag()) {
13830 .Struct => return structInitEmpty(sema, block, obj_ty, src, src),
13818 .Struct => return sema.structInitEmpty(block, obj_ty, src, src),
1383113819 .Array => return arrayInitEmpty(sema, obj_ty),
1383213820 .Void => return sema.addConstant(obj_ty, Value.void),
1383313821 else => return sema.failWithArrayInitNotSupported(block, src, obj_ty),
......@@ -13844,29 +13832,13 @@ fn structInitEmpty(
1384413832 const gpa = sema.gpa;
1384513833 // This logic must be synchronized with that in `zirStructInit`.
1384613834 const struct_ty = try sema.resolveTypeFields(block, dest_src, obj_ty);
13847 const struct_obj = struct_ty.castTag(.@"struct").?.data;
1384813835
1384913836 // 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());
1385113838 defer gpa.free(field_inits);
13839 mem.set(Air.Inst.Ref, field_inits, .none);
1385213840
13853 var root_msg: ?*Module.ErrorMsg = null;
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);
13841 return sema.finishStructInit(block, init_src, dest_src, field_inits, struct_ty, false);
1387013842}
1387113843
1387213844fn arrayInitEmpty(sema: *Sema, obj_ty: Type) CompileError!Air.Inst.Ref {
......@@ -13936,19 +13908,18 @@ fn zirStructInit(
1393613908 const unresolved_struct_type = try sema.resolveType(block, src, first_field_type_extra.container_type);
1393713909 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) {
1394013912 // This logic must be synchronized with that in `zirStructInitEmpty`.
13941 const struct_obj = struct_payload.data;
1394213913
1394313914 // Maps field index to field_type index of where it was already initialized.
1394413915 // 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());
1394613917 defer gpa.free(found_fields);
13947 mem.set(Zir.Inst.Index, found_fields, 0);
1394813918
1394913919 // 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());
1395113921 defer gpa.free(field_inits);
13922 mem.set(Air.Inst.Ref, field_inits, .none);
1395213923
1395313924 var field_i: u32 = 0;
1395413925 var extra_index = extra.end;
......@@ -13961,9 +13932,8 @@ fn zirStructInit(
1396113932 const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_type_data.src_node };
1396213933 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
1396313934 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
13964 const field_index = struct_obj.fields.getIndex(field_name) orelse
13965 return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);
13966 if (found_fields[field_index] != 0) {
13935 const field_index = try sema.structFieldIndex(block, resolved_ty, field_name, field_src);
13936 if (field_inits[field_index] != .none) {
1396713937 const other_field_type = found_fields[field_index];
1396813938 const other_field_type_data = zir_datas[other_field_type].pl_node;
1396913939 const other_field_src: LazySrcLoc = .{ .node_offset_back2tok = other_field_type_data.src_node };
......@@ -13979,27 +13949,7 @@ fn zirStructInit(
1397913949 field_inits[field_index] = try sema.resolveInst(item.data.init);
1398013950 }
1398113951
13982 var root_msg: ?*Module.ErrorMsg = null;
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);
13952 return sema.finishStructInit(block, src, src, field_inits, resolved_ty, is_ref);
1400313953 } else if (resolved_ty.zigTypeTag() == .Union) {
1400413954 if (extra.data.fields_len != 1) {
1400513955 return sema.fail(block, src, "union initialization expects exactly one field", .{});
......@@ -14051,29 +14001,69 @@ fn zirStructInit(
1405114001fn finishStructInit(
1405214002 sema: *Sema,
1405314003 block: *Block,
14054 src: LazySrcLoc,
14055 field_inits: []const Air.Inst.Ref,
14056 root_msg: ?*Module.ErrorMsg,
14057 struct_obj: *Module.Struct,
14004 init_src: LazySrcLoc,
14005 dest_src: LazySrcLoc,
14006 field_inits: []Air.Inst.Ref,
1405814007 struct_ty: Type,
1405914008 is_ref: bool,
14060) !Air.Inst.Ref {
14009) CompileError!Air.Inst.Ref {
1406114010 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
1406314051 if (root_msg) |msg| {
14064 const fqn = try struct_obj.getFullyQualifiedName(sema.mod);
14065 defer gpa.free(fqn);
14066 try sema.mod.errNoteNonLazy(
14067 struct_obj.srcLoc(sema.mod),
14068 msg,
14069 "struct '{s}' declared here",
14070 .{fqn},
14071 );
14052 if (struct_ty.castTag(.@"struct")) |struct_obj| {
14053 const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);
14054 defer gpa.free(fqn);
14055 try sema.mod.errNoteNonLazy(
14056 struct_obj.data.srcLoc(sema.mod),
14057 msg,
14058 "struct '{s}' declared here",
14059 .{fqn},
14060 );
14061 }
1407214062 return sema.failWithOwnedErrorMsg(block, msg);
1407314063 }
1407414064
1407514065 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))) {
1407714067 break false;
1407814068 }
1407914069 } else true;
......@@ -14081,10 +14071,10 @@ fn finishStructInit(
1408114071 if (is_comptime) {
1408214072 const values = try sema.arena.alloc(Value, field_inits.len);
1408314073 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).?;
1408514075 }
1408614076 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);
1408814078 }
1408914079
1409014080 if (is_ref) {
......@@ -14096,15 +14086,15 @@ fn finishStructInit(
1409614086 const alloc = try block.addTy(.alloc, alloc_ty);
1409714087 for (field_inits) |field_init, i_usize| {
1409814088 const i = @intCast(u32, i_usize);
14099 const field_src = src;
14100 const field_ptr = try sema.structFieldPtrByIndex(block, src, alloc, i, struct_obj, field_src);
14101 try sema.storePtr(block, src, field_ptr, field_init);
14089 const field_src = dest_src;
14090 const field_ptr = try sema.structFieldPtrByIndex(block, dest_src, alloc, i, field_src, struct_ty);
14091 try sema.storePtr(block, dest_src, field_ptr, field_init);
1410214092 }
1410314093
1410414094 return alloc;
1410514095 }
1410614096
14107 try sema.requireRuntimeBlock(block, src);
14097 try sema.requireRuntimeBlock(block, dest_src);
1410814098 try sema.queueFullTypeResolution(struct_ty);
1410914099 return block.addAggregateInit(struct_ty, field_inits);
1411014100}
......@@ -15872,7 +15862,8 @@ fn zirOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1587215862
1587315863fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u64 {
1587415864 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;
1587615867 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
1587715868 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
1587815869 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
1588215873 const target = sema.mod.getTarget();
1588315874
1588415875 try sema.resolveTypeLayout(block, lhs_src, ty);
15885 if (ty.tag() != .@"struct") {
15886 const msg = msg: {
15887 const msg = try sema.errMsg(block, lhs_src, "expected struct type, found '{}'", .{ty.fmt(sema.mod)});
15888 errdefer msg.destroy(sema.gpa);
15889 try sema.addDeclaredHereNote(msg, ty);
15890 break :msg msg;
15891 };
15892 return sema.failWithOwnedErrorMsg(block, msg);
15876 switch (ty.tag()) {
15877 .@"struct", .tuple, .anon_struct => {},
15878 else => {
15879 const msg = msg: {
15880 const msg = try sema.errMsg(block, lhs_src, "expected struct type, found '{}'", .{ty.fmt(sema.mod)});
15881 errdefer msg.destroy(sema.gpa);
15882 try sema.addDeclaredHereNote(msg, ty);
15883 break :msg msg;
15884 };
15885 return sema.failWithOwnedErrorMsg(block, msg);
15886 },
1589315887 }
1589415888
15895 const fields = ty.structFields();
15896 const index = fields.getIndex(field_name) orelse {
15897 const msg = msg: {
15898 const msg = try sema.errMsg(
15899 block,
15900 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 };
15889 const field_index = if (ty.isTuple()) blk: {
15890 if (mem.eql(u8, field_name, "len")) {
15891 return sema.fail(block, src, "no offset available for 'len' field of tuple", .{});
15892 }
15893 break :blk try sema.tupleFieldIndex(block, ty, field_name, rhs_src);
15894 } else try sema.structFieldIndex(block, ty, field_name, rhs_src);
1591015895
1591115896 switch (ty.containerLayout()) {
1591215897 .Packed => {
1591315898 var bit_sum: u64 = 0;
15899 const fields = ty.structFields();
1591415900 for (fields.values()) |field, i| {
15915 if (i == index) {
15901 if (i == field_index) {
1591615902 return bit_sum;
1591715903 }
1591815904 bit_sum += field.ty.bitSize(target);
1591915905 } else unreachable;
1592015906 },
15921 else => {
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 },
15907 else => return ty.structFieldOffset(field_index, target) * 8,
1592915908 }
1593015909}
1593115910
......@@ -17193,24 +17172,28 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
1719317172 }
1719417173 try sema.resolveTypeLayout(block, ty_src, struct_ty);
1719517174
17196 const struct_obj = struct_ty.castTag(.@"struct").?.data;
17197 const field_index = struct_obj.fields.getIndex(field_name) orelse
17198 return sema.failWithBadStructFieldAccess(block, struct_obj, name_src, field_name);
17175 const field_index = if (struct_ty.isTuple()) blk: {
17176 if (mem.eql(u8, field_name, "len")) {
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
1720017182 try sema.checkPtrOperand(block, ptr_src, field_ptr_ty);
17201 const field = struct_obj.fields.values()[field_index];
1720217183 const field_ptr_ty_info = field_ptr_ty.ptrInfo().data;
1720317184
1720417185 var ptr_ty_data: Type.Payload.Pointer.Data = .{
17205 .pointee_type = field.ty,
17186 .pointee_type = struct_ty.structFieldType(field_index),
1720617187 .mutable = field_ptr_ty_info.mutable,
1720717188 .@"addrspace" = field_ptr_ty_info.@"addrspace",
1720817189 };
1720917190
17210 if (struct_obj.layout == .Packed) {
17191 if (struct_ty.containerLayout() == .Packed) {
1721117192 return sema.fail(block, src, "TODO handle packed structs with @fieldParentPtr", .{});
1721217193 } 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;
1721417197 }
1721517198
1721617199 const actual_field_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_ty_data);
......@@ -19059,7 +19042,7 @@ fn structFieldPtr(
1905919042 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name);
1906019043 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);
1906319046}
1906419047
1906519048fn structFieldPtrByIndex(
......@@ -19068,9 +19051,14 @@ fn structFieldPtrByIndex(
1906819051 src: LazySrcLoc,
1906919052 struct_ptr: Air.Inst.Ref,
1907019053 field_index: u32,
19071 struct_obj: *Module.Struct,
1907219054 field_src: LazySrcLoc,
19055 struct_ty: Type,
1907319056) 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;
1907419062 const field = struct_obj.fields.values()[field_index];
1907519063 const struct_ptr_ty = sema.typeOf(struct_ptr);
1907619064 const struct_ptr_ty_info = struct_ptr_ty.ptrInfo().data;
......@@ -19231,17 +19219,13 @@ fn tupleFieldIndex(
1923119219 field_name: []const u8,
1923219220 field_name_src: LazySrcLoc,
1923319221) CompileError!u32 {
19234 const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch |err| {
19235 return sema.fail(block, field_name_src, "tuple '{}' has no such field '{s}': {s}", .{
19236 tuple_ty.fmt(sema.mod), field_name, @errorName(err),
19237 });
19238 };
19239 if (field_index >= tuple_ty.structFieldCount()) {
19240 return sema.fail(block, field_name_src, "tuple '{}' has no such field '{s}'", .{
19241 tuple_ty.fmt(sema.mod), field_name,
19242 });
19243 }
19244 return field_index;
19222 if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| {
19223 if (field_index < tuple_ty.structFieldCount()) return field_index;
19224 } else |_| {}
19225
19226 return sema.fail(block, field_name_src, "no field named '{s}' in tuple '{}'", .{
19227 field_name, tuple_ty.fmt(sema.mod),
19228 });
1924519229}
1924619230
1924719231fn tupleFieldValByIndex(
......@@ -20356,7 +20340,7 @@ fn coerce(
2035620340 },
2035720341 .Struct => {
2035820342 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);
2036020344 }
2036120345 if (inst_ty.isTupleOrAnonStruct()) {
2036220346 return sema.coerceTupleToStruct(block, dest_ty, dest_ty_src, inst, inst_src);
......@@ -25754,10 +25738,14 @@ fn structFieldIndex(
2575425738 field_src: LazySrcLoc,
2575525739) !u32 {
2575625740 const struct_ty = try sema.resolveTypeFields(block, field_src, unresolved_struct_ty);
25757 const struct_obj = struct_ty.castTag(.@"struct").?.data;
25758 const field_index_usize = struct_obj.fields.getIndex(field_name) orelse
25759 return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);
25760 return @intCast(u32, field_index_usize);
25741 if (struct_ty.isAnonStruct()) {
25742 return sema.anonStructFieldIndex(block, struct_ty, field_name, field_src);
25743 } else {
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 }
2576125749}
2576225750
2576325751fn anonStructFieldIndex(
......@@ -25773,8 +25761,8 @@ fn anonStructFieldIndex(
2577325761 return @intCast(u32, i);
2577425762 }
2577525763 }
25776 return sema.fail(block, field_src, "anonymous struct '{}' has no such field '{s}'", .{
25777 struct_ty.fmt(sema.mod), field_name,
25764 return sema.fail(block, field_src, "no field named '{s}' in anonymous struct '{}'", .{
25765 field_name, struct_ty.fmt(sema.mod),
2577825766 });
2577925767}
2578025768
src/type.zig+18
......@@ -5432,6 +5432,24 @@ pub const Type = extern union {
54325432 }
54335433 }
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
54355453 pub fn structFieldValueComptime(ty: Type, index: usize) ?Value {
54365454 switch (ty.tag()) {
54375455 .@"struct" => {
test/behavior/tuple.zig+58
......@@ -197,3 +197,61 @@ test "initializing tuple with explicit type" {
197197 var a = T{ 0, 0 };
198198 _ = a;
199199}
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 {
99// backend=stage2
1010// target=native
1111//
12// :5:27: error: struct 'tmp.Foo' has no field 'a'
12// :5:27: error: no field named 'a' in struct 'tmp.Foo'
1313// :1:13: note: struct declared here