diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-12-30 19:57:11 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2020-12-30 21:41:02 -0800 |
| commit | 133da8692e80532797dd91b32539cf2175280a95 (patch) | |
| tree | 8ff37b28c783d14be6aa459673202909de47b1ec /src/type.zig | |
| parent | 2622575fde2b5d70926fe62ed272412d72eef7b0 (diff) | |
| download | zig-133da8692e80532797dd91b32539cf2175280a95.tar.gz zig-133da8692e80532797dd91b32539cf2175280a95.zip | |
stage2: rework Type Payload layout
Add `Type.castTag` and note that it is preferable to call than
`Type.cast`. This matches other abstractions in the codebase.
Added a convenience function `Type.Tag.create` which really cleans up
the callsites of creating `Type` objects.
`Type` payloads can now share types. This is in preparation for another
improvement that I want to do.
Diffstat (limited to 'src/type.zig')
| -rw-r--r-- | src/type.zig | 613 |
1 files changed, 339 insertions, 274 deletions
diff --git a/src/type.zig b/src/type.zig index f08408738a..ce237f89c7 100644 --- a/src/type.zig +++ b/src/type.zig @@ -112,18 +112,39 @@ pub const Type = extern union { } } + /// Prefer `castTag` to this. pub fn cast(self: Type, comptime T: type) ?*T { - if (self.tag_if_small_enough < Tag.no_payload_count) + if (@hasField(T, "base_tag")) { + return base.castTag(T.base_tag); + } + if (self.tag_if_small_enough < Tag.no_payload_count) { return null; + } + inline for (@typeInfo(Tag).Enum.fields) |field| { + if (field.value < Tag.no_payload_count) + continue; + const t = @intToEnum(Tag, field.value); + if (self.ptr_otherwise.tag == t) { + if (T == t.Type()) { + return @fieldParentPtr(T, "base", self.ptr_otherwise); + } + return null; + } + } + unreachable; + } - const expected_tag = std.meta.fieldInfo(T, "base").default_value.?.tag; - if (self.ptr_otherwise.tag != expected_tag) + pub fn castTag(self: Type, comptime t: Tag) ?*t.Type() { + if (self.tag_if_small_enough < Tag.no_payload_count) return null; - return @fieldParentPtr(T, "base", self.ptr_otherwise); + if (self.ptr_otherwise.tag == t) + return @fieldParentPtr(t.Type(), "base", self.ptr_otherwise); + + return null; } - pub fn castPointer(self: Type) ?*Payload.PointerSimple { + pub fn castPointer(self: Type) ?*Payload.ElemType { return switch (self.tag()) { .single_const_pointer, .single_mut_pointer, @@ -135,7 +156,8 @@ pub const Type = extern union { .mut_slice, .optional_single_const_pointer, .optional_single_mut_pointer, - => @fieldParentPtr(Payload.PointerSimple, "base", self.ptr_otherwise), + => self.cast(Payload.ElemType), + else => null, }; } @@ -165,7 +187,7 @@ pub const Type = extern union { // Hot path for common case: if (a.castPointer()) |a_payload| { if (b.castPointer()) |b_payload| { - return a.tag() == b.tag() and eql(a_payload.pointee_type, b_payload.pointee_type); + return a.tag() == b.tag() and eql(a_payload.data, b_payload.data); } } const is_slice_a = isSlice(a); @@ -230,8 +252,8 @@ pub const Type = extern union { return true; }, .Optional => { - var buf_a: Payload.PointerSimple = undefined; - var buf_b: Payload.PointerSimple = undefined; + var buf_a: Payload.ElemType = undefined; + var buf_b: Payload.ElemType = undefined; return a.optionalChild(&buf_a).eql(b.optionalChild(&buf_b)); }, .Float, @@ -294,7 +316,7 @@ pub const Type = extern union { } }, .Optional => { - var buf: Payload.PointerSimple = undefined; + var buf: Payload.ElemType = undefined; std.hash.autoHash(&hasher, self.optionalChild(&buf).hash()); }, .Float, @@ -364,68 +386,64 @@ pub const Type = extern union { .@"anyframe", => unreachable, - .array_u8_sentinel_0 => return self.copyPayloadShallow(allocator, Payload.Array_u8_Sentinel0), - .array_u8 => return self.copyPayloadShallow(allocator, Payload.Array_u8), + .array_u8, + .array_u8_sentinel_0, + => return self.copyPayloadShallow(allocator, Payload.Len), + + .single_const_pointer, + .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, + .const_slice, + .mut_slice, + .optional, + .optional_single_mut_pointer, + .optional_single_const_pointer, + .anyframe_T, + => return self.copyPayloadShallow(allocator, Payload.ElemType), + + .int_signed, + .int_unsigned, + => return self.copyPayloadShallow(allocator, Payload.Bits), + .array => { - const payload = @fieldParentPtr(Payload.Array, "base", self.ptr_otherwise); - const new_payload = try allocator.create(Payload.Array); - new_payload.* = .{ - .base = payload.base, + const payload = self.castTag(.array).?.data; + return Tag.array.create(allocator, .{ .len = payload.len, .elem_type = try payload.elem_type.copy(allocator), - }; - return Type{ .ptr_otherwise = &new_payload.base }; + }); }, .array_sentinel => { - const payload = @fieldParentPtr(Payload.ArraySentinel, "base", self.ptr_otherwise); - const new_payload = try allocator.create(Payload.ArraySentinel); - new_payload.* = .{ - .base = payload.base, + const payload = self.castTag(.array_sentinel).?.data; + return Tag.array_sentinel.create(allocator, .{ .len = payload.len, .sentinel = try payload.sentinel.copy(allocator), .elem_type = try payload.elem_type.copy(allocator), - }; - return Type{ .ptr_otherwise = &new_payload.base }; + }); }, - .int_signed => return self.copyPayloadShallow(allocator, Payload.IntSigned), - .int_unsigned => return self.copyPayloadShallow(allocator, Payload.IntUnsigned), .function => { - const payload = @fieldParentPtr(Payload.Function, "base", self.ptr_otherwise); - const new_payload = try allocator.create(Payload.Function); + const payload = self.castTag(.function).?.data; const param_types = try allocator.alloc(Type, payload.param_types.len); for (payload.param_types) |param_type, i| { param_types[i] = try param_type.copy(allocator); } - new_payload.* = .{ - .base = payload.base, + return Tag.function.create(allocator, .{ .return_type = try payload.return_type.copy(allocator), .param_types = param_types, .cc = payload.cc, - }; - return Type{ .ptr_otherwise = &new_payload.base }; + }); }, - .optional => return self.copyPayloadSingleField(allocator, Payload.Optional, "child_type"), - .single_const_pointer, - .single_mut_pointer, - .many_const_pointer, - .many_mut_pointer, - .c_const_pointer, - .c_mut_pointer, - .const_slice, - .mut_slice, - .optional_single_mut_pointer, - .optional_single_const_pointer, - => return self.copyPayloadSingleField(allocator, Payload.PointerSimple, "pointee_type"), - .anyframe_T => return self.copyPayloadSingleField(allocator, Payload.AnyFrame, "return_type"), - .pointer => { - const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise); - const new_payload = try allocator.create(Payload.Pointer); - new_payload.* = .{ - .base = payload.base, - + const payload = self.castTag(.pointer).?.data; + const sent: ?Value = if (payload.sentinel) |some| + try some.copy(allocator) + else + null; + return Tag.pointer.create(allocator, .{ .pointee_type = try payload.pointee_type.copy(allocator), - .sentinel = if (payload.sentinel) |some| try some.copy(allocator) else null, + .sentinel = sent, .@"align" = payload.@"align", .bit_offset = payload.bit_offset, .host_size = payload.host_size, @@ -433,41 +451,28 @@ pub const Type = extern union { .mutable = payload.mutable, .@"volatile" = payload.@"volatile", .size = payload.size, - }; - return Type{ .ptr_otherwise = &new_payload.base }; + }); }, .error_union => { - const payload = @fieldParentPtr(Payload.ErrorUnion, "base", self.ptr_otherwise); - const new_payload = try allocator.create(Payload.ErrorUnion); - new_payload.* = .{ - .base = payload.base, - + const payload = self.castTag(.error_union).?.data; + return Tag.error_union.create(allocator, .{ .error_set = try payload.error_set.copy(allocator), .payload = try payload.payload.copy(allocator), - }; - return Type{ .ptr_otherwise = &new_payload.base }; + }); }, - .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet), - .error_set_single => return self.copyPayloadShallow(allocator, Payload.ErrorSetSingle), - .empty_struct => return self.copyPayloadShallow(allocator, Payload.EmptyStruct), + .error_set => return self.copyPayloadShallow(allocator, Payload.Decl), + .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name), + .empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope), } } fn copyPayloadShallow(self: Type, allocator: *Allocator, comptime T: type) error{OutOfMemory}!Type { - const payload = @fieldParentPtr(T, "base", self.ptr_otherwise); + const payload = self.cast(T).?; const new_payload = try allocator.create(T); new_payload.* = payload.*; return Type{ .ptr_otherwise = &new_payload.base }; } - fn copyPayloadSingleField(self: Type, allocator: *Allocator, comptime T: type, comptime field_name: []const u8) error{OutOfMemory}!Type { - const payload = @fieldParentPtr(T, "base", self.ptr_otherwise); - const new_payload = try allocator.create(T); - new_payload.base = payload.base; - @field(new_payload, field_name) = try @field(payload, field_name).copy(allocator); - return Type{ .ptr_otherwise = &new_payload.base }; - } - pub fn format( self: Type, comptime fmt: []const u8, @@ -527,7 +532,7 @@ pub const Type = extern union { .fn_ccc_void_no_args => return out_stream.writeAll("fn() callconv(.C) void"), .single_const_pointer_to_comptime_int => return out_stream.writeAll("*const comptime_int"), .function => { - const payload = @fieldParentPtr(Payload.Function, "base", ty.ptr_otherwise); + const payload = ty.castTag(.function).?.data; try out_stream.writeAll("fn("); for (payload.param_types) |param_type, i| { if (i != 0) try out_stream.writeAll(", "); @@ -539,108 +544,108 @@ pub const Type = extern union { }, .anyframe_T => { - const payload = @fieldParentPtr(Payload.AnyFrame, "base", ty.ptr_otherwise); + const return_type = ty.castTag(.anyframe_T).?.data; try out_stream.print("anyframe->", .{}); - ty = payload.return_type; + ty = return_type; continue; }, .array_u8 => { - const payload = @fieldParentPtr(Payload.Array_u8, "base", ty.ptr_otherwise); - return out_stream.print("[{}]u8", .{payload.len}); + const len = ty.castTag(.array_u8).?.data; + return out_stream.print("[{}]u8", .{len}); }, .array_u8_sentinel_0 => { - const payload = @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", ty.ptr_otherwise); - return out_stream.print("[{}:0]u8", .{payload.len}); + const len = ty.castTag(.array_u8_sentinel_0).?.data; + return out_stream.print("[{}:0]u8", .{len}); }, .array => { - const payload = @fieldParentPtr(Payload.Array, "base", ty.ptr_otherwise); + const payload = ty.castTag(.array).?.data; try out_stream.print("[{}]", .{payload.len}); ty = payload.elem_type; continue; }, .array_sentinel => { - const payload = @fieldParentPtr(Payload.ArraySentinel, "base", ty.ptr_otherwise); + const payload = ty.castTag(.array_sentinel).?.data; try out_stream.print("[{}:{}]", .{ payload.len, payload.sentinel }); ty = payload.elem_type; continue; }, .single_const_pointer => { - const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + const pointee_type = ty.castTag(.single_const_pointer).?.data; try out_stream.writeAll("*const "); - ty = payload.pointee_type; + ty = pointee_type; continue; }, .single_mut_pointer => { - const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + const pointee_type = ty.castTag(.single_mut_pointer).?.data; try out_stream.writeAll("*"); - ty = payload.pointee_type; + ty = pointee_type; continue; }, .many_const_pointer => { - const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + const pointee_type = ty.castTag(.many_const_pointer).?.data; try out_stream.writeAll("[*]const "); - ty = payload.pointee_type; + ty = pointee_type; continue; }, .many_mut_pointer => { - const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + const pointee_type = ty.castTag(.many_mut_pointer).?.data; try out_stream.writeAll("[*]"); - ty = payload.pointee_type; + ty = pointee_type; continue; }, .c_const_pointer => { - const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + const pointee_type = ty.castTag(.c_const_pointer).?.data; try out_stream.writeAll("[*c]const "); - ty = payload.pointee_type; + ty = pointee_type; continue; }, .c_mut_pointer => { - const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + const pointee_type = ty.castTag(.c_mut_pointer).?.data; try out_stream.writeAll("[*c]"); - ty = payload.pointee_type; + ty = pointee_type; continue; }, .const_slice => { - const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + const pointee_type = ty.castTag(.const_slice).?.data; try out_stream.writeAll("[]const "); - ty = payload.pointee_type; + ty = pointee_type; continue; }, .mut_slice => { - const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + const pointee_type = ty.castTag(.mut_slice).?.data; try out_stream.writeAll("[]"); - ty = payload.pointee_type; + ty = pointee_type; continue; }, .int_signed => { - const payload = @fieldParentPtr(Payload.IntSigned, "base", ty.ptr_otherwise); - return out_stream.print("i{}", .{payload.bits}); + const bits = ty.castTag(.int_signed).?.data; + return out_stream.print("i{d}", .{bits}); }, .int_unsigned => { - const payload = @fieldParentPtr(Payload.IntUnsigned, "base", ty.ptr_otherwise); - return out_stream.print("u{}", .{payload.bits}); + const bits = ty.castTag(.int_unsigned).?.data; + return out_stream.print("u{d}", .{bits}); }, .optional => { - const payload = @fieldParentPtr(Payload.Optional, "base", ty.ptr_otherwise); + const child_type = ty.castTag(.optional).?.data; try out_stream.writeByte('?'); - ty = payload.child_type; + ty = child_type; continue; }, .optional_single_const_pointer => { - const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + const pointee_type = ty.castTag(.optional_single_const_pointer).?.data; try out_stream.writeAll("?*const "); - ty = payload.pointee_type; + ty = pointee_type; continue; }, .optional_single_mut_pointer => { - const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + const pointee_type = ty.castTag(.optional_single_mut_pointer).?.data; try out_stream.writeAll("?*"); - ty = payload.pointee_type; + ty = pointee_type; continue; }, .pointer => { - const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); + const payload = ty.castTag(.pointer).?.data; if (payload.sentinel) |some| switch (payload.size) { .One, .C => unreachable, .Many => try out_stream.print("[*:{}]", .{some}), @@ -652,10 +657,10 @@ pub const Type = extern union { .Slice => try out_stream.writeAll("[]"), } if (payload.@"align" != 0) { - try out_stream.print("align({}", .{payload.@"align"}); + try out_stream.print("align({d}", .{payload.@"align"}); if (payload.bit_offset != 0) { - try out_stream.print(":{}:{}", .{ payload.bit_offset, payload.host_size }); + try out_stream.print(":{d}:{d}", .{ payload.bit_offset, payload.host_size }); } try out_stream.writeAll(") "); } @@ -667,19 +672,19 @@ pub const Type = extern union { continue; }, .error_union => { - const payload = @fieldParentPtr(Payload.ErrorUnion, "base", ty.ptr_otherwise); + const payload = ty.castTag(.error_union).?.data; try payload.error_set.format("", .{}, out_stream); try out_stream.writeAll("!"); ty = payload.payload; continue; }, .error_set => { - const payload = @fieldParentPtr(Payload.ErrorSet, "base", ty.ptr_otherwise); - return out_stream.writeAll(std.mem.spanZ(payload.decl.name)); + const decl = ty.castTag(.error_set).?.data; + return out_stream.writeAll(std.mem.spanZ(decl.name)); }, .error_set_single => { - const payload = @fieldParentPtr(Payload.ErrorSetSingle, "base", ty.ptr_otherwise); - return out_stream.print("error{{{}}}", .{payload.name}); + const name = ty.castTag(.error_set_single).?.data; + return out_stream.print("error{{{s}}}", .{name}); }, } unreachable; @@ -784,11 +789,10 @@ pub const Type = extern union { .array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0, .array_u8 => self.arrayLen() != 0, .array_sentinel, .single_const_pointer, .single_mut_pointer, .many_const_pointer, .many_mut_pointer, .c_const_pointer, .c_mut_pointer, .const_slice, .mut_slice, .pointer => self.elemType().hasCodeGenBits(), - .int_signed => self.cast(Payload.IntSigned).?.bits != 0, - .int_unsigned => self.cast(Payload.IntUnsigned).?.bits != 0, + .int_signed, .int_unsigned => self.cast(Payload.Bits).?.data != 0, .error_union => { - const payload = self.cast(Payload.ErrorUnion).?; + const payload = self.castTag(.error_union).?.data; return payload.error_set.hasCodeGenBits() or payload.payload.hasCodeGenBits(); }, @@ -855,7 +859,7 @@ pub const Type = extern union { => return @divExact(target.cpu.arch.ptrBitWidth(), 8), .pointer => { - const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise); + const payload = self.castTag(.pointer).?.data; if (payload.@"align" != 0) return payload.@"align"; return @divExact(target.cpu.arch.ptrBitWidth(), 8); @@ -885,18 +889,12 @@ pub const Type = extern union { .array, .array_sentinel => return self.elemType().abiAlignment(target), .int_signed, .int_unsigned => { - const bits: u16 = if (self.cast(Payload.IntSigned)) |pl| - pl.bits - else if (self.cast(Payload.IntUnsigned)) |pl| - pl.bits - else - unreachable; - + const bits: u16 = self.cast(Payload.Bits).?.data; return std.math.ceilPowerOfTwoPromote(u16, (bits + 7) / 8); }, .optional => { - var buf: Payload.PointerSimple = undefined; + var buf: Payload.ElemType = undefined; const child_type = self.optionalChild(&buf); if (!child_type.hasCodeGenBits()) return 1; @@ -907,7 +905,7 @@ pub const Type = extern union { }, .error_union => { - const payload = self.cast(Payload.ErrorUnion).?; + const payload = self.castTag(.error_union).?.data; if (!payload.error_set.hasCodeGenBits()) { return payload.payload.abiAlignment(target); } else if (!payload.payload.hasCodeGenBits()) { @@ -955,16 +953,19 @@ pub const Type = extern union { .bool, => return 1, - .array_u8 => @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", self.ptr_otherwise).len, - .array_u8_sentinel_0 => @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", self.ptr_otherwise).len + 1, + .array_u8 => self.castTag(.array_u8).?.data, + .array_u8_sentinel_0 => self.castTag(.array_u8_sentinel_0).?.data + 1, .array => { - const payload = @fieldParentPtr(Payload.Array, "base", self.ptr_otherwise); + const payload = self.castTag(.array).?.data; const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target)); return payload.len * elem_size; }, .array_sentinel => { - const payload = @fieldParentPtr(Payload.ArraySentinel, "base", self.ptr_otherwise); - const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target)); + const payload = self.castTag(.array_sentinel).?.data; + const elem_size = std.math.max( + payload.elem_type.abiAlignment(target), + payload.elem_type.abiSize(target), + ); return (payload.len + 1) * elem_size; }, .i16, .u16 => return 2, @@ -1022,18 +1023,12 @@ pub const Type = extern union { => return 2, // TODO revisit this when we have the concept of the error tag type .int_signed, .int_unsigned => { - const bits: u16 = if (self.cast(Payload.IntSigned)) |pl| - pl.bits - else if (self.cast(Payload.IntUnsigned)) |pl| - pl.bits - else - unreachable; - + const bits: u16 = self.cast(Payload.Bits).?.data; return std.math.ceilPowerOfTwoPromote(u16, (bits + 7) / 8); }, .optional => { - var buf: Payload.PointerSimple = undefined; + var buf: Payload.ElemType = undefined; const child_type = self.optionalChild(&buf); if (!child_type.hasCodeGenBits()) return 1; @@ -1048,7 +1043,7 @@ pub const Type = extern union { }, .error_union => { - const payload = self.cast(Payload.ErrorUnion).?; + const payload = self.castTag(.error_union).?.data; if (!payload.error_set.hasCodeGenBits() and !payload.payload.hasCodeGenBits()) { return 0; } else if (!payload.error_set.hasCodeGenBits()) { @@ -1132,7 +1127,7 @@ pub const Type = extern union { .single_const_pointer_to_comptime_int, => true, - .pointer => self.cast(Payload.Pointer).?.size == .One, + .pointer => self.castTag(.pointer).?.data.size == .One, }; } @@ -1214,7 +1209,7 @@ pub const Type = extern union { .single_const_pointer_to_comptime_int, => .One, - .pointer => self.cast(Payload.Pointer).?.size, + .pointer => self.castTag(.pointer).?.data.size, }; } @@ -1289,7 +1284,7 @@ pub const Type = extern union { .const_slice_u8, => true, - .pointer => self.cast(Payload.Pointer).?.size == .Slice, + .pointer => self.castTag(.pointer).?.data.size == .Slice, }; } @@ -1364,7 +1359,7 @@ pub const Type = extern union { .const_slice, => true, - .pointer => !self.cast(Payload.Pointer).?.mutable, + .pointer => !self.castTag(.pointer).?.data.mutable, }; } @@ -1438,7 +1433,7 @@ pub const Type = extern union { => false, .pointer => { - const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise); + const payload = self.castTag(.pointer).?.data; return payload.@"volatile"; }, }; @@ -1514,7 +1509,7 @@ pub const Type = extern union { => false, .pointer => { - const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise); + const payload = self.castTag(.pointer).?.data; return payload.@"allowzero"; }, }; @@ -1525,7 +1520,7 @@ pub const Type = extern union { switch (self.tag()) { .optional_single_const_pointer, .optional_single_mut_pointer => return true, .optional => { - var buf: Payload.PointerSimple = undefined; + var buf: Payload.ElemType = undefined; const child_type = self.optionalChild(&buf); // optionals of zero sized pointers behave like bools if (!child_type.hasCodeGenBits()) return false; @@ -1563,7 +1558,7 @@ pub const Type = extern union { => return false, .Optional => { - var buf: Payload.PointerSimple = undefined; + var buf: Payload.ElemType = undefined; return ty.optionalChild(&buf).isValidVarType(is_extern); }, .Pointer, .Array => ty = ty.elemType(), @@ -1631,8 +1626,8 @@ pub const Type = extern union { .empty_struct, => unreachable, - .array => self.cast(Payload.Array).?.elem_type, - .array_sentinel => self.cast(Payload.ArraySentinel).?.elem_type, + .array => self.castTag(.array).?.data.elem_type, + .array_sentinel => self.castTag(.array_sentinel).?.data.elem_type, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1641,28 +1636,29 @@ pub const Type = extern union { .c_mut_pointer, .const_slice, .mut_slice, - => self.castPointer().?.pointee_type, + => self.castPointer().?.data, .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8), .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int), - .pointer => self.cast(Payload.Pointer).?.pointee_type, + .pointer => self.castTag(.pointer).?.data.pointee_type, }; } /// Asserts that the type is an optional. - pub fn optionalChild(self: Type, buf: *Payload.PointerSimple) Type { + /// Resulting `Type` will have inner memory referencing `buf`. + pub fn optionalChild(self: Type, buf: *Payload.ElemType) Type { return switch (self.tag()) { - .optional => self.cast(Payload.Optional).?.child_type, + .optional => self.castTag(.optional).?.data, .optional_single_mut_pointer => { buf.* = .{ .base = .{ .tag = .single_mut_pointer }, - .pointee_type = self.castPointer().?.pointee_type, + .data = self.castPointer().?.data, }; return Type.initPayload(&buf.base); }, .optional_single_const_pointer => { buf.* = .{ .base = .{ .tag = .single_const_pointer }, - .pointee_type = self.castPointer().?.pointee_type, + .data = self.castPointer().?.data, }; return Type.initPayload(&buf.base); }, @@ -1673,23 +1669,16 @@ pub const Type = extern union { /// Asserts that the type is an optional. /// Same as `optionalChild` but allocates the buffer if needed. pub fn optionalChildAlloc(self: Type, allocator: *Allocator) !Type { - return switch (self.tag()) { - .optional => self.cast(Payload.Optional).?.child_type, - .optional_single_mut_pointer, .optional_single_const_pointer => { - const payload = try allocator.create(Payload.PointerSimple); - payload.* = .{ - .base = .{ - .tag = if (self.tag() == .optional_single_const_pointer) - .single_const_pointer - else - .single_mut_pointer, - }, - .pointee_type = self.castPointer().?.pointee_type, - }; - return Type.initPayload(&payload.base); + switch (self.tag()) { + .optional => return self.castTag(.optional).?.data, + .optional_single_mut_pointer => { + return Tag.single_mut_pointer.create(allocator, self.castPointer().?.data); + }, + .optional_single_const_pointer => { + return Tag.single_const_pointer.create(allocator, self.castPointer().?.data); }, else => unreachable, - }; + } } /// Asserts the type is an array or vector. @@ -1759,10 +1748,10 @@ pub const Type = extern union { .empty_struct, => unreachable, - .array => self.cast(Payload.Array).?.len, - .array_sentinel => self.cast(Payload.ArraySentinel).?.len, - .array_u8 => self.cast(Payload.Array_u8).?.len, - .array_u8_sentinel_0 => self.cast(Payload.Array_u8_Sentinel0).?.len, + .array => self.castTag(.array).?.data.len, + .array_sentinel => self.castTag(.array_sentinel).?.data.len, + .array_u8 => self.castTag(.array_u8).?.data, + .array_u8_sentinel_0 => self.castTag(.array_u8_sentinel_0).?.data, }; } @@ -1836,8 +1825,8 @@ pub const Type = extern union { .array_u8, => return null, - .pointer => return self.cast(Payload.Pointer).?.sentinel, - .array_sentinel => return self.cast(Payload.ArraySentinel).?.sentinel, + .pointer => return self.castTag(.pointer).?.data.sentinel, + .array_sentinel => return self.castTag(.array_sentinel).?.data.sentinel, .array_u8_sentinel_0 => return Value.initTag(.zero), }; } @@ -2048,8 +2037,14 @@ pub const Type = extern union { .empty_struct, => unreachable, - .int_unsigned => .{ .signedness = .unsigned, .bits = self.cast(Payload.IntUnsigned).?.bits }, - .int_signed => .{ .signedness = .signed, .bits = self.cast(Payload.IntSigned).?.bits }, + .int_unsigned => .{ + .signedness = .unsigned, + .bits = self.castTag(.int_unsigned).?.data, + }, + .int_signed => .{ + .signedness = .signed, + .bits = self.castTag(.int_signed).?.data, + }, .u8 => .{ .signedness = .unsigned, .bits = 8 }, .i8 => .{ .signedness = .signed, .bits = 8 }, .u16 => .{ .signedness = .unsigned, .bits = 16 }, @@ -2178,7 +2173,7 @@ pub const Type = extern union { .fn_void_no_args => 0, .fn_naked_noreturn_no_args => 0, .fn_ccc_void_no_args => 0, - .function => @fieldParentPtr(Payload.Function, "base", self.ptr_otherwise).param_types.len, + .function => self.castTag(.function).?.data.param_types.len, .f16, .f32, @@ -2254,7 +2249,7 @@ pub const Type = extern union { .fn_naked_noreturn_no_args => return, .fn_ccc_void_no_args => return, .function => { - const payload = @fieldParentPtr(Payload.Function, "base", self.ptr_otherwise); + const payload = self.castTag(.function).?.data; std.mem.copy(Type, types, payload.param_types); }, @@ -2327,7 +2322,7 @@ pub const Type = extern union { pub fn fnParamType(self: Type, index: usize) Type { switch (self.tag()) { .function => { - const payload = @fieldParentPtr(Payload.Function, "base", self.ptr_otherwise); + const payload = self.castTag(.function).?.data; return payload.param_types[index]; }, @@ -2410,7 +2405,7 @@ pub const Type = extern union { .fn_ccc_void_no_args, => Type.initTag(.void), - .function => @fieldParentPtr(Payload.Function, "base", self.ptr_otherwise).return_type, + .function => self.castTag(.function).?.data.return_type, .f16, .f32, @@ -2484,7 +2479,7 @@ pub const Type = extern union { .fn_void_no_args => .Unspecified, .fn_naked_noreturn_no_args => .Naked, .fn_ccc_void_no_args => .C, - .function => @fieldParentPtr(Payload.Function, "base", self.ptr_otherwise).cc, + .function => self.castTag(.function).?.data.cc, .f16, .f32, @@ -2760,15 +2755,8 @@ pub const Type = extern union { .@"null" => return Value.initTag(.null_value), .@"undefined" => return Value.initTag(.undef), - .int_unsigned => { - if (ty.cast(Payload.IntUnsigned).?.bits == 0) { - return Value.initTag(.zero); - } else { - return null; - } - }, - .int_signed => { - if (ty.cast(Payload.IntSigned).?.bits == 0) { + .int_unsigned, .int_signed => { + if (ty.cast(Payload.Bits).?.data == 0) { return Value.initTag(.zero); } else { return null; @@ -2787,12 +2775,11 @@ pub const Type = extern union { .single_const_pointer, .single_mut_pointer, => { - const ptr = ty.castPointer().?; - ty = ptr.pointee_type; + ty = ty.castPointer().?.data; continue; }, .pointer => { - ty = ty.cast(Payload.Pointer).?.pointee_type; + ty = ty.castTag(.pointer).?.data.pointee_type; continue; }, }; @@ -2869,7 +2856,7 @@ pub const Type = extern union { .c_mut_pointer, => return true, - .pointer => self.cast(Payload.Pointer).?.size == .C, + .pointer => self.castTag(.pointer).?.data.size == .C, }; } @@ -2950,7 +2937,7 @@ pub const Type = extern union { .pointer, => unreachable, - .empty_struct => self.cast(Type.Payload.EmptyStruct).?.scope, + .empty_struct => self.castTag(.empty_struct).?.data, }; } @@ -3105,117 +3092,195 @@ pub const Type = extern union { pub const last_no_payload_tag = Tag.const_slice_u8; pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; - }; - pub const Payload = struct { - tag: Tag, + pub fn Type(comptime t: Tag) type { + return switch (t) { + .u8, + .i8, + .u16, + .i16, + .u32, + .i32, + .u64, + .i64, + .usize, + .isize, + .c_short, + .c_ushort, + .c_int, + .c_uint, + .c_long, + .c_ulong, + .c_longlong, + .c_ulonglong, + .c_longdouble, + .f16, + .f32, + .f64, + .f128, + .c_void, + .bool, + .void, + .type, + .anyerror, + .comptime_int, + .comptime_float, + .noreturn, + .enum_literal, + .@"null", + .@"undefined", + .fn_noreturn_no_args, + .fn_void_no_args, + .fn_naked_noreturn_no_args, + .fn_ccc_void_no_args, + .single_const_pointer_to_comptime_int, + .anyerror_void_error_union, + .@"anyframe", + .const_slice_u8, + => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"), + + .array_u8, + .array_u8_sentinel_0, + => Payload.Len, + + .single_const_pointer, + .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, + .const_slice, + .mut_slice, + .optional, + .optional_single_mut_pointer, + .optional_single_const_pointer, + .anyframe_T, + => Payload.ElemType, + + .int_signed, + .int_unsigned, + => Payload.Bits, + + .array => Payload.Array, + .array_sentinel => Payload.ArraySentinel, + .pointer => Payload.Pointer, + .function => Payload.Function, + .error_union => Payload.ErrorUnion, + .error_set => Payload.Decl, + .error_set_single => Payload.Name, + .empty_struct => Payload.ContainerScope, + }; + } - pub const Array_u8_Sentinel0 = struct { - base: Payload = Payload{ .tag = .array_u8_sentinel_0 }, + pub fn create(comptime t: Tag, ally: *Allocator, data: Data(t)) error{OutOfMemory}!Type { + const ptr = try ally.create(t.Type()); + ptr.* = .{ + .base = .{ .tag = t }, + .data = data, + }; + return Type{ .ptr_otherwise = &ptr.base }; + } - len: u64, - }; + pub fn Data(comptime t: Tag) type { + return std.meta.fieldInfo(t.Type(), "data").field_type; + } + }; - pub const Array_u8 = struct { - base: Payload = Payload{ .tag = .array_u8 }, + /// The sub-types are named after what fields they contain. + pub const Payload = struct { + tag: Tag, - len: u64, + pub const Len = struct { + base: Payload, + data: u64, }; pub const Array = struct { - base: Payload = Payload{ .tag = .array }, + pub const base_tag = Tag.array; - len: u64, - elem_type: Type, + base: Payload = Payload{ .tag = base_tag }, + data: struct { + len: u64, + elem_type: Type, + }, }; pub const ArraySentinel = struct { - base: Payload = Payload{ .tag = .array_sentinel }, + pub const base_tag = Tag.array_sentinel; - len: u64, - sentinel: Value, - elem_type: Type, + base: Payload = Payload{ .tag = base_tag }, + data: struct { + len: u64, + sentinel: Value, + elem_type: Type, + }, }; - pub const PointerSimple = struct { + pub const ElemType = struct { base: Payload, - - pointee_type: Type, + data: Type, }; - pub const IntSigned = struct { - base: Payload = Payload{ .tag = .int_signed }, - - bits: u16, - }; - - pub const IntUnsigned = struct { - base: Payload = Payload{ .tag = .int_unsigned }, - - bits: u16, + pub const Bits = struct { + base: Payload, + data: u16, }; pub const Function = struct { - base: Payload = Payload{ .tag = .function }, - - param_types: []Type, - return_type: Type, - cc: std.builtin.CallingConvention, - }; - - pub const Optional = struct { - base: Payload = Payload{ .tag = .optional }, + pub const base_tag = Tag.function; - child_type: Type, + base: Payload = Payload{ .tag = base_tag }, + data: struct { + param_types: []Type, + return_type: Type, + cc: std.builtin.CallingConvention, + }, }; pub const Pointer = struct { - base: Payload = .{ .tag = .pointer }, - - pointee_type: Type, - sentinel: ?Value, - /// If zero use pointee_type.AbiAlign() - @"align": u32, - bit_offset: u16, - host_size: u16, - @"allowzero": bool, - mutable: bool, - @"volatile": bool, - size: std.builtin.TypeInfo.Pointer.Size, + pub const base_tag = Tag.pointer; + + base: Payload = Payload{ .tag = base_tag }, + data: struct { + pointee_type: Type, + sentinel: ?Value, + /// If zero use pointee_type.AbiAlign() + @"align": u32, + bit_offset: u16, + host_size: u16, + @"allowzero": bool, + mutable: bool, + @"volatile": bool, + size: std.builtin.TypeInfo.Pointer.Size, + }, }; pub const ErrorUnion = struct { - base: Payload = .{ .tag = .error_union }, + pub const base_tag = Tag.error_union; - error_set: Type, - payload: Type, - }; - - pub const AnyFrame = struct { - base: Payload = .{ .tag = .anyframe_T }, - - return_type: Type, + base: Payload = Payload{ .tag = base_tag }, + data: struct { + error_set: Type, + payload: Type, + }, }; - pub const ErrorSet = struct { - base: Payload = .{ .tag = .error_set }, - - decl: *Module.Decl, + pub const Decl = struct { + base: Payload, + data: *Module.Decl, }; - pub const ErrorSetSingle = struct { - base: Payload = .{ .tag = .error_set_single }, - + pub const Name = struct { + base: Payload, /// memory is owned by `Module` - name: []const u8, + data: []const u8, }; /// Mostly used for namespace like structs with zero fields. /// Most commonly used for files. - pub const EmptyStruct = struct { - base: Payload = .{ .tag = .empty_struct }, - - scope: *Module.Scope.Container, + pub const ContainerScope = struct { + base: Payload, + data: *Module.Scope.Container, }; }; }; |
