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 {...@@ -938,6 +938,7 @@ pub const Struct = struct {
938 known_non_opv: bool,938 known_non_opv: bool,
939 requires_comptime: PropertyBoolean = .unknown,939 requires_comptime: PropertyBoolean = .unknown,
940 have_field_inits: bool = false,940 have_field_inits: bool = false,
941 is_tuple: bool,
941942
942 pub const Fields = std.StringArrayHashMapUnmanaged(Field);943 pub const Fields = std.StringArrayHashMapUnmanaged(Field);
943944
...@@ -4458,6 +4459,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {...@@ -4458,6 +4459,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
4458 .layout = .Auto,4459 .layout = .Auto,
4459 .status = .none,4460 .status = .none,
4460 .known_non_opv = undefined,4461 .known_non_opv = undefined,
4462 .is_tuple = undefined, // set below
4461 .namespace = .{4463 .namespace = .{
4462 .parent = null,4464 .parent = null,
4463 .ty = struct_ty,4465 .ty = struct_ty,
...@@ -4489,6 +4491,9 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {...@@ -4489,6 +4491,9 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
4489 assert(file.zir_loaded);4491 assert(file.zir_loaded);
4490 const main_struct_inst = Zir.main_struct_inst;4492 const main_struct_inst = Zir.main_struct_inst;
4491 struct_obj.zir_index = main_struct_inst;4493 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
4493 var sema_arena = std.heap.ArenaAllocator.init(gpa);4498 var sema_arena = std.heap.ArenaAllocator.init(gpa);
4494 defer sema_arena.deinit();4499 defer sema_arena.deinit();
src/Sema.zig+96-163
...@@ -2519,6 +2519,7 @@ fn zirStructDecl(...@@ -2519,6 +2519,7 @@ fn zirStructDecl(
2519 .layout = small.layout,2519 .layout = small.layout,
2520 .status = .none,2520 .status = .none,
2521 .known_non_opv = undefined,2521 .known_non_opv = undefined,
2522 .is_tuple = small.is_tuple,
2522 .namespace = .{2523 .namespace = .{
2523 .parent = block.namespace,2524 .parent = block.namespace,
2524 .ty = struct_ty,2525 .ty = struct_ty,
...@@ -4291,13 +4292,12 @@ fn zirValidateArrayInit(...@@ -4291,13 +4292,12 @@ fn zirValidateArrayInit(
42914292
4292 if (instrs.len != array_len) switch (array_ty.zigTypeTag()) {4293 if (instrs.len != array_len) switch (array_ty.zigTypeTag()) {
4293 .Struct => {4294 .Struct => {
4294 const struct_obj = array_ty.castTag(.tuple).?.data;
4295 var root_msg: ?*Module.ErrorMsg = null;4295 var root_msg: ?*Module.ErrorMsg = null;
4296 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);4296 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
42974297
4298 for (struct_obj.values) |default_val, i| {4298 var i = instrs.len;
4299 if (i < instrs.len) continue;4299 while (i < array_len) : (i += 1) {
43004300 const default_val = array_ty.structFieldDefaultValue(i);
4301 if (default_val.tag() == .unreachable_value) {4301 if (default_val.tag() == .unreachable_value) {
4302 const template = "missing tuple field with index {d}";4302 const template = "missing tuple field with index {d}";
4303 if (root_msg) |msg| {4303 if (root_msg) |msg| {
...@@ -7230,7 +7230,7 @@ fn instantiateGenericCall(...@@ -7230,7 +7230,7 @@ fn instantiateGenericCall(
7230}7230}
72317231
7232fn resolveTupleLazyValues(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void {7232fn resolveTupleLazyValues(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void {
7233 if (!ty.isTuple()) return;7233 if (!ty.isSimpleTuple()) return;
7234 const tuple = ty.tupleFields();7234 const tuple = ty.tupleFields();
7235 for (tuple.values) |field_val, i| {7235 for (tuple.values) |field_val, i| {
7236 try sema.resolveTupleLazyValues(block, src, tuple.types[i]);7236 try sema.resolveTupleLazyValues(block, src, tuple.types[i]);
...@@ -7295,7 +7295,7 @@ fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr...@@ -7295,7 +7295,7 @@ fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
7295 const indexable_ty = try sema.resolveType(block, .unneeded, bin.lhs);7295 const indexable_ty = try sema.resolveType(block, .unneeded, bin.lhs);
7296 assert(indexable_ty.isIndexable()); // validated by a previous instruction7296 assert(indexable_ty.isIndexable()); // validated by a previous instruction
7297 if (indexable_ty.zigTypeTag() == .Struct) {7297 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));
7299 return sema.addType(elem_type);7299 return sema.addType(elem_type);
7300 } else {7300 } else {
7301 const elem_type = indexable_ty.elemType2();7301 const elem_type = indexable_ty.elemType2();
...@@ -11827,9 +11827,9 @@ fn analyzeTupleCat(...@@ -11827,9 +11827,9 @@ fn analyzeTupleCat(
11827 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node };11827 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node };
11828 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node };11828 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node };
1182911829
11830 const lhs_tuple = lhs_ty.tupleFields();11830 const lhs_len = lhs_ty.structFieldCount();
11831 const rhs_tuple = rhs_ty.tupleFields();11831 const rhs_len = rhs_ty.structFieldCount();
11832 const dest_fields = lhs_tuple.types.len + rhs_tuple.types.len;11832 const dest_fields = lhs_len + rhs_len;
1183311833
11834 if (dest_fields == 0) {11834 if (dest_fields == 0) {
11835 return sema.addConstant(Type.initTag(.empty_struct_literal), Value.initTag(.empty_struct_value));11835 return sema.addConstant(Type.initTag(.empty_struct_literal), Value.initTag(.empty_struct_value));
...@@ -11841,20 +11841,23 @@ fn analyzeTupleCat(...@@ -11841,20 +11841,23 @@ fn analyzeTupleCat(
1184111841
11842 const opt_runtime_src = rs: {11842 const opt_runtime_src = rs: {
11843 var runtime_src: ?LazySrcLoc = null;11843 var runtime_src: ?LazySrcLoc = null;
11844 for (lhs_tuple.types) |ty, i| {11844 var i: u32 = 0;
11845 types[i] = ty;11845 while (i < lhs_len) : (i += 1) {
11846 values[i] = lhs_tuple.values[i];11846 types[i] = lhs_ty.structFieldType(i);
11847 const default_val = lhs_ty.structFieldDefaultValue(i);
11848 values[i] = default_val;
11847 const operand_src = lhs_src; // TODO better source location11849 const operand_src = lhs_src; // TODO better source location
11848 if (values[i].tag() == .unreachable_value) {11850 if (default_val.tag() == .unreachable_value) {
11849 runtime_src = operand_src;11851 runtime_src = operand_src;
11850 }11852 }
11851 }11853 }
11852 const offset = lhs_tuple.types.len;11854 i = 0;
11853 for (rhs_tuple.types) |ty, i| {11855 while (i < rhs_len) : (i += 1) {
11854 types[i + offset] = ty;11856 types[i + lhs_len] = rhs_ty.structFieldType(i);
11855 values[i + offset] = rhs_tuple.values[i];11857 const default_val = rhs_ty.structFieldDefaultValue(i);
11858 values[i + lhs_len] = default_val;
11856 const operand_src = rhs_src; // TODO better source location11859 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) {
11858 runtime_src = operand_src;11861 runtime_src = operand_src;
11859 }11862 }
11860 }11863 }
...@@ -11874,14 +11877,15 @@ fn analyzeTupleCat(...@@ -11874,14 +11877,15 @@ fn analyzeTupleCat(
11874 try sema.requireRuntimeBlock(block, src, runtime_src);11877 try sema.requireRuntimeBlock(block, src, runtime_src);
1187511878
11876 const element_refs = try sema.arena.alloc(Air.Inst.Ref, final_len);11879 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) {
11878 const operand_src = lhs_src; // TODO better source location11882 const operand_src = lhs_src; // TODO better source location
11879 element_refs[i] = try sema.tupleFieldValByIndex(block, operand_src, lhs, @intCast(u32, i), lhs_ty);11883 element_refs[i] = try sema.tupleFieldValByIndex(block, operand_src, lhs, @intCast(u32, i), lhs_ty);
11880 }11884 }
11881 const offset = lhs_tuple.types.len;11885 i = 0;
11882 for (rhs_tuple.types) |_, i| {11886 while (i < rhs_len) : (i += 1) {
11883 const operand_src = rhs_src; // TODO better source location11887 const operand_src = rhs_src; // TODO better source location
11884 element_refs[i + offset] =11888 element_refs[i + lhs_len] =
11885 try sema.tupleFieldValByIndex(block, operand_src, rhs, @intCast(u32, i), rhs_ty);11889 try sema.tupleFieldValByIndex(block, operand_src, rhs, @intCast(u32, i), rhs_ty);
11886 }11890 }
1188711891
...@@ -12107,12 +12111,11 @@ fn analyzeTupleMul(...@@ -12107,12 +12111,11 @@ fn analyzeTupleMul(
12107 factor: u64,12111 factor: u64,
12108) CompileError!Air.Inst.Ref {12112) CompileError!Air.Inst.Ref {
12109 const operand_ty = sema.typeOf(operand);12113 const operand_ty = sema.typeOf(operand);
12110 const operand_tuple = operand_ty.tupleFields();
12111 const src = LazySrcLoc.nodeOffset(src_node);12114 const src = LazySrcLoc.nodeOffset(src_node);
12112 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node };12115 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node };
12113 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node };12116 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();
12116 const final_len_u64 = std.math.mul(u64, tuple_len, factor) catch12119 const final_len_u64 = std.math.mul(u64, tuple_len, factor) catch
12117 return sema.fail(block, rhs_src, "operation results in overflow", .{});12120 return sema.fail(block, rhs_src, "operation results in overflow", .{});
1211812121
...@@ -12126,18 +12129,19 @@ fn analyzeTupleMul(...@@ -12126,18 +12129,19 @@ fn analyzeTupleMul(
1212612129
12127 const opt_runtime_src = rs: {12130 const opt_runtime_src = rs: {
12128 var runtime_src: ?LazySrcLoc = null;12131 var runtime_src: ?LazySrcLoc = null;
12129 for (operand_tuple.types) |ty, i| {12132 var i: u32 = 0;
12130 types[i] = ty;12133 while (i < tuple_len) : (i += 1) {
12131 values[i] = operand_tuple.values[i];12134 types[i] = operand_ty.structFieldType(i);
12135 values[i] = operand_ty.structFieldDefaultValue(i);
12132 const operand_src = lhs_src; // TODO better source location12136 const operand_src = lhs_src; // TODO better source location
12133 if (values[i].tag() == .unreachable_value) {12137 if (values[i].tag() == .unreachable_value) {
12134 runtime_src = operand_src;12138 runtime_src = operand_src;
12135 }12139 }
12136 }12140 }
12137 var i: usize = 1;12141 i = 0;
12138 while (i < factor) : (i += 1) {12142 while (i < factor) : (i += 1) {
12139 mem.copy(Type, types[tuple_len * i ..], operand_tuple.types);12143 mem.copy(Type, types[tuple_len * i ..], types[0..tuple_len]);
12140 mem.copy(Value, values[tuple_len * i ..], operand_tuple.values);12144 mem.copy(Value, values[tuple_len * i ..], values[0..tuple_len]);
12141 }12145 }
12142 break :rs runtime_src;12146 break :rs runtime_src;
12143 };12147 };
...@@ -12155,11 +12159,12 @@ fn analyzeTupleMul(...@@ -12155,11 +12159,12 @@ fn analyzeTupleMul(
12155 try sema.requireRuntimeBlock(block, src, runtime_src);12159 try sema.requireRuntimeBlock(block, src, runtime_src);
1215612160
12157 const element_refs = try sema.arena.alloc(Air.Inst.Ref, final_len);12161 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) {
12159 const operand_src = lhs_src; // TODO better source location12164 const operand_src = lhs_src; // TODO better source location
12160 element_refs[i] = try sema.tupleFieldValByIndex(block, operand_src, operand, @intCast(u32, i), operand_ty);12165 element_refs[i] = try sema.tupleFieldValByIndex(block, operand_src, operand, @intCast(u32, i), operand_ty);
12161 }12166 }
12162 var i: usize = 1;12167 i = 1;
12163 while (i < factor) : (i += 1) {12168 while (i < factor) : (i += 1) {
12164 mem.copy(Air.Inst.Ref, element_refs[tuple_len * i ..], element_refs[0..tuple_len]);12169 mem.copy(Air.Inst.Ref, element_refs[tuple_len * i ..], element_refs[0..tuple_len]);
12165 }12170 }
...@@ -15593,7 +15598,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -15593,7 +15598,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
15593 const layout = struct_ty.containerLayout();15598 const layout = struct_ty.containerLayout();
1559415599
15595 const struct_field_vals = fv: {15600 const struct_field_vals = fv: {
15596 if (struct_ty.isTupleOrAnonStruct()) {15601 if (struct_ty.isSimpleTupleOrAnonStruct()) {
15597 const tuple = struct_ty.tupleFields();15602 const tuple = struct_ty.tupleFields();
15598 const field_types = tuple.types;15603 const field_types = tuple.types;
15599 const struct_field_vals = try fields_anon_decl.arena().alloc(Value, field_types.len);15604 const struct_field_vals = try fields_anon_decl.arena().alloc(Value, field_types.len);
...@@ -17063,10 +17068,12 @@ fn finishStructInit(...@@ -17063,10 +17068,12 @@ fn finishStructInit(
17063 }17068 }
17064 }17069 }
17065 } else if (struct_ty.isTuple()) {17070 } else if (struct_ty.isTuple()) {
17066 const struct_obj = struct_ty.castTag(.tuple).?.data;17071 var i: u32 = 0;
17067 for (struct_obj.values) |default_val, i| {17072 const len = struct_ty.structFieldCount();
17073 while (i < len) : (i += 1) {
17068 if (field_inits[i] != .none) continue;17074 if (field_inits[i] != .none) continue;
1706917075
17076 const default_val = struct_ty.structFieldDefaultValue(i);
17070 if (default_val.tag() == .unreachable_value) {17077 if (default_val.tag() == .unreachable_value) {
17071 const template = "missing tuple field with index {d}";17078 const template = "missing tuple field with index {d}";
17072 if (root_msg) |msg| {17079 if (root_msg) |msg| {
...@@ -17075,7 +17082,7 @@ fn finishStructInit(...@@ -17075,7 +17082,7 @@ fn finishStructInit(
17075 root_msg = try sema.errMsg(block, init_src, template, .{i});17082 root_msg = try sema.errMsg(block, init_src, template, .{i});
17076 }17083 }
17077 } else {17084 } 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);
17079 }17086 }
17080 }17087 }
17081 } else {17088 } else {
...@@ -17297,7 +17304,7 @@ fn zirArrayInit(...@@ -17297,7 +17304,7 @@ fn zirArrayInit(
17297 const resolved_arg = try sema.resolveInst(arg);17304 const resolved_arg = try sema.resolveInst(arg);
17298 const arg_src = src; // TODO better source location17305 const arg_src = src; // TODO better source location
17299 const elem_ty = if (array_ty.zigTypeTag() == .Struct)17306 const elem_ty = if (array_ty.zigTypeTag() == .Struct)
17300 array_ty.tupleFields().types[i]17307 array_ty.structFieldType(i)
17301 else17308 else
17302 array_ty.elemType2();17309 array_ty.elemType2();
17303 resolved_args[i] = try sema.coerce(block, elem_ty, resolved_arg, arg_src);17310 resolved_args[i] = try sema.coerce(block, elem_ty, resolved_arg, arg_src);
...@@ -17337,12 +17344,11 @@ fn zirArrayInit(...@@ -17337,12 +17344,11 @@ fn zirArrayInit(
17337 const alloc = try block.addTy(.alloc, alloc_ty);17344 const alloc = try block.addTy(.alloc, alloc_ty);
1733817345
17339 if (array_ty.isTuple()) {17346 if (array_ty.isTuple()) {
17340 const types = array_ty.tupleFields().types;
17341 for (resolved_args) |arg, i| {17347 for (resolved_args) |arg, i| {
17342 const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{17348 const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
17343 .mutable = true,17349 .mutable = true,
17344 .@"addrspace" = target_util.defaultAddressSpace(target, .local),17350 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
17345 .pointee_type = types[i],17351 .pointee_type = array_ty.structFieldType(i),
17346 });17352 });
17347 const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty);17353 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...@@ -18015,10 +18021,7 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
18015 return sema.fail(block, src, "non-packed struct does not support backing integer type", .{});18021 return sema.fail(block, src, "non-packed struct does not support backing integer type", .{});
18016 }18022 }
1801718023
18018 return if (is_tuple_val.toBool())18024 return try sema.reifyStruct(block, inst, src, layout, backing_int_val, fields_val, name_strategy, 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);
18022 },18025 },
18023 .Enum => {18026 .Enum => {
18024 const struct_val: []const Value = union_val.val.castTag(.aggregate).?.data;18027 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...@@ -18432,84 +18435,6 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
18432 }18435 }
18433}18436}
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
18513fn reifyStruct(18438fn reifyStruct(
18514 sema: *Sema,18439 sema: *Sema,
18515 block: *Block,18440 block: *Block,
...@@ -18519,6 +18444,7 @@ fn reifyStruct(...@@ -18519,6 +18444,7 @@ fn reifyStruct(
18519 backing_int_val: Value,18444 backing_int_val: Value,
18520 fields_val: Value,18445 fields_val: Value,
18521 name_strategy: Zir.Inst.NameStrategy,18446 name_strategy: Zir.Inst.NameStrategy,
18447 is_tuple: bool,
18522) CompileError!Air.Inst.Ref {18448) CompileError!Air.Inst.Ref {
18523 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);18449 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
18524 errdefer new_decl_arena.deinit();18450 errdefer new_decl_arena.deinit();
...@@ -18542,6 +18468,7 @@ fn reifyStruct(...@@ -18542,6 +18468,7 @@ fn reifyStruct(
18542 .layout = layout,18468 .layout = layout,
18543 .status = .have_field_types,18469 .status = .have_field_types,
18544 .known_non_opv = false,18470 .known_non_opv = false,
18471 .is_tuple = is_tuple,
18545 .namespace = .{18472 .namespace = .{
18546 .parent = block.namespace,18473 .parent = block.namespace,
18547 .ty = struct_ty,18474 .ty = struct_ty,
...@@ -23201,6 +23128,7 @@ fn structFieldVal(...@@ -23201,6 +23128,7 @@ fn structFieldVal(
23201 },23128 },
23202 .@"struct" => {23129 .@"struct" => {
23203 const struct_obj = struct_ty.castTag(.@"struct").?.data;23130 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
23205 const field_index_usize = struct_obj.fields.getIndex(field_name) orelse23133 const field_index_usize = struct_obj.fields.getIndex(field_name) orelse
23206 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name);23134 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name);
...@@ -23273,11 +23201,10 @@ fn tupleFieldValByIndex(...@@ -23273,11 +23201,10 @@ fn tupleFieldValByIndex(
23273 field_index: u32,23201 field_index: u32,
23274 tuple_ty: Type,23202 tuple_ty: Type,
23275) CompileError!Air.Inst.Ref {23203) CompileError!Air.Inst.Ref {
23276 const tuple = tuple_ty.tupleFields();23204 const field_ty = tuple_ty.structFieldType(field_index);
23277 const field_ty = tuple.types[field_index];
2327823205
23279 if (tuple.values[field_index].tag() != .unreachable_value) {23206 if (tuple_ty.structFieldValueComptime(field_index)) |default_value| {
23280 return sema.addConstant(field_ty, tuple.values[field_index]);23207 return sema.addConstant(field_ty, default_value);
23281 }23208 }
2328223209
23283 if (try sema.resolveMaybeUndefVal(tuple_byval)) |tuple_val| {23210 if (try sema.resolveMaybeUndefVal(tuple_byval)) |tuple_val| {
...@@ -23625,19 +23552,20 @@ fn tupleFieldPtr(...@@ -23625,19 +23552,20 @@ fn tupleFieldPtr(
23625) CompileError!Air.Inst.Ref {23552) CompileError!Air.Inst.Ref {
23626 const tuple_ptr_ty = sema.typeOf(tuple_ptr);23553 const tuple_ptr_ty = sema.typeOf(tuple_ptr);
23627 const tuple_ty = tuple_ptr_ty.childType();23554 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) {
23631 return sema.fail(block, tuple_ptr_src, "indexing into empty tuple is not allowed", .{});23559 return sema.fail(block, tuple_ptr_src, "indexing into empty tuple is not allowed", .{});
23632 }23560 }
2363323561
23634 if (field_index >= tuple_fields.types.len) {23562 if (field_index >= field_count) {
23635 return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{23563 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,
23637 });23565 });
23638 }23566 }
2363923567
23640 const field_ty = tuple_fields.types[field_index];23568 const field_ty = tuple_ty.structFieldType(field_index);
23641 const ptr_field_ty = try Type.ptr(sema.arena, sema.mod, .{23569 const ptr_field_ty = try Type.ptr(sema.arena, sema.mod, .{
23642 .pointee_type = field_ty,23570 .pointee_type = field_ty,
23643 .mutable = tuple_ptr_ty.ptrIsMutable(),23571 .mutable = tuple_ptr_ty.ptrIsMutable(),
...@@ -23680,24 +23608,23 @@ fn tupleField(...@@ -23680,24 +23608,23 @@ fn tupleField(
23680 field_index_src: LazySrcLoc,23608 field_index_src: LazySrcLoc,
23681 field_index: u32,23609 field_index: u32,
23682) CompileError!Air.Inst.Ref {23610) CompileError!Air.Inst.Ref {
23683 const tuple_ty = sema.typeOf(tuple);23611 const tuple_ty = try sema.resolveTypeFields(sema.typeOf(tuple));
23684 const tuple_fields = tuple_ty.tupleFields();23612 const field_count = tuple_ty.structFieldCount();
2368523613
23686 if (tuple_fields.types.len == 0) {23614 if (field_count == 0) {
23687 return sema.fail(block, tuple_src, "indexing into empty tuple is not allowed", .{});23615 return sema.fail(block, tuple_src, "indexing into empty tuple is not allowed", .{});
23688 }23616 }
2368923617
23690 if (field_index >= tuple_fields.types.len) {23618 if (field_index >= field_count) {
23691 return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{23619 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,
23693 });23621 });
23694 }23622 }
2369523623
23696 const field_ty = tuple_fields.types[field_index];23624 const field_ty = tuple_ty.structFieldType(field_index);
23697 const field_val = tuple_fields.values[field_index];
2369823625
23699 if (field_val.tag() != .unreachable_value) {23626 if (tuple_ty.structFieldValueComptime(field_index)) |default_value| {
23700 return sema.addConstant(field_ty, field_val); // comptime field23627 return sema.addConstant(field_ty, default_value); // comptime field
23701 }23628 }
2370223629
23703 if (try sema.resolveMaybeUndefVal(tuple)) |tuple_val| {23630 if (try sema.resolveMaybeUndefVal(tuple)) |tuple_val| {
...@@ -24277,7 +24204,7 @@ fn coerceExtra(...@@ -24277,7 +24204,7 @@ fn coerceExtra(
2427724204
24278 // empty tuple to zero-length slice24205 // empty tuple to zero-length slice
24279 // note that this allows coercing to a mutable slice.24206 // 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) {
24281 const slice_val = try Value.Tag.slice.create(sema.arena, .{24208 const slice_val = try Value.Tag.slice.create(sema.arena, .{
24282 .ptr = Value.undef,24209 .ptr = Value.undef,
24283 .len = Value.zero,24210 .len = Value.zero,
...@@ -25587,9 +25514,9 @@ fn storePtr2(...@@ -25587,9 +25514,9 @@ fn storePtr2(
25587 // fields.25514 // fields.
25588 const operand_ty = sema.typeOf(uncasted_operand);25515 const operand_ty = sema.typeOf(uncasted_operand);
25589 if (operand_ty.isTuple() and elem_ty.zigTypeTag() == .Array) {25516 if (operand_ty.isTuple() and elem_ty.zigTypeTag() == .Array) {
25590 const tuple = operand_ty.tupleFields();25517 const field_count = operand_ty.structFieldCount();
25591 for (tuple.types) |_, i_usize| {25518 var i: u32 = 0;
25592 const i = @intCast(u32, i_usize);25519 while (i < field_count) : (i += 1) {
25593 const elem_src = operand_src; // TODO better source location25520 const elem_src = operand_src; // TODO better source location
25594 const elem = try sema.tupleField(block, operand_src, uncasted_operand, elem_src, i);25521 const elem = try sema.tupleField(block, operand_src, uncasted_operand, elem_src, i);
25595 const elem_index = try sema.addIntUnsigned(Type.usize, i);25522 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...@@ -26681,7 +26608,7 @@ fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_resul
26681 const inst_info = inst_ty.ptrInfo().data;26608 const inst_info = inst_ty.ptrInfo().data;
26682 const len0 = (inst_info.pointee_type.zigTypeTag() == .Array and (inst_info.pointee_type.arrayLenIncludingSentinel() == 0 or26609 const len0 = (inst_info.pointee_type.zigTypeTag() == .Array and (inst_info.pointee_type.arrayLenIncludingSentinel() == 0 or
26683 (inst_info.pointee_type.arrayLen() == 0 and dest_info.sentinel == null and dest_info.size != .C and dest_info.size != .Many))) or26610 (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
26686 const ok_cv_qualifiers =26613 const ok_cv_qualifiers =
26687 ((inst_info.mutable or !dest_info.mutable) or len0) and26614 ((inst_info.mutable or !dest_info.mutable) or len0) and
...@@ -27166,18 +27093,18 @@ fn coerceTupleToStruct(...@@ -27166,18 +27093,18 @@ fn coerceTupleToStruct(
27166 mem.set(Air.Inst.Ref, field_refs, .none);27093 mem.set(Air.Inst.Ref, field_refs, .none);
2716727094
27168 const inst_ty = sema.typeOf(inst);27095 const inst_ty = sema.typeOf(inst);
27169 const tuple = inst_ty.tupleFields();
27170 var runtime_src: ?LazySrcLoc = null;27096 var runtime_src: ?LazySrcLoc = null;
27171 for (tuple.types) |_, i_usize| {27097 const field_count = struct_ty.structFieldCount();
27172 const i = @intCast(u32, i_usize);27098 var field_i: u32 = 0;
27099 while (field_i < field_count) : (field_i += 1) {
27173 const field_src = inst_src; // TODO better source location27100 const field_src = inst_src; // TODO better source location
27174 const field_name = if (inst_ty.castTag(.anon_struct)) |payload|27101 const field_name = if (inst_ty.castTag(.anon_struct)) |payload|
27175 payload.data.names[i]27102 payload.data.names[field_i]
27176 else27103 else
27177 try std.fmt.allocPrint(sema.arena, "{d}", .{i});27104 try std.fmt.allocPrint(sema.arena, "{d}", .{field_i});
27178 const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src);27105 const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src);
27179 const field = fields.values()[field_index];27106 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);
27181 const coerced = try sema.coerce(block, field.ty, elem_ref, field_src);27108 const coerced = try sema.coerce(block, field.ty, elem_ref, field_src);
27182 field_refs[field_index] = coerced;27109 field_refs[field_index] = coerced;
27183 if (field.is_comptime) {27110 if (field.is_comptime) {
...@@ -27186,7 +27113,7 @@ fn coerceTupleToStruct(...@@ -27186,7 +27113,7 @@ fn coerceTupleToStruct(
27186 };27113 };
2718727114
27188 if (!init_val.eql(field.default_val, field.ty, sema.mod)) {27115 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);
27190 }27117 }
27191 }27118 }
27192 if (runtime_src == null) {27119 if (runtime_src == null) {
...@@ -27255,15 +27182,14 @@ fn coerceTupleToTuple(...@@ -27255,15 +27182,14 @@ fn coerceTupleToTuple(
27255 mem.set(Air.Inst.Ref, field_refs, .none);27182 mem.set(Air.Inst.Ref, field_refs, .none);
2725627183
27257 const inst_ty = sema.typeOf(inst);27184 const inst_ty = sema.typeOf(inst);
27258 const tuple = inst_ty.tupleFields();
27259 var runtime_src: ?LazySrcLoc = null;27185 var runtime_src: ?LazySrcLoc = null;
27260 for (tuple.types) |_, i_usize| {27186 var field_i: u32 = 0;
27261 const i = @intCast(u32, i_usize);27187 while (field_i < field_count) : (field_i += 1) {
27262 const field_src = inst_src; // TODO better source location27188 const field_src = inst_src; // TODO better source location
27263 const field_name = if (inst_ty.castTag(.anon_struct)) |payload|27189 const field_name = if (inst_ty.castTag(.anon_struct)) |payload|
27264 payload.data.names[i]27190 payload.data.names[field_i]
27265 else27191 else
27266 try std.fmt.allocPrint(sema.arena, "{d}", .{i});27192 try std.fmt.allocPrint(sema.arena, "{d}", .{field_i});
2726727193
27268 if (mem.eql(u8, field_name, "len")) {27194 if (mem.eql(u8, field_name, "len")) {
27269 return sema.fail(block, field_src, "cannot assign to 'len' field of tuple", .{});27195 return sema.fail(block, field_src, "cannot assign to 'len' field of tuple", .{});
...@@ -27271,9 +27197,9 @@ fn coerceTupleToTuple(...@@ -27271,9 +27197,9 @@ fn coerceTupleToTuple(
2727127197
27272 const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_src);27198 const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_src);
2727327199
27274 const field_ty = tuple_ty.structFieldType(i);27200 const field_ty = tuple_ty.structFieldType(field_i);
27275 const default_val = tuple_ty.structFieldDefaultValue(i);27201 const default_val = tuple_ty.structFieldDefaultValue(field_i);
27276 const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, i);27202 const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i);
27277 const coerced = try sema.coerce(block, field_ty, elem_ref, field_src);27203 const coerced = try sema.coerce(block, field_ty, elem_ref, field_src);
27278 field_refs[field_index] = coerced;27204 field_refs[field_index] = coerced;
27279 if (default_val.tag() != .unreachable_value) {27205 if (default_val.tag() != .unreachable_value) {
...@@ -27282,7 +27208,7 @@ fn coerceTupleToTuple(...@@ -27282,7 +27208,7 @@ fn coerceTupleToTuple(
27282 };27208 };
2728327209
27284 if (!init_val.eql(default_val, field_ty, sema.mod)) {27210 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);
27286 }27212 }
27287 }27213 }
27288 if (runtime_src == null) {27214 if (runtime_src == null) {
...@@ -29665,6 +29591,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -29665,6 +29591,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
29665 block_scope.params.deinit(gpa);29591 block_scope.params.deinit(gpa);
29666 }29592 }
2966729593
29594 struct_obj.fields = .{};
29668 try struct_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len);29595 try struct_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len);
2966929596
29670 const Field = struct {29597 const Field = struct {
...@@ -29699,8 +29626,11 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -29699,8 +29626,11 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
29699 const has_type_body = @truncate(u1, cur_bit_bag) != 0;29626 const has_type_body = @truncate(u1, cur_bit_bag) != 0;
29700 cur_bit_bag >>= 1;29627 cur_bit_bag >>= 1;
2970129628
29702 const field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]);29629 var field_name_zir: ?[:0]const u8 = null;
29703 extra_index += 1;29630 if (!small.is_tuple) {
29631 field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]);
29632 extra_index += 1;
29633 }
29704 extra_index += 1; // doc_comment29634 extra_index += 1; // doc_comment
2970529635
29706 fields[field_i] = .{};29636 fields[field_i] = .{};
...@@ -29713,7 +29643,10 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -29713,7 +29643,10 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
29713 extra_index += 1;29643 extra_index += 1;
2971429644
29715 // This string needs to outlive the ZIR code.29645 // 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
29718 const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);29651 const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);
29719 if (gop.found_existing) {29652 if (gop.found_existing) {
src/codegen/c.zig+1-1
...@@ -1791,7 +1791,7 @@ pub const DeclGen = struct {...@@ -1791,7 +1791,7 @@ pub const DeclGen = struct {
1791 },1791 },
1792 .Struct, .Union => |tag| if (tag == .Struct and t.containerLayout() == .Packed)1792 .Struct, .Union => |tag| if (tag == .Struct and t.containerLayout() == .Packed)
1793 try dg.renderType(w, t.castTag(.@"struct").?.data.backing_int_ty, kind)1793 try dg.renderType(w, t.castTag(.@"struct").?.data.backing_int_ty, kind)
1794 else if (t.isTupleOrAnonStruct()) {1794 else if (t.isSimpleTupleOrAnonStruct()) {
1795 const ExpectedContents = struct { types: [8]Type, values: [8]Value };1795 const ExpectedContents = struct { types: [8]Type, values: [8]Value };
1796 var stack align(@alignOf(ExpectedContents)) =1796 var stack align(@alignOf(ExpectedContents)) =
1797 std.heap.stackFallback(@sizeOf(ExpectedContents), dg.gpa);1797 std.heap.stackFallback(@sizeOf(ExpectedContents), dg.gpa);
src/codegen/llvm.zig+5-5
...@@ -1951,7 +1951,7 @@ pub const Object = struct {...@@ -1951,7 +1951,7 @@ pub const Object = struct {
1951 break :blk fwd_decl;1951 break :blk fwd_decl;
1952 };1952 };
19531953
1954 if (ty.isTupleOrAnonStruct()) {1954 if (ty.isSimpleTupleOrAnonStruct()) {
1955 const tuple = ty.tupleFields();1955 const tuple = ty.tupleFields();
19561956
1957 var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};1957 var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
...@@ -2885,7 +2885,7 @@ pub const DeclGen = struct {...@@ -2885,7 +2885,7 @@ pub const DeclGen = struct {
2885 // reference, we need to copy it here.2885 // reference, we need to copy it here.
2886 gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator());2886 gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator());
28872887
2888 if (t.isTupleOrAnonStruct()) {2888 if (t.isSimpleTupleOrAnonStruct()) {
2889 const tuple = t.tupleFields();2889 const tuple = t.tupleFields();
2890 const llvm_struct_ty = dg.context.structCreateNamed("");2890 const llvm_struct_ty = dg.context.structCreateNamed("");
2891 gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls2891 gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls
...@@ -3579,7 +3579,7 @@ pub const DeclGen = struct {...@@ -3579,7 +3579,7 @@ pub const DeclGen = struct {
3579 const field_vals = tv.val.castTag(.aggregate).?.data;3579 const field_vals = tv.val.castTag(.aggregate).?.data;
3580 const gpa = dg.gpa;3580 const gpa = dg.gpa;
35813581
3582 if (tv.ty.isTupleOrAnonStruct()) {3582 if (tv.ty.isSimpleTupleOrAnonStruct()) {
3583 const tuple = tv.ty.tupleFields();3583 const tuple = tv.ty.tupleFields();
3584 var llvm_fields: std.ArrayListUnmanaged(*llvm.Value) = .{};3584 var llvm_fields: std.ArrayListUnmanaged(*llvm.Value) = .{};
3585 defer llvm_fields.deinit(gpa);3585 defer llvm_fields.deinit(gpa);
...@@ -10247,7 +10247,7 @@ fn llvmFieldIndex(...@@ -10247,7 +10247,7 @@ fn llvmFieldIndex(
10247 var offset: u64 = 0;10247 var offset: u64 = 0;
10248 var big_align: u32 = 0;10248 var big_align: u32 = 0;
1024910249
10250 if (ty.isTupleOrAnonStruct()) {10250 if (ty.isSimpleTupleOrAnonStruct()) {
10251 const tuple = ty.tupleFields();10251 const tuple = ty.tupleFields();
10252 var llvm_field_index: c_uint = 0;10252 var llvm_field_index: c_uint = 0;
10253 for (tuple.types) |field_ty, i| {10253 for (tuple.types) |field_ty, i| {
...@@ -10810,7 +10810,7 @@ fn isByRef(ty: Type) bool {...@@ -10810,7 +10810,7 @@ fn isByRef(ty: Type) bool {
10810 .Struct => {10810 .Struct => {
10811 // Packed structs are represented to LLVM as integers.10811 // Packed structs are represented to LLVM as integers.
10812 if (ty.containerLayout() == .Packed) return false;10812 if (ty.containerLayout() == .Packed) return false;
10813 if (ty.isTupleOrAnonStruct()) {10813 if (ty.isSimpleTupleOrAnonStruct()) {
10814 const tuple = ty.tupleFields();10814 const tuple = ty.tupleFields();
10815 var count: usize = 0;10815 var count: usize = 0;
10816 for (tuple.values) |field_val, i| {10816 for (tuple.values) |field_val, i| {
src/type.zig+19-5
...@@ -4494,6 +4494,7 @@ pub const Type = extern union {...@@ -4494,6 +4494,7 @@ pub const Type = extern union {
4494 .mut_slice,4494 .mut_slice,
4495 .tuple,4495 .tuple,
4496 .empty_struct_literal,4496 .empty_struct_literal,
4497 .@"struct",
4497 => return null,4498 => return null,
44984499
4499 .pointer => return self.castTag(.pointer).?.data.sentinel,4500 .pointer => return self.castTag(.pointer).?.data.sentinel,
...@@ -5571,11 +5572,7 @@ pub const Type = extern union {...@@ -5571,11 +5572,7 @@ pub const Type = extern union {
55715572
5572 pub fn structFieldCount(ty: Type) usize {5573 pub fn structFieldCount(ty: Type) usize {
5573 switch (ty.tag()) {5574 switch (ty.tag()) {
5574 .@"struct" => {5575 .@"struct" => return ty.castTag(.@"struct").?.data.fields.count(),
5575 const struct_obj = ty.castTag(.@"struct").?.data;
5576 assert(struct_obj.haveFieldTypes());
5577 return struct_obj.fields.count();
5578 },
5579 .empty_struct, .empty_struct_literal => return 0,5576 .empty_struct, .empty_struct_literal => return 0,
5580 .tuple => return ty.castTag(.tuple).?.data.types.len,5577 .tuple => return ty.castTag(.tuple).?.data.types.len,
5581 .anon_struct => return ty.castTag(.anon_struct).?.data.types.len,5578 .anon_struct => return ty.castTag(.anon_struct).?.data.types.len,
...@@ -6178,6 +6175,7 @@ pub const Type = extern union {...@@ -6178,6 +6175,7 @@ pub const Type = extern union {
6178 pub fn isTuple(ty: Type) bool {6175 pub fn isTuple(ty: Type) bool {
6179 return switch (ty.tag()) {6176 return switch (ty.tag()) {
6180 .tuple, .empty_struct_literal => true,6177 .tuple, .empty_struct_literal => true,
6178 .@"struct" => ty.castTag(.@"struct").?.data.is_tuple,
6181 else => false,6179 else => false,
6182 };6180 };
6183 }6181 }
...@@ -6190,12 +6188,28 @@ pub const Type = extern union {...@@ -6190,12 +6188,28 @@ pub const Type = extern union {
6190 }6188 }
61916189
6192 pub fn isTupleOrAnonStruct(ty: Type) bool {6190 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 {
6193 return switch (ty.tag()) {6206 return switch (ty.tag()) {
6194 .tuple, .empty_struct_literal, .anon_struct => true,6207 .tuple, .empty_struct_literal, .anon_struct => true,
6195 else => false,6208 else => false,
6196 };6209 };
6197 }6210 }
61986211
6212 // Only allowed for simple tuple types
6199 pub fn tupleFields(ty: Type) Payload.Tuple.Data {6213 pub fn tupleFields(ty: Type) Payload.Tuple.Data {
6200 return switch (ty.tag()) {6214 return switch (ty.tag()) {
6201 .tuple => ty.castTag(.tuple).?.data,6215 .tuple => ty.castTag(.tuple).?.data,
src/value.zig+2-2
...@@ -2209,7 +2209,7 @@ pub const Value = extern union {...@@ -2209,7 +2209,7 @@ pub const Value = extern union {
2209 const b_field_vals = b.castTag(.aggregate).?.data;2209 const b_field_vals = b.castTag(.aggregate).?.data;
2210 assert(a_field_vals.len == b_field_vals.len);2210 assert(a_field_vals.len == b_field_vals.len);
22112211
2212 if (ty.isTupleOrAnonStruct()) {2212 if (ty.isSimpleTupleOrAnonStruct()) {
2213 const types = ty.tupleFields().types;2213 const types = ty.tupleFields().types;
2214 assert(types.len == a_field_vals.len);2214 assert(types.len == a_field_vals.len);
2215 for (types) |field_ty, i| {2215 for (types) |field_ty, i| {
...@@ -3004,7 +3004,7 @@ pub const Value = extern union {...@@ -3004,7 +3004,7 @@ pub const Value = extern union {
3004 .the_only_possible_value => return ty.onePossibleValue().?,3004 .the_only_possible_value => return ty.onePossibleValue().?,
30053005
3006 .empty_struct_value => {3006 .empty_struct_value => {
3007 if (ty.isTupleOrAnonStruct()) {3007 if (ty.isSimpleTupleOrAnonStruct()) {
3008 const tuple = ty.tupleFields();3008 const tuple = ty.tupleFields();
3009 return tuple.values[index];3009 return tuple.values[index];
3010 }3010 }