authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-11-22 01:19:50+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-11-23 12:13:39+02:00
logd5da2a6114926fae44f31eeab0706578f090dca8
treeb2a561651f35aae2dd934f43690e0311c95db0c6
parent80575face7a3b1e0f47e413507a6fa8b1d002e57

Sema: implement tuple declarations


6 files changed, 128 insertions(+), 176 deletions(-)

src/Module.zig+5
......@@ -938,6 +938,7 @@ pub const Struct = struct {
938938 known_non_opv: bool,
939939 requires_comptime: PropertyBoolean = .unknown,
940940 have_field_inits: bool = false,
941 is_tuple: bool,
941942
942943 pub const Fields = std.StringArrayHashMapUnmanaged(Field);
943944
......@@ -4458,6 +4459,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
44584459 .layout = .Auto,
44594460 .status = .none,
44604461 .known_non_opv = undefined,
4462 .is_tuple = undefined, // set below
44614463 .namespace = .{
44624464 .parent = null,
44634465 .ty = struct_ty,
......@@ -4489,6 +4491,9 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
44894491 assert(file.zir_loaded);
44904492 const main_struct_inst = Zir.main_struct_inst;
44914493 struct_obj.zir_index = main_struct_inst;
4494 const extended = file.zir.instructions.items(.data)[main_struct_inst].extended;
4495 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
4496 struct_obj.is_tuple = small.is_tuple;
44924497
44934498 var sema_arena = std.heap.ArenaAllocator.init(gpa);
44944499 defer sema_arena.deinit();
src/Sema.zig+96-163
......@@ -2519,6 +2519,7 @@ fn zirStructDecl(
25192519 .layout = small.layout,
25202520 .status = .none,
25212521 .known_non_opv = undefined,
2522 .is_tuple = small.is_tuple,
25222523 .namespace = .{
25232524 .parent = block.namespace,
25242525 .ty = struct_ty,
......@@ -4291,13 +4292,12 @@ fn zirValidateArrayInit(
42914292
42924293 if (instrs.len != array_len) switch (array_ty.zigTypeTag()) {
42934294 .Struct => {
4294 const struct_obj = array_ty.castTag(.tuple).?.data;
42954295 var root_msg: ?*Module.ErrorMsg = null;
42964296 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
42974297
4298 for (struct_obj.values) |default_val, i| {
4299 if (i < instrs.len) continue;
4300
4298 var i = instrs.len;
4299 while (i < array_len) : (i += 1) {
4300 const default_val = array_ty.structFieldDefaultValue(i);
43014301 if (default_val.tag() == .unreachable_value) {
43024302 const template = "missing tuple field with index {d}";
43034303 if (root_msg) |msg| {
......@@ -7230,7 +7230,7 @@ fn instantiateGenericCall(
72307230}
72317231
72327232fn resolveTupleLazyValues(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void {
7233 if (!ty.isTuple()) return;
7233 if (!ty.isSimpleTuple()) return;
72347234 const tuple = ty.tupleFields();
72357235 for (tuple.values) |field_val, i| {
72367236 try sema.resolveTupleLazyValues(block, src, tuple.types[i]);
......@@ -7295,7 +7295,7 @@ fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
72957295 const indexable_ty = try sema.resolveType(block, .unneeded, bin.lhs);
72967296 assert(indexable_ty.isIndexable()); // validated by a previous instruction
72977297 if (indexable_ty.zigTypeTag() == .Struct) {
7298 const elem_type = indexable_ty.tupleFields().types[@enumToInt(bin.rhs)];
7298 const elem_type = indexable_ty.structFieldType(@enumToInt(bin.rhs));
72997299 return sema.addType(elem_type);
73007300 } else {
73017301 const elem_type = indexable_ty.elemType2();
......@@ -11827,9 +11827,9 @@ fn analyzeTupleCat(
1182711827 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node };
1182811828 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node };
1182911829
11830 const lhs_tuple = lhs_ty.tupleFields();
11831 const rhs_tuple = rhs_ty.tupleFields();
11832 const dest_fields = lhs_tuple.types.len + rhs_tuple.types.len;
11830 const lhs_len = lhs_ty.structFieldCount();
11831 const rhs_len = rhs_ty.structFieldCount();
11832 const dest_fields = lhs_len + rhs_len;
1183311833
1183411834 if (dest_fields == 0) {
1183511835 return sema.addConstant(Type.initTag(.empty_struct_literal), Value.initTag(.empty_struct_value));
......@@ -11841,20 +11841,23 @@ fn analyzeTupleCat(
1184111841
1184211842 const opt_runtime_src = rs: {
1184311843 var runtime_src: ?LazySrcLoc = null;
11844 for (lhs_tuple.types) |ty, i| {
11845 types[i] = ty;
11846 values[i] = lhs_tuple.values[i];
11844 var i: u32 = 0;
11845 while (i < lhs_len) : (i += 1) {
11846 types[i] = lhs_ty.structFieldType(i);
11847 const default_val = lhs_ty.structFieldDefaultValue(i);
11848 values[i] = default_val;
1184711849 const operand_src = lhs_src; // TODO better source location
11848 if (values[i].tag() == .unreachable_value) {
11850 if (default_val.tag() == .unreachable_value) {
1184911851 runtime_src = operand_src;
1185011852 }
1185111853 }
11852 const offset = lhs_tuple.types.len;
11853 for (rhs_tuple.types) |ty, i| {
11854 types[i + offset] = ty;
11855 values[i + offset] = rhs_tuple.values[i];
11854 i = 0;
11855 while (i < rhs_len) : (i += 1) {
11856 types[i + lhs_len] = rhs_ty.structFieldType(i);
11857 const default_val = rhs_ty.structFieldDefaultValue(i);
11858 values[i + lhs_len] = default_val;
1185611859 const operand_src = rhs_src; // TODO better source location
11857 if (rhs_tuple.values[i].tag() == .unreachable_value) {
11860 if (default_val.tag() == .unreachable_value) {
1185811861 runtime_src = operand_src;
1185911862 }
1186011863 }
......@@ -11874,14 +11877,15 @@ fn analyzeTupleCat(
1187411877 try sema.requireRuntimeBlock(block, src, runtime_src);
1187511878
1187611879 const element_refs = try sema.arena.alloc(Air.Inst.Ref, final_len);
11877 for (lhs_tuple.types) |_, i| {
11880 var i: u32 = 0;
11881 while (i < lhs_len) : (i += 1) {
1187811882 const operand_src = lhs_src; // TODO better source location
1187911883 element_refs[i] = try sema.tupleFieldValByIndex(block, operand_src, lhs, @intCast(u32, i), lhs_ty);
1188011884 }
11881 const offset = lhs_tuple.types.len;
11882 for (rhs_tuple.types) |_, i| {
11885 i = 0;
11886 while (i < rhs_len) : (i += 1) {
1188311887 const operand_src = rhs_src; // TODO better source location
11884 element_refs[i + offset] =
11888 element_refs[i + lhs_len] =
1188511889 try sema.tupleFieldValByIndex(block, operand_src, rhs, @intCast(u32, i), rhs_ty);
1188611890 }
1188711891
......@@ -12107,12 +12111,11 @@ fn analyzeTupleMul(
1210712111 factor: u64,
1210812112) CompileError!Air.Inst.Ref {
1210912113 const operand_ty = sema.typeOf(operand);
12110 const operand_tuple = operand_ty.tupleFields();
1211112114 const src = LazySrcLoc.nodeOffset(src_node);
1211212115 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node };
1211312116 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node };
1211412117
12115 const tuple_len = operand_tuple.types.len;
12118 const tuple_len = operand_ty.structFieldCount();
1211612119 const final_len_u64 = std.math.mul(u64, tuple_len, factor) catch
1211712120 return sema.fail(block, rhs_src, "operation results in overflow", .{});
1211812121
......@@ -12126,18 +12129,19 @@ fn analyzeTupleMul(
1212612129
1212712130 const opt_runtime_src = rs: {
1212812131 var runtime_src: ?LazySrcLoc = null;
12129 for (operand_tuple.types) |ty, i| {
12130 types[i] = ty;
12131 values[i] = operand_tuple.values[i];
12132 var i: u32 = 0;
12133 while (i < tuple_len) : (i += 1) {
12134 types[i] = operand_ty.structFieldType(i);
12135 values[i] = operand_ty.structFieldDefaultValue(i);
1213212136 const operand_src = lhs_src; // TODO better source location
1213312137 if (values[i].tag() == .unreachable_value) {
1213412138 runtime_src = operand_src;
1213512139 }
1213612140 }
12137 var i: usize = 1;
12141 i = 0;
1213812142 while (i < factor) : (i += 1) {
12139 mem.copy(Type, types[tuple_len * i ..], operand_tuple.types);
12140 mem.copy(Value, values[tuple_len * i ..], operand_tuple.values);
12143 mem.copy(Type, types[tuple_len * i ..], types[0..tuple_len]);
12144 mem.copy(Value, values[tuple_len * i ..], values[0..tuple_len]);
1214112145 }
1214212146 break :rs runtime_src;
1214312147 };
......@@ -12155,11 +12159,12 @@ fn analyzeTupleMul(
1215512159 try sema.requireRuntimeBlock(block, src, runtime_src);
1215612160
1215712161 const element_refs = try sema.arena.alloc(Air.Inst.Ref, final_len);
12158 for (operand_tuple.types) |_, i| {
12162 var i: u32 = 0;
12163 while (i < tuple_len) : (i += 1) {
1215912164 const operand_src = lhs_src; // TODO better source location
1216012165 element_refs[i] = try sema.tupleFieldValByIndex(block, operand_src, operand, @intCast(u32, i), operand_ty);
1216112166 }
12162 var i: usize = 1;
12167 i = 1;
1216312168 while (i < factor) : (i += 1) {
1216412169 mem.copy(Air.Inst.Ref, element_refs[tuple_len * i ..], element_refs[0..tuple_len]);
1216512170 }
......@@ -15593,7 +15598,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1559315598 const layout = struct_ty.containerLayout();
1559415599
1559515600 const struct_field_vals = fv: {
15596 if (struct_ty.isTupleOrAnonStruct()) {
15601 if (struct_ty.isSimpleTupleOrAnonStruct()) {
1559715602 const tuple = struct_ty.tupleFields();
1559815603 const field_types = tuple.types;
1559915604 const struct_field_vals = try fields_anon_decl.arena().alloc(Value, field_types.len);
......@@ -17063,10 +17068,12 @@ fn finishStructInit(
1706317068 }
1706417069 }
1706517070 } else if (struct_ty.isTuple()) {
17066 const struct_obj = struct_ty.castTag(.tuple).?.data;
17067 for (struct_obj.values) |default_val, i| {
17071 var i: u32 = 0;
17072 const len = struct_ty.structFieldCount();
17073 while (i < len) : (i += 1) {
1706817074 if (field_inits[i] != .none) continue;
1706917075
17076 const default_val = struct_ty.structFieldDefaultValue(i);
1707017077 if (default_val.tag() == .unreachable_value) {
1707117078 const template = "missing tuple field with index {d}";
1707217079 if (root_msg) |msg| {
......@@ -17075,7 +17082,7 @@ fn finishStructInit(
1707517082 root_msg = try sema.errMsg(block, init_src, template, .{i});
1707617083 }
1707717084 } else {
17078 field_inits[i] = try sema.addConstant(struct_obj.types[i], default_val);
17085 field_inits[i] = try sema.addConstant(struct_ty.structFieldType(i), default_val);
1707917086 }
1708017087 }
1708117088 } else {
......@@ -17297,7 +17304,7 @@ fn zirArrayInit(
1729717304 const resolved_arg = try sema.resolveInst(arg);
1729817305 const arg_src = src; // TODO better source location
1729917306 const elem_ty = if (array_ty.zigTypeTag() == .Struct)
17300 array_ty.tupleFields().types[i]
17307 array_ty.structFieldType(i)
1730117308 else
1730217309 array_ty.elemType2();
1730317310 resolved_args[i] = try sema.coerce(block, elem_ty, resolved_arg, arg_src);
......@@ -17337,12 +17344,11 @@ fn zirArrayInit(
1733717344 const alloc = try block.addTy(.alloc, alloc_ty);
1733817345
1733917346 if (array_ty.isTuple()) {
17340 const types = array_ty.tupleFields().types;
1734117347 for (resolved_args) |arg, i| {
1734217348 const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
1734317349 .mutable = true,
1734417350 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
17345 .pointee_type = types[i],
17351 .pointee_type = array_ty.structFieldType(i),
1734617352 });
1734717353 const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty);
1734817354
......@@ -18015,10 +18021,7 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
1801518021 return sema.fail(block, src, "non-packed struct does not support backing integer type", .{});
1801618022 }
1801718023
18018 return if (is_tuple_val.toBool())
18019 try sema.reifyTuple(block, src, fields_val)
18020 else
18021 try sema.reifyStruct(block, inst, src, layout, backing_int_val, fields_val, name_strategy);
18024 return try sema.reifyStruct(block, inst, src, layout, backing_int_val, fields_val, name_strategy, is_tuple_val.toBool());
1802218025 },
1802318026 .Enum => {
1802418027 const struct_val: []const Value = union_val.val.castTag(.aggregate).?.data;
......@@ -18432,84 +18435,6 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
1843218435 }
1843318436}
1843418437
18435fn reifyTuple(
18436 sema: *Sema,
18437 block: *Block,
18438 src: LazySrcLoc,
18439 fields_val: Value,
18440) CompileError!Air.Inst.Ref {
18441 const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(sema.mod));
18442 if (fields_len == 0) return sema.addType(Type.initTag(.empty_struct_literal));
18443
18444 const types = try sema.arena.alloc(Type, fields_len);
18445 const values = try sema.arena.alloc(Value, fields_len);
18446
18447 var used_fields: std.AutoArrayHashMapUnmanaged(u32, void) = .{};
18448 defer used_fields.deinit(sema.gpa);
18449 try used_fields.ensureTotalCapacity(sema.gpa, fields_len);
18450
18451 var i: usize = 0;
18452 while (i < fields_len) : (i += 1) {
18453 const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i);
18454 const field_struct_val = elem_val.castTag(.aggregate).?.data;
18455 // TODO use reflection instead of magic numbers here
18456 // name: []const u8
18457 const name_val = field_struct_val[0];
18458 // field_type: type,
18459 const field_type_val = field_struct_val[1];
18460 //default_value: ?*const anyopaque,
18461 const default_value_val = field_struct_val[2];
18462
18463 const field_name = try name_val.toAllocatedBytes(
18464 Type.initTag(.const_slice_u8),
18465 sema.arena,
18466 sema.mod,
18467 );
18468
18469 const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch |err| {
18470 return sema.fail(
18471 block,
18472 src,
18473 "tuple cannot have non-numeric field '{s}': {}",
18474 .{ field_name, err },
18475 );
18476 };
18477
18478 if (field_index >= fields_len) {
18479 return sema.fail(
18480 block,
18481 src,
18482 "tuple field {} exceeds tuple field count",
18483 .{field_index},
18484 );
18485 }
18486
18487 const gop = used_fields.getOrPutAssumeCapacity(field_index);
18488 if (gop.found_existing) {
18489 // TODO: better source location
18490 return sema.fail(block, src, "duplicate tuple field {}", .{field_index});
18491 }
18492
18493 const default_val = if (default_value_val.optionalValue()) |opt_val| blk: {
18494 const payload_val = if (opt_val.pointerDecl()) |opt_decl|
18495 sema.mod.declPtr(opt_decl).val
18496 else
18497 opt_val;
18498 break :blk try payload_val.copy(sema.arena);
18499 } else Value.initTag(.unreachable_value);
18500
18501 var buffer: Value.ToTypeBuffer = undefined;
18502 types[field_index] = try field_type_val.toType(&buffer).copy(sema.arena);
18503 values[field_index] = default_val;
18504 }
18505
18506 const ty = try Type.Tag.tuple.create(sema.arena, .{
18507 .types = types,
18508 .values = values,
18509 });
18510 return sema.addType(ty);
18511}
18512
1851318438fn reifyStruct(
1851418439 sema: *Sema,
1851518440 block: *Block,
......@@ -18519,6 +18444,7 @@ fn reifyStruct(
1851918444 backing_int_val: Value,
1852018445 fields_val: Value,
1852118446 name_strategy: Zir.Inst.NameStrategy,
18447 is_tuple: bool,
1852218448) CompileError!Air.Inst.Ref {
1852318449 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
1852418450 errdefer new_decl_arena.deinit();
......@@ -18542,6 +18468,7 @@ fn reifyStruct(
1854218468 .layout = layout,
1854318469 .status = .have_field_types,
1854418470 .known_non_opv = false,
18471 .is_tuple = is_tuple,
1854518472 .namespace = .{
1854618473 .parent = block.namespace,
1854718474 .ty = struct_ty,
......@@ -23201,6 +23128,7 @@ fn structFieldVal(
2320123128 },
2320223129 .@"struct" => {
2320323130 const struct_obj = struct_ty.castTag(.@"struct").?.data;
23131 if (struct_obj.is_tuple) return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty);
2320423132
2320523133 const field_index_usize = struct_obj.fields.getIndex(field_name) orelse
2320623134 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name);
......@@ -23273,11 +23201,10 @@ fn tupleFieldValByIndex(
2327323201 field_index: u32,
2327423202 tuple_ty: Type,
2327523203) CompileError!Air.Inst.Ref {
23276 const tuple = tuple_ty.tupleFields();
23277 const field_ty = tuple.types[field_index];
23204 const field_ty = tuple_ty.structFieldType(field_index);
2327823205
23279 if (tuple.values[field_index].tag() != .unreachable_value) {
23280 return sema.addConstant(field_ty, tuple.values[field_index]);
23206 if (tuple_ty.structFieldValueComptime(field_index)) |default_value| {
23207 return sema.addConstant(field_ty, default_value);
2328123208 }
2328223209
2328323210 if (try sema.resolveMaybeUndefVal(tuple_byval)) |tuple_val| {
......@@ -23625,19 +23552,20 @@ fn tupleFieldPtr(
2362523552) CompileError!Air.Inst.Ref {
2362623553 const tuple_ptr_ty = sema.typeOf(tuple_ptr);
2362723554 const tuple_ty = tuple_ptr_ty.childType();
23628 const tuple_fields = tuple_ty.tupleFields();
23555 _ = try sema.resolveTypeFields(tuple_ty);
23556 const field_count = tuple_ty.structFieldCount();
2362923557
23630 if (tuple_fields.types.len == 0) {
23558 if (field_count == 0) {
2363123559 return sema.fail(block, tuple_ptr_src, "indexing into empty tuple is not allowed", .{});
2363223560 }
2363323561
23634 if (field_index >= tuple_fields.types.len) {
23562 if (field_index >= field_count) {
2363523563 return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{
23636 field_index, tuple_fields.types.len,
23564 field_index, field_count,
2363723565 });
2363823566 }
2363923567
23640 const field_ty = tuple_fields.types[field_index];
23568 const field_ty = tuple_ty.structFieldType(field_index);
2364123569 const ptr_field_ty = try Type.ptr(sema.arena, sema.mod, .{
2364223570 .pointee_type = field_ty,
2364323571 .mutable = tuple_ptr_ty.ptrIsMutable(),
......@@ -23680,24 +23608,23 @@ fn tupleField(
2368023608 field_index_src: LazySrcLoc,
2368123609 field_index: u32,
2368223610) CompileError!Air.Inst.Ref {
23683 const tuple_ty = sema.typeOf(tuple);
23684 const tuple_fields = tuple_ty.tupleFields();
23611 const tuple_ty = try sema.resolveTypeFields(sema.typeOf(tuple));
23612 const field_count = tuple_ty.structFieldCount();
2368523613
23686 if (tuple_fields.types.len == 0) {
23614 if (field_count == 0) {
2368723615 return sema.fail(block, tuple_src, "indexing into empty tuple is not allowed", .{});
2368823616 }
2368923617
23690 if (field_index >= tuple_fields.types.len) {
23618 if (field_index >= field_count) {
2369123619 return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{
23692 field_index, tuple_fields.types.len,
23620 field_index, field_count,
2369323621 });
2369423622 }
2369523623
23696 const field_ty = tuple_fields.types[field_index];
23697 const field_val = tuple_fields.values[field_index];
23624 const field_ty = tuple_ty.structFieldType(field_index);
2369823625
23699 if (field_val.tag() != .unreachable_value) {
23700 return sema.addConstant(field_ty, field_val); // comptime field
23626 if (tuple_ty.structFieldValueComptime(field_index)) |default_value| {
23627 return sema.addConstant(field_ty, default_value); // comptime field
2370123628 }
2370223629
2370323630 if (try sema.resolveMaybeUndefVal(tuple)) |tuple_val| {
......@@ -24277,7 +24204,7 @@ fn coerceExtra(
2427724204
2427824205 // empty tuple to zero-length slice
2427924206 // note that this allows coercing to a mutable slice.
24280 if (inst_child_ty.tupleFields().types.len == 0) {
24207 if (inst_child_ty.structFieldCount() == 0) {
2428124208 const slice_val = try Value.Tag.slice.create(sema.arena, .{
2428224209 .ptr = Value.undef,
2428324210 .len = Value.zero,
......@@ -25587,9 +25514,9 @@ fn storePtr2(
2558725514 // fields.
2558825515 const operand_ty = sema.typeOf(uncasted_operand);
2558925516 if (operand_ty.isTuple() and elem_ty.zigTypeTag() == .Array) {
25590 const tuple = operand_ty.tupleFields();
25591 for (tuple.types) |_, i_usize| {
25592 const i = @intCast(u32, i_usize);
25517 const field_count = operand_ty.structFieldCount();
25518 var i: u32 = 0;
25519 while (i < field_count) : (i += 1) {
2559325520 const elem_src = operand_src; // TODO better source location
2559425521 const elem = try sema.tupleField(block, operand_src, uncasted_operand, elem_src, i);
2559525522 const elem_index = try sema.addIntUnsigned(Type.usize, i);
......@@ -26681,7 +26608,7 @@ fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_resul
2668126608 const inst_info = inst_ty.ptrInfo().data;
2668226609 const len0 = (inst_info.pointee_type.zigTypeTag() == .Array and (inst_info.pointee_type.arrayLenIncludingSentinel() == 0 or
2668326610 (inst_info.pointee_type.arrayLen() == 0 and dest_info.sentinel == null and dest_info.size != .C and dest_info.size != .Many))) or
26684 (inst_info.pointee_type.isTuple() and inst_info.pointee_type.tupleFields().types.len == 0);
26611 (inst_info.pointee_type.isTuple() and inst_info.pointee_type.structFieldCount() == 0);
2668526612
2668626613 const ok_cv_qualifiers =
2668726614 ((inst_info.mutable or !dest_info.mutable) or len0) and
......@@ -27166,18 +27093,18 @@ fn coerceTupleToStruct(
2716627093 mem.set(Air.Inst.Ref, field_refs, .none);
2716727094
2716827095 const inst_ty = sema.typeOf(inst);
27169 const tuple = inst_ty.tupleFields();
2717027096 var runtime_src: ?LazySrcLoc = null;
27171 for (tuple.types) |_, i_usize| {
27172 const i = @intCast(u32, i_usize);
27097 const field_count = struct_ty.structFieldCount();
27098 var field_i: u32 = 0;
27099 while (field_i < field_count) : (field_i += 1) {
2717327100 const field_src = inst_src; // TODO better source location
2717427101 const field_name = if (inst_ty.castTag(.anon_struct)) |payload|
27175 payload.data.names[i]
27102 payload.data.names[field_i]
2717627103 else
27177 try std.fmt.allocPrint(sema.arena, "{d}", .{i});
27104 try std.fmt.allocPrint(sema.arena, "{d}", .{field_i});
2717827105 const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src);
2717927106 const field = fields.values()[field_index];
27180 const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, i);
27107 const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i);
2718127108 const coerced = try sema.coerce(block, field.ty, elem_ref, field_src);
2718227109 field_refs[field_index] = coerced;
2718327110 if (field.is_comptime) {
......@@ -27186,7 +27113,7 @@ fn coerceTupleToStruct(
2718627113 };
2718727114
2718827115 if (!init_val.eql(field.default_val, field.ty, sema.mod)) {
27189 return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, i);
27116 return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i);
2719027117 }
2719127118 }
2719227119 if (runtime_src == null) {
......@@ -27255,15 +27182,14 @@ fn coerceTupleToTuple(
2725527182 mem.set(Air.Inst.Ref, field_refs, .none);
2725627183
2725727184 const inst_ty = sema.typeOf(inst);
27258 const tuple = inst_ty.tupleFields();
2725927185 var runtime_src: ?LazySrcLoc = null;
27260 for (tuple.types) |_, i_usize| {
27261 const i = @intCast(u32, i_usize);
27186 var field_i: u32 = 0;
27187 while (field_i < field_count) : (field_i += 1) {
2726227188 const field_src = inst_src; // TODO better source location
2726327189 const field_name = if (inst_ty.castTag(.anon_struct)) |payload|
27264 payload.data.names[i]
27190 payload.data.names[field_i]
2726527191 else
27266 try std.fmt.allocPrint(sema.arena, "{d}", .{i});
27192 try std.fmt.allocPrint(sema.arena, "{d}", .{field_i});
2726727193
2726827194 if (mem.eql(u8, field_name, "len")) {
2726927195 return sema.fail(block, field_src, "cannot assign to 'len' field of tuple", .{});
......@@ -27271,9 +27197,9 @@ fn coerceTupleToTuple(
2727127197
2727227198 const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_src);
2727327199
27274 const field_ty = tuple_ty.structFieldType(i);
27275 const default_val = tuple_ty.structFieldDefaultValue(i);
27276 const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, i);
27200 const field_ty = tuple_ty.structFieldType(field_i);
27201 const default_val = tuple_ty.structFieldDefaultValue(field_i);
27202 const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i);
2727727203 const coerced = try sema.coerce(block, field_ty, elem_ref, field_src);
2727827204 field_refs[field_index] = coerced;
2727927205 if (default_val.tag() != .unreachable_value) {
......@@ -27282,7 +27208,7 @@ fn coerceTupleToTuple(
2728227208 };
2728327209
2728427210 if (!init_val.eql(default_val, field_ty, sema.mod)) {
27285 return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, i);
27211 return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i);
2728627212 }
2728727213 }
2728827214 if (runtime_src == null) {
......@@ -29665,6 +29591,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
2966529591 block_scope.params.deinit(gpa);
2966629592 }
2966729593
29594 struct_obj.fields = .{};
2966829595 try struct_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len);
2966929596
2967029597 const Field = struct {
......@@ -29699,8 +29626,11 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
2969929626 const has_type_body = @truncate(u1, cur_bit_bag) != 0;
2970029627 cur_bit_bag >>= 1;
2970129628
29702 const field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]);
29703 extra_index += 1;
29629 var field_name_zir: ?[:0]const u8 = null;
29630 if (!small.is_tuple) {
29631 field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]);
29632 extra_index += 1;
29633 }
2970429634 extra_index += 1; // doc_comment
2970529635
2970629636 fields[field_i] = .{};
......@@ -29713,7 +29643,10 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
2971329643 extra_index += 1;
2971429644
2971529645 // This string needs to outlive the ZIR code.
29716 const field_name = try decl_arena_allocator.dupe(u8, field_name_zir);
29646 const field_name = if (field_name_zir) |some|
29647 try decl_arena_allocator.dupe(u8, some)
29648 else
29649 try std.fmt.allocPrint(decl_arena_allocator, "{d}", .{field_i});
2971729650
2971829651 const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);
2971929652 if (gop.found_existing) {
src/codegen/c.zig+1-1
......@@ -1791,7 +1791,7 @@ pub const DeclGen = struct {
17911791 },
17921792 .Struct, .Union => |tag| if (tag == .Struct and t.containerLayout() == .Packed)
17931793 try dg.renderType(w, t.castTag(.@"struct").?.data.backing_int_ty, kind)
1794 else if (t.isTupleOrAnonStruct()) {
1794 else if (t.isSimpleTupleOrAnonStruct()) {
17951795 const ExpectedContents = struct { types: [8]Type, values: [8]Value };
17961796 var stack align(@alignOf(ExpectedContents)) =
17971797 std.heap.stackFallback(@sizeOf(ExpectedContents), dg.gpa);
src/codegen/llvm.zig+5-5
......@@ -1951,7 +1951,7 @@ pub const Object = struct {
19511951 break :blk fwd_decl;
19521952 };
19531953
1954 if (ty.isTupleOrAnonStruct()) {
1954 if (ty.isSimpleTupleOrAnonStruct()) {
19551955 const tuple = ty.tupleFields();
19561956
19571957 var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
......@@ -2885,7 +2885,7 @@ pub const DeclGen = struct {
28852885 // reference, we need to copy it here.
28862886 gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator());
28872887
2888 if (t.isTupleOrAnonStruct()) {
2888 if (t.isSimpleTupleOrAnonStruct()) {
28892889 const tuple = t.tupleFields();
28902890 const llvm_struct_ty = dg.context.structCreateNamed("");
28912891 gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls
......@@ -3579,7 +3579,7 @@ pub const DeclGen = struct {
35793579 const field_vals = tv.val.castTag(.aggregate).?.data;
35803580 const gpa = dg.gpa;
35813581
3582 if (tv.ty.isTupleOrAnonStruct()) {
3582 if (tv.ty.isSimpleTupleOrAnonStruct()) {
35833583 const tuple = tv.ty.tupleFields();
35843584 var llvm_fields: std.ArrayListUnmanaged(*llvm.Value) = .{};
35853585 defer llvm_fields.deinit(gpa);
......@@ -10247,7 +10247,7 @@ fn llvmFieldIndex(
1024710247 var offset: u64 = 0;
1024810248 var big_align: u32 = 0;
1024910249
10250 if (ty.isTupleOrAnonStruct()) {
10250 if (ty.isSimpleTupleOrAnonStruct()) {
1025110251 const tuple = ty.tupleFields();
1025210252 var llvm_field_index: c_uint = 0;
1025310253 for (tuple.types) |field_ty, i| {
......@@ -10810,7 +10810,7 @@ fn isByRef(ty: Type) bool {
1081010810 .Struct => {
1081110811 // Packed structs are represented to LLVM as integers.
1081210812 if (ty.containerLayout() == .Packed) return false;
10813 if (ty.isTupleOrAnonStruct()) {
10813 if (ty.isSimpleTupleOrAnonStruct()) {
1081410814 const tuple = ty.tupleFields();
1081510815 var count: usize = 0;
1081610816 for (tuple.values) |field_val, i| {
src/type.zig+19-5
......@@ -4494,6 +4494,7 @@ pub const Type = extern union {
44944494 .mut_slice,
44954495 .tuple,
44964496 .empty_struct_literal,
4497 .@"struct",
44974498 => return null,
44984499
44994500 .pointer => return self.castTag(.pointer).?.data.sentinel,
......@@ -5571,11 +5572,7 @@ pub const Type = extern union {
55715572
55725573 pub fn structFieldCount(ty: Type) usize {
55735574 switch (ty.tag()) {
5574 .@"struct" => {
5575 const struct_obj = ty.castTag(.@"struct").?.data;
5576 assert(struct_obj.haveFieldTypes());
5577 return struct_obj.fields.count();
5578 },
5575 .@"struct" => return ty.castTag(.@"struct").?.data.fields.count(),
55795576 .empty_struct, .empty_struct_literal => return 0,
55805577 .tuple => return ty.castTag(.tuple).?.data.types.len,
55815578 .anon_struct => return ty.castTag(.anon_struct).?.data.types.len,
......@@ -6178,6 +6175,7 @@ pub const Type = extern union {
61786175 pub fn isTuple(ty: Type) bool {
61796176 return switch (ty.tag()) {
61806177 .tuple, .empty_struct_literal => true,
6178 .@"struct" => ty.castTag(.@"struct").?.data.is_tuple,
61816179 else => false,
61826180 };
61836181 }
......@@ -6190,12 +6188,28 @@ pub const Type = extern union {
61906188 }
61916189
61926190 pub fn isTupleOrAnonStruct(ty: Type) bool {
6191 return switch (ty.tag()) {
6192 .tuple, .empty_struct_literal, .anon_struct => true,
6193 .@"struct" => ty.castTag(.@"struct").?.data.is_tuple,
6194 else => false,
6195 };
6196 }
6197
6198 pub fn isSimpleTuple(ty: Type) bool {
6199 return switch (ty.tag()) {
6200 .tuple, .empty_struct_literal => true,
6201 else => false,
6202 };
6203 }
6204
6205 pub fn isSimpleTupleOrAnonStruct(ty: Type) bool {
61936206 return switch (ty.tag()) {
61946207 .tuple, .empty_struct_literal, .anon_struct => true,
61956208 else => false,
61966209 };
61976210 }
61986211
6212 // Only allowed for simple tuple types
61996213 pub fn tupleFields(ty: Type) Payload.Tuple.Data {
62006214 return switch (ty.tag()) {
62016215 .tuple => ty.castTag(.tuple).?.data,
src/value.zig+2-2
......@@ -2209,7 +2209,7 @@ pub const Value = extern union {
22092209 const b_field_vals = b.castTag(.aggregate).?.data;
22102210 assert(a_field_vals.len == b_field_vals.len);
22112211
2212 if (ty.isTupleOrAnonStruct()) {
2212 if (ty.isSimpleTupleOrAnonStruct()) {
22132213 const types = ty.tupleFields().types;
22142214 assert(types.len == a_field_vals.len);
22152215 for (types) |field_ty, i| {
......@@ -3004,7 +3004,7 @@ pub const Value = extern union {
30043004 .the_only_possible_value => return ty.onePossibleValue().?,
30053005
30063006 .empty_struct_value => {
3007 if (ty.isTupleOrAnonStruct()) {
3007 if (ty.isSimpleTupleOrAnonStruct()) {
30083008 const tuple = ty.tupleFields();
30093009 return tuple.values[index];
30103010 }