aboutsummaryrefslogtreecommitdiff
path: root/src/type.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-12-30 19:57:11 -0700
committerAndrew Kelley <andrew@ziglang.org>2020-12-30 21:41:02 -0800
commit133da8692e80532797dd91b32539cf2175280a95 (patch)
tree8ff37b28c783d14be6aa459673202909de47b1ec /src/type.zig
parent2622575fde2b5d70926fe62ed272412d72eef7b0 (diff)
downloadzig-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.zig613
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,
};
};
};