diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2022-01-20 00:33:51 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2022-01-20 16:17:16 -0700 |
| commit | e86ff712a666ab5be54fa763cc12a5f245718117 (patch) | |
| tree | 90166386cac32112afbb0c087453cf22938a2702 /src/type.zig | |
| parent | eb70f6e8d7f4c1a735fe25de368f6d5459cba16c (diff) | |
| download | zig-e86ff712a666ab5be54fa763cc12a5f245718117.tar.gz zig-e86ff712a666ab5be54fa763cc12a5f245718117.zip | |
stage2: implement tuples
* AIR instruction vector_init gains the ability to init arrays and
tuples in addition to vectors. This will probably also gain the
ability to initialize structs and be renamed to `aggregate_init`.
* AstGen prefers to use an `anon_array_init` ZIR instruction for
local variables when the init expr is an array literal and there is
no type.
Diffstat (limited to 'src/type.zig')
| -rw-r--r-- | src/type.zig | 183 |
1 files changed, 172 insertions, 11 deletions
diff --git a/src/type.zig b/src/type.zig index f62c94c469..f7d8795162 100644 --- a/src/type.zig +++ b/src/type.zig @@ -128,6 +128,7 @@ pub const Type = extern union { .prefetch_options, .export_options, .extern_options, + .tuple, => return .Struct, .enum_full, @@ -604,6 +605,24 @@ pub const Type = extern union { return a_payload.data == b_payload.data; } } + if (a.castTag(.tuple)) |a_payload| { + if (b.castTag(.tuple)) |b_payload| { + if (a_payload.data.types.len != b_payload.data.types.len) return false; + + for (a_payload.data.types) |a_ty, i| { + const b_ty = b_payload.data.types[i]; + if (!eql(a_ty, b_ty)) return false; + } + + for (a_payload.data.values) |a_val, i| { + const ty = a_payload.data.types[i]; + const b_val = b_payload.data.values[i]; + if (!Value.eql(a_val, b_val, ty)) return false; + } + + return true; + } + } return a.tag() == b.tag(); }, .Enum => { @@ -891,6 +910,21 @@ pub const Type = extern union { .elem_type = try payload.elem_type.copy(allocator), }); }, + .tuple => { + const payload = self.castTag(.tuple).?.data; + const types = try allocator.alloc(Type, payload.types.len); + const values = try allocator.alloc(Value, payload.values.len); + for (payload.types) |ty, i| { + types[i] = try ty.copy(allocator); + } + for (payload.values) |val, i| { + values[i] = try val.copy(allocator); + } + return Tag.tuple.create(allocator, .{ + .types = types, + .values = values, + }); + }, .function => { const payload = self.castTag(.function).?.data; const param_types = try allocator.alloc(Type, payload.param_types.len); @@ -1119,6 +1153,24 @@ pub const Type = extern union { ty = payload.elem_type; continue; }, + .tuple => { + const tuple = ty.castTag(.tuple).?.data; + try writer.writeAll("tuple{"); + for (tuple.types) |field_ty, i| { + if (i != 0) try writer.writeAll(", "); + const val = tuple.values[i]; + if (val.tag() != .unreachable_value) { + try writer.writeAll("comptime "); + } + try field_ty.format("", .{}, writer); + if (val.tag() != .unreachable_value) { + try writer.writeAll(" = "); + try val.format("", .{}, writer); + } + } + try writer.writeAll("}"); + return; + }, .single_const_pointer => { const pointee_type = ty.castTag(.single_const_pointer).?.data; try writer.writeAll("*const "); @@ -1480,15 +1532,40 @@ pub const Type = extern union { return requiresComptime(optionalChild(ty, &buf)); }, - .error_union, - .anyframe_T, - .@"struct", - .@"union", - .union_tagged, - .enum_numbered, - .enum_full, - .enum_nonexhaustive, - => false, // TODO some of these should be `true` depending on their child types + .tuple => { + const tuple = ty.castTag(.tuple).?.data; + for (tuple.types) |field_ty| { + if (requiresComptime(field_ty)) { + return true; + } + } + return false; + }, + + .@"struct" => { + const struct_obj = ty.castTag(.@"struct").?.data; + for (struct_obj.fields.values()) |field| { + if (requiresComptime(field.ty)) { + return true; + } + } + return false; + }, + + .@"union", .union_tagged => { + const union_obj = ty.cast(Payload.Union).?.data; + for (union_obj.fields.values()) |field| { + if (requiresComptime(field.ty)) { + return true; + } + } + return false; + }, + + .error_union => return requiresComptime(errorUnionPayload(ty)), + .anyframe_T => return ty.castTag(.anyframe_T).?.data.requiresComptime(), + .enum_numbered => return ty.castTag(.enum_numbered).?.data.tag_ty.requiresComptime(), + .enum_full, .enum_nonexhaustive => return ty.cast(Payload.EnumFull).?.data.tag_ty.requiresComptime(), }; } @@ -1697,6 +1774,16 @@ pub const Type = extern union { return payload.error_set.hasCodeGenBits() or payload.payload.hasCodeGenBits(); }, + .tuple => { + const tuple = self.castTag(.tuple).?.data; + for (tuple.types) |ty, i| { + const val = tuple.values[i]; + if (val.tag() != .unreachable_value) continue; // comptime field + if (ty.hasCodeGenBits()) return true; + } + return false; + }, + .void, .type, .comptime_int, @@ -1968,6 +2055,21 @@ pub const Type = extern union { } return big_align; }, + + .tuple => { + const tuple = self.castTag(.tuple).?.data; + var big_align: u32 = 0; + for (tuple.types) |field_ty, i| { + const val = tuple.values[i]; + if (val.tag() != .unreachable_value) continue; // comptime field + if (!field_ty.hasCodeGenBits()) continue; + + const field_align = field_ty.abiAlignment(target); + big_align = @maximum(big_align, field_align); + } + return big_align; + }, + .enum_full, .enum_nonexhaustive, .enum_simple, .enum_numbered => { var buffer: Payload.Bits = undefined; const int_tag_ty = self.intTagType(&buffer); @@ -2037,13 +2139,14 @@ pub const Type = extern union { .void, => 0, - .@"struct" => { + .@"struct", .tuple => { const field_count = self.structFieldCount(); if (field_count == 0) { return 0; } return self.structFieldOffset(field_count, target); }, + .enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => { var buffer: Payload.Bits = undefined; const int_tag_ty = self.intTagType(&buffer); @@ -2231,6 +2334,11 @@ pub const Type = extern union { } return total; }, + + .tuple => { + @panic("TODO bitSize tuples"); + }, + .enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => { var buffer: Payload.Bits = undefined; const int_tag_ty = ty.intTagType(&buffer); @@ -2926,6 +3034,7 @@ pub const Type = extern union { pub fn containerLayout(ty: Type) std.builtin.TypeInfo.ContainerLayout { return switch (ty.tag()) { + .tuple => .Auto, .@"struct" => ty.castTag(.@"struct").?.data.layout, .@"union" => ty.castTag(.@"union").?.data.layout, .union_tagged => ty.castTag(.union_tagged).?.data.layout, @@ -2998,6 +3107,7 @@ pub const Type = extern union { .array_sentinel => ty.castTag(.array_sentinel).?.data.len, .array_u8 => ty.castTag(.array_u8).?.data, .array_u8_sentinel_0 => ty.castTag(.array_u8_sentinel_0).?.data, + .tuple => ty.castTag(.tuple).?.data.types.len, else => unreachable, }; @@ -3010,6 +3120,7 @@ pub const Type = extern union { pub fn vectorLen(ty: Type) u32 { return switch (ty.tag()) { .vector => @intCast(u32, ty.castTag(.vector).?.data.len), + .tuple => @intCast(u32, ty.castTag(.tuple).?.data.types.len), else => unreachable, }; } @@ -3463,6 +3574,17 @@ pub const Type = extern union { } return Value.initTag(.empty_struct_value); }, + + .tuple => { + const tuple = ty.castTag(.tuple).?.data; + for (tuple.values) |val| { + if (val.tag() == .unreachable_value) { + return null; // non-comptime field + } + } + return Value.initTag(.empty_struct_value); + }, + .enum_numbered => { const enum_numbered = ty.castTag(.enum_numbered).?.data; if (enum_numbered.fields.count() == 1) { @@ -3539,7 +3661,8 @@ pub const Type = extern union { .Slice, .Many, .C => true, .One => ty.elemType().zigTypeTag() == .Array, }, - else => false, // TODO tuples are indexable + .Struct => ty.tag() == .tuple, + else => false, }; } @@ -3766,6 +3889,7 @@ pub const Type = extern union { return struct_obj.fields.count(); }, .empty_struct => return 0, + .tuple => return ty.castTag(.tuple).?.data.types.len, else => unreachable, } } @@ -3781,6 +3905,7 @@ pub const Type = extern union { const union_obj = ty.cast(Payload.Union).?.data; return union_obj.fields.values()[index].ty; }, + .tuple => return ty.castTag(.tuple).?.data.types[index], else => unreachable, } } @@ -3933,6 +4058,31 @@ pub const Type = extern union { it.offset = std.mem.alignForwardGeneric(u64, it.offset, it.big_align); return it.offset; }, + + .tuple => { + const tuple = ty.castTag(.tuple).?.data; + + var offset: u64 = 0; + var big_align: u32 = 0; + + for (tuple.types) |field_ty, i| { + const field_val = tuple.values[i]; + if (field_val.tag() != .unreachable_value) { + // comptime field + if (i == index) return offset; + continue; + } + + const field_align = field_ty.abiAlignment(target); + big_align = @maximum(big_align, field_align); + offset = std.mem.alignForwardGeneric(u64, offset, field_align); + if (i == index) return offset; + offset += field_ty.abiSize(target); + } + offset = std.mem.alignForwardGeneric(u64, offset, big_align); + return offset; + }, + .@"union" => return 0, .union_tagged => { const union_obj = ty.castTag(.union_tagged).?.data; @@ -4182,6 +4332,8 @@ pub const Type = extern union { array, array_sentinel, vector, + /// Possible Value tags for this: @"struct" + tuple, pointer, single_const_pointer, single_mut_pointer, @@ -4326,6 +4478,7 @@ pub const Type = extern union { .enum_simple => Payload.EnumSimple, .enum_numbered => Payload.EnumNumbered, .empty_struct => Payload.ContainerScope, + .tuple => Payload.Tuple, }; } @@ -4490,6 +4643,14 @@ pub const Type = extern union { data: *Module.Struct, }; + pub const Tuple = struct { + base: Payload = .{ .tag = .tuple }, + data: struct { + types: []Type, + values: []Value, + }, + }; + pub const Union = struct { base: Payload, data: *Module.Union, |
