diff options
| author | Veikka Tuominen <git@vexu.eu> | 2022-11-22 01:19:50 +0200 |
|---|---|---|
| committer | Veikka Tuominen <git@vexu.eu> | 2022-11-23 12:13:39 +0200 |
| commit | d5da2a6114926fae44f31eeab0706578f090dca8 (patch) | |
| tree | b2a561651f35aae2dd934f43690e0311c95db0c6 /src | |
| parent | 80575face7a3b1e0f47e413507a6fa8b1d002e57 (diff) | |
| download | zig-d5da2a6114926fae44f31eeab0706578f090dca8.tar.gz zig-d5da2a6114926fae44f31eeab0706578f090dca8.zip | |
Sema: implement tuple declarations
Diffstat (limited to 'src')
| -rw-r--r-- | src/Module.zig | 5 | ||||
| -rw-r--r-- | src/Sema.zig | 259 | ||||
| -rw-r--r-- | src/codegen/c.zig | 2 | ||||
| -rw-r--r-- | src/codegen/llvm.zig | 10 | ||||
| -rw-r--r-- | src/type.zig | 24 | ||||
| -rw-r--r-- | src/value.zig | 4 |
6 files changed, 128 insertions, 176 deletions
diff --git a/src/Module.zig b/src/Module.zig index 8ea49f13b3..bb03616dff 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -938,6 +938,7 @@ pub const Struct = struct { known_non_opv: bool, requires_comptime: PropertyBoolean = .unknown, have_field_inits: bool = false, + is_tuple: bool, pub const Fields = std.StringArrayHashMapUnmanaged(Field); @@ -4458,6 +4459,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { .layout = .Auto, .status = .none, .known_non_opv = undefined, + .is_tuple = undefined, // set below .namespace = .{ .parent = null, .ty = struct_ty, @@ -4489,6 +4491,9 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { assert(file.zir_loaded); const main_struct_inst = Zir.main_struct_inst; struct_obj.zir_index = main_struct_inst; + const extended = file.zir.instructions.items(.data)[main_struct_inst].extended; + const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); + struct_obj.is_tuple = small.is_tuple; var sema_arena = std.heap.ArenaAllocator.init(gpa); defer sema_arena.deinit(); diff --git a/src/Sema.zig b/src/Sema.zig index a1c7fa7b91..b8d7b9f2b5 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -2519,6 +2519,7 @@ fn zirStructDecl( .layout = small.layout, .status = .none, .known_non_opv = undefined, + .is_tuple = small.is_tuple, .namespace = .{ .parent = block.namespace, .ty = struct_ty, @@ -4291,13 +4292,12 @@ fn zirValidateArrayInit( if (instrs.len != array_len) switch (array_ty.zigTypeTag()) { .Struct => { - const struct_obj = array_ty.castTag(.tuple).?.data; var root_msg: ?*Module.ErrorMsg = null; errdefer if (root_msg) |msg| msg.destroy(sema.gpa); - for (struct_obj.values) |default_val, i| { - if (i < instrs.len) continue; - + var i = instrs.len; + while (i < array_len) : (i += 1) { + const default_val = array_ty.structFieldDefaultValue(i); if (default_val.tag() == .unreachable_value) { const template = "missing tuple field with index {d}"; if (root_msg) |msg| { @@ -7230,7 +7230,7 @@ fn instantiateGenericCall( } fn resolveTupleLazyValues(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void { - if (!ty.isTuple()) return; + if (!ty.isSimpleTuple()) return; const tuple = ty.tupleFields(); for (tuple.values) |field_val, i| { try sema.resolveTupleLazyValues(block, src, tuple.types[i]); @@ -7295,7 +7295,7 @@ fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr const indexable_ty = try sema.resolveType(block, .unneeded, bin.lhs); assert(indexable_ty.isIndexable()); // validated by a previous instruction if (indexable_ty.zigTypeTag() == .Struct) { - const elem_type = indexable_ty.tupleFields().types[@enumToInt(bin.rhs)]; + const elem_type = indexable_ty.structFieldType(@enumToInt(bin.rhs)); return sema.addType(elem_type); } else { const elem_type = indexable_ty.elemType2(); @@ -11827,9 +11827,9 @@ fn analyzeTupleCat( const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node }; const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node }; - const lhs_tuple = lhs_ty.tupleFields(); - const rhs_tuple = rhs_ty.tupleFields(); - const dest_fields = lhs_tuple.types.len + rhs_tuple.types.len; + const lhs_len = lhs_ty.structFieldCount(); + const rhs_len = rhs_ty.structFieldCount(); + const dest_fields = lhs_len + rhs_len; if (dest_fields == 0) { return sema.addConstant(Type.initTag(.empty_struct_literal), Value.initTag(.empty_struct_value)); @@ -11841,20 +11841,23 @@ fn analyzeTupleCat( const opt_runtime_src = rs: { var runtime_src: ?LazySrcLoc = null; - for (lhs_tuple.types) |ty, i| { - types[i] = ty; - values[i] = lhs_tuple.values[i]; + var i: u32 = 0; + while (i < lhs_len) : (i += 1) { + types[i] = lhs_ty.structFieldType(i); + const default_val = lhs_ty.structFieldDefaultValue(i); + values[i] = default_val; const operand_src = lhs_src; // TODO better source location - if (values[i].tag() == .unreachable_value) { + if (default_val.tag() == .unreachable_value) { runtime_src = operand_src; } } - const offset = lhs_tuple.types.len; - for (rhs_tuple.types) |ty, i| { - types[i + offset] = ty; - values[i + offset] = rhs_tuple.values[i]; + i = 0; + while (i < rhs_len) : (i += 1) { + types[i + lhs_len] = rhs_ty.structFieldType(i); + const default_val = rhs_ty.structFieldDefaultValue(i); + values[i + lhs_len] = default_val; const operand_src = rhs_src; // TODO better source location - if (rhs_tuple.values[i].tag() == .unreachable_value) { + if (default_val.tag() == .unreachable_value) { runtime_src = operand_src; } } @@ -11874,14 +11877,15 @@ fn analyzeTupleCat( try sema.requireRuntimeBlock(block, src, runtime_src); const element_refs = try sema.arena.alloc(Air.Inst.Ref, final_len); - for (lhs_tuple.types) |_, i| { + var i: u32 = 0; + while (i < lhs_len) : (i += 1) { const operand_src = lhs_src; // TODO better source location element_refs[i] = try sema.tupleFieldValByIndex(block, operand_src, lhs, @intCast(u32, i), lhs_ty); } - const offset = lhs_tuple.types.len; - for (rhs_tuple.types) |_, i| { + i = 0; + while (i < rhs_len) : (i += 1) { const operand_src = rhs_src; // TODO better source location - element_refs[i + offset] = + element_refs[i + lhs_len] = try sema.tupleFieldValByIndex(block, operand_src, rhs, @intCast(u32, i), rhs_ty); } @@ -12107,12 +12111,11 @@ fn analyzeTupleMul( factor: u64, ) CompileError!Air.Inst.Ref { const operand_ty = sema.typeOf(operand); - const operand_tuple = operand_ty.tupleFields(); const src = LazySrcLoc.nodeOffset(src_node); const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node }; const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node }; - const tuple_len = operand_tuple.types.len; + const tuple_len = operand_ty.structFieldCount(); const final_len_u64 = std.math.mul(u64, tuple_len, factor) catch return sema.fail(block, rhs_src, "operation results in overflow", .{}); @@ -12126,18 +12129,19 @@ fn analyzeTupleMul( const opt_runtime_src = rs: { var runtime_src: ?LazySrcLoc = null; - for (operand_tuple.types) |ty, i| { - types[i] = ty; - values[i] = operand_tuple.values[i]; + var i: u32 = 0; + while (i < tuple_len) : (i += 1) { + types[i] = operand_ty.structFieldType(i); + values[i] = operand_ty.structFieldDefaultValue(i); const operand_src = lhs_src; // TODO better source location if (values[i].tag() == .unreachable_value) { runtime_src = operand_src; } } - var i: usize = 1; + i = 0; while (i < factor) : (i += 1) { - mem.copy(Type, types[tuple_len * i ..], operand_tuple.types); - mem.copy(Value, values[tuple_len * i ..], operand_tuple.values); + mem.copy(Type, types[tuple_len * i ..], types[0..tuple_len]); + mem.copy(Value, values[tuple_len * i ..], values[0..tuple_len]); } break :rs runtime_src; }; @@ -12155,11 +12159,12 @@ fn analyzeTupleMul( try sema.requireRuntimeBlock(block, src, runtime_src); const element_refs = try sema.arena.alloc(Air.Inst.Ref, final_len); - for (operand_tuple.types) |_, i| { + var i: u32 = 0; + while (i < tuple_len) : (i += 1) { const operand_src = lhs_src; // TODO better source location element_refs[i] = try sema.tupleFieldValByIndex(block, operand_src, operand, @intCast(u32, i), operand_ty); } - var i: usize = 1; + i = 1; while (i < factor) : (i += 1) { mem.copy(Air.Inst.Ref, element_refs[tuple_len * i ..], element_refs[0..tuple_len]); } @@ -15593,7 +15598,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const layout = struct_ty.containerLayout(); const struct_field_vals = fv: { - if (struct_ty.isTupleOrAnonStruct()) { + if (struct_ty.isSimpleTupleOrAnonStruct()) { const tuple = struct_ty.tupleFields(); const field_types = tuple.types; const struct_field_vals = try fields_anon_decl.arena().alloc(Value, field_types.len); @@ -17063,10 +17068,12 @@ fn finishStructInit( } } } else if (struct_ty.isTuple()) { - const struct_obj = struct_ty.castTag(.tuple).?.data; - for (struct_obj.values) |default_val, i| { + var i: u32 = 0; + const len = struct_ty.structFieldCount(); + while (i < len) : (i += 1) { if (field_inits[i] != .none) continue; + const default_val = struct_ty.structFieldDefaultValue(i); if (default_val.tag() == .unreachable_value) { const template = "missing tuple field with index {d}"; if (root_msg) |msg| { @@ -17075,7 +17082,7 @@ fn finishStructInit( root_msg = try sema.errMsg(block, init_src, template, .{i}); } } else { - field_inits[i] = try sema.addConstant(struct_obj.types[i], default_val); + field_inits[i] = try sema.addConstant(struct_ty.structFieldType(i), default_val); } } } else { @@ -17297,7 +17304,7 @@ fn zirArrayInit( const resolved_arg = try sema.resolveInst(arg); const arg_src = src; // TODO better source location const elem_ty = if (array_ty.zigTypeTag() == .Struct) - array_ty.tupleFields().types[i] + array_ty.structFieldType(i) else array_ty.elemType2(); resolved_args[i] = try sema.coerce(block, elem_ty, resolved_arg, arg_src); @@ -17337,12 +17344,11 @@ fn zirArrayInit( const alloc = try block.addTy(.alloc, alloc_ty); if (array_ty.isTuple()) { - const types = array_ty.tupleFields().types; for (resolved_args) |arg, i| { const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ .mutable = true, .@"addrspace" = target_util.defaultAddressSpace(target, .local), - .pointee_type = types[i], + .pointee_type = array_ty.structFieldType(i), }); const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty); @@ -18015,10 +18021,7 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in return sema.fail(block, src, "non-packed struct does not support backing integer type", .{}); } - return if (is_tuple_val.toBool()) - try sema.reifyTuple(block, src, fields_val) - else - try sema.reifyStruct(block, inst, src, layout, backing_int_val, fields_val, name_strategy); + return try sema.reifyStruct(block, inst, src, layout, backing_int_val, fields_val, name_strategy, is_tuple_val.toBool()); }, .Enum => { 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 } } -fn reifyTuple( - sema: *Sema, - block: *Block, - src: LazySrcLoc, - fields_val: Value, -) CompileError!Air.Inst.Ref { - const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(sema.mod)); - if (fields_len == 0) return sema.addType(Type.initTag(.empty_struct_literal)); - - const types = try sema.arena.alloc(Type, fields_len); - const values = try sema.arena.alloc(Value, fields_len); - - var used_fields: std.AutoArrayHashMapUnmanaged(u32, void) = .{}; - defer used_fields.deinit(sema.gpa); - try used_fields.ensureTotalCapacity(sema.gpa, fields_len); - - var i: usize = 0; - while (i < fields_len) : (i += 1) { - const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i); - const field_struct_val = elem_val.castTag(.aggregate).?.data; - // TODO use reflection instead of magic numbers here - // name: []const u8 - const name_val = field_struct_val[0]; - // field_type: type, - const field_type_val = field_struct_val[1]; - //default_value: ?*const anyopaque, - const default_value_val = field_struct_val[2]; - - const field_name = try name_val.toAllocatedBytes( - Type.initTag(.const_slice_u8), - sema.arena, - sema.mod, - ); - - const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch |err| { - return sema.fail( - block, - src, - "tuple cannot have non-numeric field '{s}': {}", - .{ field_name, err }, - ); - }; - - if (field_index >= fields_len) { - return sema.fail( - block, - src, - "tuple field {} exceeds tuple field count", - .{field_index}, - ); - } - - const gop = used_fields.getOrPutAssumeCapacity(field_index); - if (gop.found_existing) { - // TODO: better source location - return sema.fail(block, src, "duplicate tuple field {}", .{field_index}); - } - - const default_val = if (default_value_val.optionalValue()) |opt_val| blk: { - const payload_val = if (opt_val.pointerDecl()) |opt_decl| - sema.mod.declPtr(opt_decl).val - else - opt_val; - break :blk try payload_val.copy(sema.arena); - } else Value.initTag(.unreachable_value); - - var buffer: Value.ToTypeBuffer = undefined; - types[field_index] = try field_type_val.toType(&buffer).copy(sema.arena); - values[field_index] = default_val; - } - - const ty = try Type.Tag.tuple.create(sema.arena, .{ - .types = types, - .values = values, - }); - return sema.addType(ty); -} - fn reifyStruct( sema: *Sema, block: *Block, @@ -18519,6 +18444,7 @@ fn reifyStruct( backing_int_val: Value, fields_val: Value, name_strategy: Zir.Inst.NameStrategy, + is_tuple: bool, ) CompileError!Air.Inst.Ref { var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); errdefer new_decl_arena.deinit(); @@ -18542,6 +18468,7 @@ fn reifyStruct( .layout = layout, .status = .have_field_types, .known_non_opv = false, + .is_tuple = is_tuple, .namespace = .{ .parent = block.namespace, .ty = struct_ty, @@ -23201,6 +23128,7 @@ fn structFieldVal( }, .@"struct" => { const struct_obj = struct_ty.castTag(.@"struct").?.data; + if (struct_obj.is_tuple) return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty); const field_index_usize = struct_obj.fields.getIndex(field_name) orelse return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name); @@ -23273,11 +23201,10 @@ fn tupleFieldValByIndex( field_index: u32, tuple_ty: Type, ) CompileError!Air.Inst.Ref { - const tuple = tuple_ty.tupleFields(); - const field_ty = tuple.types[field_index]; + const field_ty = tuple_ty.structFieldType(field_index); - if (tuple.values[field_index].tag() != .unreachable_value) { - return sema.addConstant(field_ty, tuple.values[field_index]); + if (tuple_ty.structFieldValueComptime(field_index)) |default_value| { + return sema.addConstant(field_ty, default_value); } if (try sema.resolveMaybeUndefVal(tuple_byval)) |tuple_val| { @@ -23625,19 +23552,20 @@ fn tupleFieldPtr( ) CompileError!Air.Inst.Ref { const tuple_ptr_ty = sema.typeOf(tuple_ptr); const tuple_ty = tuple_ptr_ty.childType(); - const tuple_fields = tuple_ty.tupleFields(); + _ = try sema.resolveTypeFields(tuple_ty); + const field_count = tuple_ty.structFieldCount(); - if (tuple_fields.types.len == 0) { + if (field_count == 0) { return sema.fail(block, tuple_ptr_src, "indexing into empty tuple is not allowed", .{}); } - if (field_index >= tuple_fields.types.len) { + if (field_index >= field_count) { return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{ - field_index, tuple_fields.types.len, + field_index, field_count, }); } - const field_ty = tuple_fields.types[field_index]; + const field_ty = tuple_ty.structFieldType(field_index); const ptr_field_ty = try Type.ptr(sema.arena, sema.mod, .{ .pointee_type = field_ty, .mutable = tuple_ptr_ty.ptrIsMutable(), @@ -23680,24 +23608,23 @@ fn tupleField( field_index_src: LazySrcLoc, field_index: u32, ) CompileError!Air.Inst.Ref { - const tuple_ty = sema.typeOf(tuple); - const tuple_fields = tuple_ty.tupleFields(); + const tuple_ty = try sema.resolveTypeFields(sema.typeOf(tuple)); + const field_count = tuple_ty.structFieldCount(); - if (tuple_fields.types.len == 0) { + if (field_count == 0) { return sema.fail(block, tuple_src, "indexing into empty tuple is not allowed", .{}); } - if (field_index >= tuple_fields.types.len) { + if (field_index >= field_count) { return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{ - field_index, tuple_fields.types.len, + field_index, field_count, }); } - const field_ty = tuple_fields.types[field_index]; - const field_val = tuple_fields.values[field_index]; + const field_ty = tuple_ty.structFieldType(field_index); - if (field_val.tag() != .unreachable_value) { - return sema.addConstant(field_ty, field_val); // comptime field + if (tuple_ty.structFieldValueComptime(field_index)) |default_value| { + return sema.addConstant(field_ty, default_value); // comptime field } if (try sema.resolveMaybeUndefVal(tuple)) |tuple_val| { @@ -24277,7 +24204,7 @@ fn coerceExtra( // empty tuple to zero-length slice // note that this allows coercing to a mutable slice. - if (inst_child_ty.tupleFields().types.len == 0) { + if (inst_child_ty.structFieldCount() == 0) { const slice_val = try Value.Tag.slice.create(sema.arena, .{ .ptr = Value.undef, .len = Value.zero, @@ -25587,9 +25514,9 @@ fn storePtr2( // fields. const operand_ty = sema.typeOf(uncasted_operand); if (operand_ty.isTuple() and elem_ty.zigTypeTag() == .Array) { - const tuple = operand_ty.tupleFields(); - for (tuple.types) |_, i_usize| { - const i = @intCast(u32, i_usize); + const field_count = operand_ty.structFieldCount(); + var i: u32 = 0; + while (i < field_count) : (i += 1) { const elem_src = operand_src; // TODO better source location const elem = try sema.tupleField(block, operand_src, uncasted_operand, elem_src, i); 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 const inst_info = inst_ty.ptrInfo().data; const len0 = (inst_info.pointee_type.zigTypeTag() == .Array and (inst_info.pointee_type.arrayLenIncludingSentinel() == 0 or (inst_info.pointee_type.arrayLen() == 0 and dest_info.sentinel == null and dest_info.size != .C and dest_info.size != .Many))) or - (inst_info.pointee_type.isTuple() and inst_info.pointee_type.tupleFields().types.len == 0); + (inst_info.pointee_type.isTuple() and inst_info.pointee_type.structFieldCount() == 0); const ok_cv_qualifiers = ((inst_info.mutable or !dest_info.mutable) or len0) and @@ -27166,18 +27093,18 @@ fn coerceTupleToStruct( mem.set(Air.Inst.Ref, field_refs, .none); const inst_ty = sema.typeOf(inst); - const tuple = inst_ty.tupleFields(); var runtime_src: ?LazySrcLoc = null; - for (tuple.types) |_, i_usize| { - const i = @intCast(u32, i_usize); + const field_count = struct_ty.structFieldCount(); + var field_i: u32 = 0; + while (field_i < field_count) : (field_i += 1) { const field_src = inst_src; // TODO better source location const field_name = if (inst_ty.castTag(.anon_struct)) |payload| - payload.data.names[i] + payload.data.names[field_i] else - try std.fmt.allocPrint(sema.arena, "{d}", .{i}); + try std.fmt.allocPrint(sema.arena, "{d}", .{field_i}); const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src); const field = fields.values()[field_index]; - const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, i); + const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i); const coerced = try sema.coerce(block, field.ty, elem_ref, field_src); field_refs[field_index] = coerced; if (field.is_comptime) { @@ -27186,7 +27113,7 @@ fn coerceTupleToStruct( }; if (!init_val.eql(field.default_val, field.ty, sema.mod)) { - return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, i); + return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i); } } if (runtime_src == null) { @@ -27255,15 +27182,14 @@ fn coerceTupleToTuple( mem.set(Air.Inst.Ref, field_refs, .none); const inst_ty = sema.typeOf(inst); - const tuple = inst_ty.tupleFields(); var runtime_src: ?LazySrcLoc = null; - for (tuple.types) |_, i_usize| { - const i = @intCast(u32, i_usize); + var field_i: u32 = 0; + while (field_i < field_count) : (field_i += 1) { const field_src = inst_src; // TODO better source location const field_name = if (inst_ty.castTag(.anon_struct)) |payload| - payload.data.names[i] + payload.data.names[field_i] else - try std.fmt.allocPrint(sema.arena, "{d}", .{i}); + try std.fmt.allocPrint(sema.arena, "{d}", .{field_i}); if (mem.eql(u8, field_name, "len")) { return sema.fail(block, field_src, "cannot assign to 'len' field of tuple", .{}); @@ -27271,9 +27197,9 @@ fn coerceTupleToTuple( const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_src); - const field_ty = tuple_ty.structFieldType(i); - const default_val = tuple_ty.structFieldDefaultValue(i); - const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, i); + const field_ty = tuple_ty.structFieldType(field_i); + const default_val = tuple_ty.structFieldDefaultValue(field_i); + const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i); const coerced = try sema.coerce(block, field_ty, elem_ref, field_src); field_refs[field_index] = coerced; if (default_val.tag() != .unreachable_value) { @@ -27282,7 +27208,7 @@ fn coerceTupleToTuple( }; if (!init_val.eql(default_val, field_ty, sema.mod)) { - return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, i); + return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i); } } if (runtime_src == null) { @@ -29665,6 +29591,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void block_scope.params.deinit(gpa); } + struct_obj.fields = .{}; try struct_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len); const Field = struct { @@ -29699,8 +29626,11 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void const has_type_body = @truncate(u1, cur_bit_bag) != 0; cur_bit_bag >>= 1; - const field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]); - extra_index += 1; + var field_name_zir: ?[:0]const u8 = null; + if (!small.is_tuple) { + field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]); + extra_index += 1; + } extra_index += 1; // doc_comment fields[field_i] = .{}; @@ -29713,7 +29643,10 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void extra_index += 1; // This string needs to outlive the ZIR code. - const field_name = try decl_arena_allocator.dupe(u8, field_name_zir); + const field_name = if (field_name_zir) |some| + try decl_arena_allocator.dupe(u8, some) + else + try std.fmt.allocPrint(decl_arena_allocator, "{d}", .{field_i}); const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name); if (gop.found_existing) { diff --git a/src/codegen/c.zig b/src/codegen/c.zig index a06f8e76dd..5c459e7d9b 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -1791,7 +1791,7 @@ pub const DeclGen = struct { }, .Struct, .Union => |tag| if (tag == .Struct and t.containerLayout() == .Packed) try dg.renderType(w, t.castTag(.@"struct").?.data.backing_int_ty, kind) - else if (t.isTupleOrAnonStruct()) { + else if (t.isSimpleTupleOrAnonStruct()) { const ExpectedContents = struct { types: [8]Type, values: [8]Value }; var stack align(@alignOf(ExpectedContents)) = std.heap.stackFallback(@sizeOf(ExpectedContents), dg.gpa); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index d34336701a..67073ac56e 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1951,7 +1951,7 @@ pub const Object = struct { break :blk fwd_decl; }; - if (ty.isTupleOrAnonStruct()) { + if (ty.isSimpleTupleOrAnonStruct()) { const tuple = ty.tupleFields(); var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{}; @@ -2885,7 +2885,7 @@ pub const DeclGen = struct { // reference, we need to copy it here. gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator()); - if (t.isTupleOrAnonStruct()) { + if (t.isSimpleTupleOrAnonStruct()) { const tuple = t.tupleFields(); const llvm_struct_ty = dg.context.structCreateNamed(""); gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls @@ -3579,7 +3579,7 @@ pub const DeclGen = struct { const field_vals = tv.val.castTag(.aggregate).?.data; const gpa = dg.gpa; - if (tv.ty.isTupleOrAnonStruct()) { + if (tv.ty.isSimpleTupleOrAnonStruct()) { const tuple = tv.ty.tupleFields(); var llvm_fields: std.ArrayListUnmanaged(*llvm.Value) = .{}; defer llvm_fields.deinit(gpa); @@ -10247,7 +10247,7 @@ fn llvmFieldIndex( var offset: u64 = 0; var big_align: u32 = 0; - if (ty.isTupleOrAnonStruct()) { + if (ty.isSimpleTupleOrAnonStruct()) { const tuple = ty.tupleFields(); var llvm_field_index: c_uint = 0; for (tuple.types) |field_ty, i| { @@ -10810,7 +10810,7 @@ fn isByRef(ty: Type) bool { .Struct => { // Packed structs are represented to LLVM as integers. if (ty.containerLayout() == .Packed) return false; - if (ty.isTupleOrAnonStruct()) { + if (ty.isSimpleTupleOrAnonStruct()) { const tuple = ty.tupleFields(); var count: usize = 0; for (tuple.values) |field_val, i| { diff --git a/src/type.zig b/src/type.zig index 6afee8bc73..66be76ff31 100644 --- a/src/type.zig +++ b/src/type.zig @@ -4494,6 +4494,7 @@ pub const Type = extern union { .mut_slice, .tuple, .empty_struct_literal, + .@"struct", => return null, .pointer => return self.castTag(.pointer).?.data.sentinel, @@ -5571,11 +5572,7 @@ pub const Type = extern union { pub fn structFieldCount(ty: Type) usize { switch (ty.tag()) { - .@"struct" => { - const struct_obj = ty.castTag(.@"struct").?.data; - assert(struct_obj.haveFieldTypes()); - return struct_obj.fields.count(); - }, + .@"struct" => return ty.castTag(.@"struct").?.data.fields.count(), .empty_struct, .empty_struct_literal => return 0, .tuple => return ty.castTag(.tuple).?.data.types.len, .anon_struct => return ty.castTag(.anon_struct).?.data.types.len, @@ -6178,6 +6175,7 @@ pub const Type = extern union { pub fn isTuple(ty: Type) bool { return switch (ty.tag()) { .tuple, .empty_struct_literal => true, + .@"struct" => ty.castTag(.@"struct").?.data.is_tuple, else => false, }; } @@ -6192,10 +6190,26 @@ pub const Type = extern union { pub fn isTupleOrAnonStruct(ty: Type) bool { return switch (ty.tag()) { .tuple, .empty_struct_literal, .anon_struct => true, + .@"struct" => ty.castTag(.@"struct").?.data.is_tuple, + else => false, + }; + } + + pub fn isSimpleTuple(ty: Type) bool { + return switch (ty.tag()) { + .tuple, .empty_struct_literal => true, + else => false, + }; + } + + pub fn isSimpleTupleOrAnonStruct(ty: Type) bool { + return switch (ty.tag()) { + .tuple, .empty_struct_literal, .anon_struct => true, else => false, }; } + // Only allowed for simple tuple types pub fn tupleFields(ty: Type) Payload.Tuple.Data { return switch (ty.tag()) { .tuple => ty.castTag(.tuple).?.data, diff --git a/src/value.zig b/src/value.zig index 43c31905ca..94769b4da7 100644 --- a/src/value.zig +++ b/src/value.zig @@ -2209,7 +2209,7 @@ pub const Value = extern union { const b_field_vals = b.castTag(.aggregate).?.data; assert(a_field_vals.len == b_field_vals.len); - if (ty.isTupleOrAnonStruct()) { + if (ty.isSimpleTupleOrAnonStruct()) { const types = ty.tupleFields().types; assert(types.len == a_field_vals.len); for (types) |field_ty, i| { @@ -3004,7 +3004,7 @@ pub const Value = extern union { .the_only_possible_value => return ty.onePossibleValue().?, .empty_struct_value => { - if (ty.isTupleOrAnonStruct()) { + if (ty.isSimpleTupleOrAnonStruct()) { const tuple = ty.tupleFields(); return tuple.values[index]; } |
