aboutsummaryrefslogtreecommitdiff
path: root/src/type.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-03-22 00:23:54 -0700
committerAndrew Kelley <andrew@ziglang.org>2022-03-22 15:45:58 -0700
commit593130ce0a4b06185fcb4806f8330857a1da9f92 (patch)
treeae30c61a06e6cecb97cc760dc6acd0cbfb83c162 /src/type.zig
parentb74f2924102fe06addb688dc5fd039dc2756f619 (diff)
downloadzig-593130ce0a4b06185fcb4806f8330857a1da9f92.tar.gz
zig-593130ce0a4b06185fcb4806f8330857a1da9f92.zip
stage2: lazy `@alignOf`
Add a `target` parameter to every function that deals with Type and Value.
Diffstat (limited to 'src/type.zig')
-rw-r--r--src/type.zig736
1 files changed, 488 insertions, 248 deletions
diff --git a/src/type.zig b/src/type.zig
index 6d27150412..0b49eac0a8 100644
--- a/src/type.zig
+++ b/src/type.zig
@@ -6,6 +6,7 @@ const Target = std.Target;
const Module = @import("Module.zig");
const log = std.log.scoped(.Type);
const target_util = @import("target.zig");
+const TypedValue = @import("TypedValue.zig");
const file_struct = @This();
@@ -520,7 +521,7 @@ pub const Type = extern union {
}
}
- pub fn eql(a: Type, b: Type) bool {
+ pub fn eql(a: Type, b: Type, target: Target) bool {
// As a shortcut, if the small tags / addresses match, we're done.
if (a.tag_if_small_enough == b.tag_if_small_enough) return true;
@@ -636,7 +637,7 @@ pub const Type = extern union {
const a_info = a.fnInfo();
const b_info = b.fnInfo();
- if (!eql(a_info.return_type, b_info.return_type))
+ if (!eql(a_info.return_type, b_info.return_type, target))
return false;
if (a_info.cc != b_info.cc)
@@ -662,7 +663,7 @@ pub const Type = extern union {
if (a_param_ty.tag() == .generic_poison) continue;
if (b_param_ty.tag() == .generic_poison) continue;
- if (!eql(a_param_ty, b_param_ty))
+ if (!eql(a_param_ty, b_param_ty, target))
return false;
}
@@ -680,13 +681,13 @@ pub const Type = extern union {
if (a.arrayLen() != b.arrayLen())
return false;
const elem_ty = a.elemType();
- if (!elem_ty.eql(b.elemType()))
+ if (!elem_ty.eql(b.elemType(), target))
return false;
const sentinel_a = a.sentinel();
const sentinel_b = b.sentinel();
if (sentinel_a) |sa| {
if (sentinel_b) |sb| {
- return sa.eql(sb, elem_ty);
+ return sa.eql(sb, elem_ty, target);
} else {
return false;
}
@@ -717,7 +718,7 @@ pub const Type = extern union {
const info_a = a.ptrInfo().data;
const info_b = b.ptrInfo().data;
- if (!info_a.pointee_type.eql(info_b.pointee_type))
+ if (!info_a.pointee_type.eql(info_b.pointee_type, target))
return false;
if (info_a.@"align" != info_b.@"align")
return false;
@@ -740,7 +741,7 @@ pub const Type = extern union {
const sentinel_b = info_b.sentinel;
if (sentinel_a) |sa| {
if (sentinel_b) |sb| {
- if (!sa.eql(sb, info_a.pointee_type))
+ if (!sa.eql(sb, info_a.pointee_type, target))
return false;
} else {
return false;
@@ -761,7 +762,7 @@ pub const Type = extern union {
var buf_a: Payload.ElemType = undefined;
var buf_b: Payload.ElemType = undefined;
- return a.optionalChild(&buf_a).eql(b.optionalChild(&buf_b));
+ return a.optionalChild(&buf_a).eql(b.optionalChild(&buf_b), target);
},
.anyerror_void_error_union, .error_union => {
@@ -769,18 +770,18 @@ pub const Type = extern union {
const a_set = a.errorUnionSet();
const b_set = b.errorUnionSet();
- if (!a_set.eql(b_set)) return false;
+ if (!a_set.eql(b_set, target)) return false;
const a_payload = a.errorUnionPayload();
const b_payload = b.errorUnionPayload();
- if (!a_payload.eql(b_payload)) return false;
+ if (!a_payload.eql(b_payload, target)) return false;
return true;
},
.anyframe_T => {
if (b.zigTypeTag() != .AnyFrame) return false;
- return a.childType().eql(b.childType());
+ return a.childType().eql(b.childType(), target);
},
.empty_struct => {
@@ -803,7 +804,7 @@ pub const Type = extern union {
for (a_tuple.types) |a_ty, i| {
const b_ty = b_tuple.types[i];
- if (!eql(a_ty, b_ty)) return false;
+ if (!eql(a_ty, b_ty, target)) return false;
}
for (a_tuple.values) |a_val, i| {
@@ -819,7 +820,7 @@ pub const Type = extern union {
if (b_val.tag() == .unreachable_value) {
return false;
} else {
- if (!Value.eql(a_val, b_val, ty)) return false;
+ if (!Value.eql(a_val, b_val, ty, target)) return false;
}
}
}
@@ -839,7 +840,7 @@ pub const Type = extern union {
for (a_struct_obj.types) |a_ty, i| {
const b_ty = b_struct_obj.types[i];
- if (!eql(a_ty, b_ty)) return false;
+ if (!eql(a_ty, b_ty, target)) return false;
}
for (a_struct_obj.values) |a_val, i| {
@@ -855,7 +856,7 @@ pub const Type = extern union {
if (b_val.tag() == .unreachable_value) {
return false;
} else {
- if (!Value.eql(a_val, b_val, ty)) return false;
+ if (!Value.eql(a_val, b_val, ty, target)) return false;
}
}
}
@@ -910,13 +911,13 @@ pub const Type = extern union {
}
}
- pub fn hash(self: Type) u64 {
+ pub fn hash(self: Type, target: Target) u64 {
var hasher = std.hash.Wyhash.init(0);
- self.hashWithHasher(&hasher);
+ self.hashWithHasher(&hasher, target);
return hasher.final();
}
- pub fn hashWithHasher(ty: Type, hasher: *std.hash.Wyhash) void {
+ pub fn hashWithHasher(ty: Type, hasher: *std.hash.Wyhash, target: Target) void {
switch (ty.tag()) {
.generic_poison => unreachable,
@@ -1035,7 +1036,7 @@ pub const Type = extern union {
std.hash.autoHash(hasher, std.builtin.TypeId.Fn);
const fn_info = ty.fnInfo();
- hashWithHasher(fn_info.return_type, hasher);
+ hashWithHasher(fn_info.return_type, hasher, target);
std.hash.autoHash(hasher, fn_info.alignment);
std.hash.autoHash(hasher, fn_info.cc);
std.hash.autoHash(hasher, fn_info.is_var_args);
@@ -1045,7 +1046,7 @@ pub const Type = extern union {
for (fn_info.param_types) |param_ty, i| {
std.hash.autoHash(hasher, fn_info.paramIsComptime(i));
if (param_ty.tag() == .generic_poison) continue;
- hashWithHasher(param_ty, hasher);
+ hashWithHasher(param_ty, hasher, target);
}
},
@@ -1058,8 +1059,8 @@ pub const Type = extern union {
const elem_ty = ty.elemType();
std.hash.autoHash(hasher, ty.arrayLen());
- hashWithHasher(elem_ty, hasher);
- hashSentinel(ty.sentinel(), elem_ty, hasher);
+ hashWithHasher(elem_ty, hasher, target);
+ hashSentinel(ty.sentinel(), elem_ty, hasher, target);
},
.vector => {
@@ -1067,7 +1068,7 @@ pub const Type = extern union {
const elem_ty = ty.elemType();
std.hash.autoHash(hasher, ty.vectorLen());
- hashWithHasher(elem_ty, hasher);
+ hashWithHasher(elem_ty, hasher, target);
},
.single_const_pointer_to_comptime_int,
@@ -1091,8 +1092,8 @@ pub const Type = extern union {
std.hash.autoHash(hasher, std.builtin.TypeId.Pointer);
const info = ty.ptrInfo().data;
- hashWithHasher(info.pointee_type, hasher);
- hashSentinel(info.sentinel, info.pointee_type, hasher);
+ hashWithHasher(info.pointee_type, hasher, target);
+ hashSentinel(info.sentinel, info.pointee_type, hasher, target);
std.hash.autoHash(hasher, info.@"align");
std.hash.autoHash(hasher, info.@"addrspace");
std.hash.autoHash(hasher, info.bit_offset);
@@ -1110,22 +1111,22 @@ pub const Type = extern union {
std.hash.autoHash(hasher, std.builtin.TypeId.Optional);
var buf: Payload.ElemType = undefined;
- hashWithHasher(ty.optionalChild(&buf), hasher);
+ hashWithHasher(ty.optionalChild(&buf), hasher, target);
},
.anyerror_void_error_union, .error_union => {
std.hash.autoHash(hasher, std.builtin.TypeId.ErrorUnion);
const set_ty = ty.errorUnionSet();
- hashWithHasher(set_ty, hasher);
+ hashWithHasher(set_ty, hasher, target);
const payload_ty = ty.errorUnionPayload();
- hashWithHasher(payload_ty, hasher);
+ hashWithHasher(payload_ty, hasher, target);
},
.anyframe_T => {
std.hash.autoHash(hasher, std.builtin.TypeId.AnyFrame);
- hashWithHasher(ty.childType(), hasher);
+ hashWithHasher(ty.childType(), hasher, target);
},
.empty_struct => {
@@ -1144,10 +1145,10 @@ pub const Type = extern union {
std.hash.autoHash(hasher, tuple.types.len);
for (tuple.types) |field_ty, i| {
- hashWithHasher(field_ty, hasher);
+ hashWithHasher(field_ty, hasher, target);
const field_val = tuple.values[i];
if (field_val.tag() == .unreachable_value) continue;
- field_val.hash(field_ty, hasher);
+ field_val.hash(field_ty, hasher, target);
}
},
.anon_struct => {
@@ -1159,9 +1160,9 @@ pub const Type = extern union {
const field_name = struct_obj.names[i];
const field_val = struct_obj.values[i];
hasher.update(field_name);
- hashWithHasher(field_ty, hasher);
+ hashWithHasher(field_ty, hasher, target);
if (field_val.tag() == .unreachable_value) continue;
- field_val.hash(field_ty, hasher);
+ field_val.hash(field_ty, hasher, target);
}
},
@@ -1209,35 +1210,35 @@ pub const Type = extern union {
}
}
- fn hashSentinel(opt_val: ?Value, ty: Type, hasher: *std.hash.Wyhash) void {
+ fn hashSentinel(opt_val: ?Value, ty: Type, hasher: *std.hash.Wyhash, target: Target) void {
if (opt_val) |s| {
std.hash.autoHash(hasher, true);
- s.hash(ty, hasher);
+ s.hash(ty, hasher, target);
} else {
std.hash.autoHash(hasher, false);
}
}
pub const HashContext64 = struct {
+ target: Target,
+
pub fn hash(self: @This(), t: Type) u64 {
- _ = self;
- return t.hash();
+ return t.hash(self.target);
}
pub fn eql(self: @This(), a: Type, b: Type) bool {
- _ = self;
- return a.eql(b);
+ return a.eql(b, self.target);
}
};
pub const HashContext32 = struct {
+ target: Target,
+
pub fn hash(self: @This(), t: Type) u32 {
- _ = self;
- return @truncate(u32, t.hash());
+ return @truncate(u32, t.hash(self.target));
}
pub fn eql(self: @This(), a: Type, b: Type, b_index: usize) bool {
- _ = self;
_ = b_index;
- return a.eql(b);
+ return a.eql(b, self.target);
}
};
@@ -1404,8 +1405,8 @@ pub const Type = extern union {
.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);
+ for (payload.param_types) |param_ty, i| {
+ param_types[i] = try param_ty.copy(allocator);
}
const other_comptime_params = payload.comptime_params[0..payload.param_types.len];
const comptime_params = try allocator.dupe(bool, other_comptime_params);
@@ -1474,14 +1475,42 @@ pub const Type = extern union {
return Type{ .ptr_otherwise = &new_payload.base };
}
- pub fn format(
+ pub fn format(ty: Type, comptime unused_fmt_string: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
+ _ = ty;
+ _ = unused_fmt_string;
+ _ = options;
+ _ = writer;
+ @compileError("do not format types directly; use either ty.fmtDebug() or ty.fmt()");
+ }
+
+ pub fn fmt(ty: Type, target: Target) std.fmt.Formatter(TypedValue.format) {
+ var ty_payload: Value.Payload.Ty = .{
+ .base = .{ .tag = .ty },
+ .data = ty,
+ };
+ return .{ .data = .{
+ .tv = .{
+ .ty = Type.type,
+ .val = Value.initPayload(&ty_payload.base),
+ },
+ .target = target,
+ } };
+ }
+
+ pub fn fmtDebug(ty: Type) std.fmt.Formatter(dump) {
+ return .{ .data = ty };
+ }
+
+ /// This is a debug function. In order to print types in a meaningful way
+ /// we also need access to the target.
+ pub fn dump(
start_type: Type,
- comptime fmt: []const u8,
+ comptime unused_format_string: []const u8,
options: std.fmt.FormatOptions,
writer: anytype,
) @TypeOf(writer).Error!void {
_ = options;
- comptime assert(fmt.len == 0);
+ comptime assert(unused_format_string.len == 0);
var ty = start_type;
while (true) {
const t = ty.tag();
@@ -1584,7 +1613,7 @@ pub const Type = extern union {
try writer.writeAll("fn(");
for (payload.param_types) |param_type, i| {
if (i != 0) try writer.writeAll(", ");
- try param_type.format("", .{}, writer);
+ try param_type.dump("", .{}, writer);
}
if (payload.is_var_args) {
if (payload.param_types.len != 0) {
@@ -1622,7 +1651,7 @@ pub const Type = extern union {
.vector => {
const payload = ty.castTag(.vector).?.data;
try writer.print("@Vector({d}, ", .{payload.len});
- try payload.elem_type.format("", .{}, writer);
+ try payload.elem_type.dump("", .{}, writer);
return writer.writeAll(")");
},
.array => {
@@ -1633,7 +1662,10 @@ pub const Type = extern union {
},
.array_sentinel => {
const payload = ty.castTag(.array_sentinel).?.data;
- try writer.print("[{d}:{}]", .{ payload.len, payload.sentinel.fmtValue(payload.elem_type) });
+ try writer.print("[{d}:{}]", .{
+ payload.len,
+ payload.sentinel.fmtDebug(),
+ });
ty = payload.elem_type;
continue;
},
@@ -1646,9 +1678,9 @@ pub const Type = extern union {
if (val.tag() != .unreachable_value) {
try writer.writeAll("comptime ");
}
- try field_ty.format("", .{}, writer);
+ try field_ty.dump("", .{}, writer);
if (val.tag() != .unreachable_value) {
- try writer.print(" = {}", .{val.fmtValue(field_ty)});
+ try writer.print(" = {}", .{val.fmtDebug()});
}
}
try writer.writeAll("}");
@@ -1665,9 +1697,9 @@ pub const Type = extern union {
}
try writer.writeAll(anon_struct.names[i]);
try writer.writeAll(": ");
- try field_ty.format("", .{}, writer);
+ try field_ty.dump("", .{}, writer);
if (val.tag() != .unreachable_value) {
- try writer.print(" = {}", .{val.fmtValue(field_ty)});
+ try writer.print(" = {}", .{val.fmtDebug()});
}
}
try writer.writeAll("}");
@@ -1752,8 +1784,8 @@ pub const Type = extern union {
const payload = ty.castTag(.pointer).?.data;
if (payload.sentinel) |some| switch (payload.size) {
.One, .C => unreachable,
- .Many => try writer.print("[*:{}]", .{some.fmtValue(payload.pointee_type)}),
- .Slice => try writer.print("[:{}]", .{some.fmtValue(payload.pointee_type)}),
+ .Many => try writer.print("[*:{}]", .{some.fmtDebug()}),
+ .Slice => try writer.print("[:{}]", .{some.fmtDebug()}),
} else switch (payload.size) {
.One => try writer.writeAll("*"),
.Many => try writer.writeAll("[*]"),
@@ -1780,7 +1812,7 @@ pub const Type = extern union {
},
.error_union => {
const payload = ty.castTag(.error_union).?.data;
- try payload.error_set.format("", .{}, writer);
+ try payload.error_set.dump("", .{}, writer);
try writer.writeAll("!");
ty = payload.payload;
continue;
@@ -1821,20 +1853,17 @@ pub const Type = extern union {
}
}
- pub fn nameAllocArena(ty: Type, arena: Allocator) Allocator.Error![:0]const u8 {
- return nameAllocAdvanced(ty, arena, true);
- }
+ pub const nameAllocArena = nameAlloc;
- pub fn nameAlloc(ty: Type, gpa: Allocator) Allocator.Error![:0]const u8 {
- return nameAllocAdvanced(ty, gpa, false);
+ pub fn nameAlloc(ty: Type, ally: Allocator, target: Target) Allocator.Error![:0]const u8 {
+ var buffer = std.ArrayList(u8).init(ally);
+ defer buffer.deinit();
+ try ty.print(buffer.writer(), target);
+ return buffer.toOwnedSliceSentinel(0);
}
- /// Returns a name suitable for `@typeName`.
- pub fn nameAllocAdvanced(
- ty: Type,
- ally: Allocator,
- is_arena: bool,
- ) Allocator.Error![:0]const u8 {
+ /// Prints a name suitable for `@typeName`.
+ pub fn print(ty: Type, writer: anytype, target: Target) @TypeOf(writer).Error!void {
const t = ty.tag();
switch (t) {
.inferred_alloc_const => unreachable,
@@ -1892,141 +1921,251 @@ pub const Type = extern union {
.comptime_int,
.comptime_float,
.noreturn,
- => return maybeDupe(@tagName(t), ally, is_arena),
+ => try writer.writeAll(@tagName(t)),
- .enum_literal => return maybeDupe("@TypeOf(.enum_literal)", ally, is_arena),
- .@"null" => return maybeDupe("@TypeOf(null)", ally, is_arena),
- .@"undefined" => return maybeDupe("@TypeOf(undefined)", ally, is_arena),
- .empty_struct_literal => return maybeDupe("@TypeOf(.{})", ally, is_arena),
+ .enum_literal => try writer.writeAll("@TypeOf(.enum_literal)"),
+ .@"null" => try writer.writeAll("@TypeOf(null)"),
+ .@"undefined" => try writer.writeAll("@TypeOf(undefined)"),
+ .empty_struct_literal => try writer.writeAll("@TypeOf(.{})"),
.empty_struct => {
const namespace = ty.castTag(.empty_struct).?.data;
- var buffer = std.ArrayList(u8).init(ally);
- defer buffer.deinit();
- try namespace.renderFullyQualifiedName("", buffer.writer());
- return buffer.toOwnedSliceSentinel(0);
+ try namespace.renderFullyQualifiedName("", writer);
},
.@"struct" => {
const struct_obj = ty.castTag(.@"struct").?.data;
- return try struct_obj.owner_decl.getFullyQualifiedName(ally);
+ try struct_obj.owner_decl.renderFullyQualifiedName(writer);
},
.@"union", .union_tagged => {
const union_obj = ty.cast(Payload.Union).?.data;
- return try union_obj.owner_decl.getFullyQualifiedName(ally);
+ try union_obj.owner_decl.renderFullyQualifiedName(writer);
},
.enum_full, .enum_nonexhaustive => {
const enum_full = ty.cast(Payload.EnumFull).?.data;
- return try enum_full.owner_decl.getFullyQualifiedName(ally);
+ try enum_full.owner_decl.renderFullyQualifiedName(writer);
},
.enum_simple => {
const enum_simple = ty.castTag(.enum_simple).?.data;
- return try enum_simple.owner_decl.getFullyQualifiedName(ally);
+ try enum_simple.owner_decl.renderFullyQualifiedName(writer);
},
.enum_numbered => {
const enum_numbered = ty.castTag(.enum_numbered).?.data;
- return try enum_numbered.owner_decl.getFullyQualifiedName(ally);
+ try enum_numbered.owner_decl.renderFullyQualifiedName(writer);
},
.@"opaque" => {
const opaque_obj = ty.cast(Payload.Opaque).?.data;
- return try opaque_obj.owner_decl.getFullyQualifiedName(ally);
+ try opaque_obj.owner_decl.renderFullyQualifiedName(writer);
},
- .anyerror_void_error_union => return maybeDupe("anyerror!void", ally, is_arena),
- .const_slice_u8 => return maybeDupe("[]const u8", ally, is_arena),
- .const_slice_u8_sentinel_0 => return maybeDupe("[:0]const u8", ally, is_arena),
- .fn_noreturn_no_args => return maybeDupe("fn() noreturn", ally, is_arena),
- .fn_void_no_args => return maybeDupe("fn() void", ally, is_arena),
- .fn_naked_noreturn_no_args => return maybeDupe("fn() callconv(.Naked) noreturn", ally, is_arena),
- .fn_ccc_void_no_args => return maybeDupe("fn() callconv(.C) void", ally, is_arena),
- .single_const_pointer_to_comptime_int => return maybeDupe("*const comptime_int", ally, is_arena),
- .manyptr_u8 => return maybeDupe("[*]u8", ally, is_arena),
- .manyptr_const_u8 => return maybeDupe("[*]const u8", ally, is_arena),
- .manyptr_const_u8_sentinel_0 => return maybeDupe("[*:0]const u8", ally, is_arena),
+ .anyerror_void_error_union => try writer.writeAll("anyerror!void"),
+ .const_slice_u8 => try writer.writeAll("[]const u8"),
+ .const_slice_u8_sentinel_0 => try writer.writeAll("[:0]const u8"),
+ .fn_noreturn_no_args => try writer.writeAll("fn() noreturn"),
+ .fn_void_no_args => try writer.writeAll("fn() void"),
+ .fn_naked_noreturn_no_args => try writer.writeAll("fn() callconv(.Naked) noreturn"),
+ .fn_ccc_void_no_args => try writer.writeAll("fn() callconv(.C) void"),
+ .single_const_pointer_to_comptime_int => try writer.writeAll("*const comptime_int"),
+ .manyptr_u8 => try writer.writeAll("[*]u8"),
+ .manyptr_const_u8 => try writer.writeAll("[*]const u8"),
+ .manyptr_const_u8_sentinel_0 => try writer.writeAll("[*:0]const u8"),
.error_set_inferred => {
const func = ty.castTag(.error_set_inferred).?.data.func;
- var buf = std.ArrayList(u8).init(ally);
- defer buf.deinit();
- try buf.appendSlice("@typeInfo(@typeInfo(@TypeOf(");
- try func.owner_decl.renderFullyQualifiedName(buf.writer());
- try buf.appendSlice(")).Fn.return_type.?).ErrorUnion.error_set");
- return try buf.toOwnedSliceSentinel(0);
+ try writer.writeAll("@typeInfo(@typeInfo(@TypeOf(");
+ try func.owner_decl.renderFullyQualifiedName(writer);
+ try writer.writeAll(")).Fn.return_type.?).ErrorUnion.error_set");
},
.function => {
const fn_info = ty.fnInfo();
- var buf = std.ArrayList(u8).init(ally);
- defer buf.deinit();
- try buf.appendSlice("fn(");
- for (fn_info.param_types) |param_type, i| {
- if (i != 0) try buf.appendSlice(", ");
- const param_name = try param_type.nameAllocAdvanced(ally, is_arena);
- defer if (!is_arena) ally.free(param_name);
- try buf.appendSlice(param_name);
+ try writer.writeAll("fn(");
+ for (fn_info.param_types) |param_ty, i| {
+ if (i != 0) try writer.writeAll(", ");
+ try print(param_ty, writer, target);
}
if (fn_info.is_var_args) {
if (fn_info.param_types.len != 0) {
- try buf.appendSlice(", ");
+ try writer.writeAll(", ");
}
- try buf.appendSlice("...");
+ try writer.writeAll("...");
}
- try buf.appendSlice(") ");
+ try writer.writeAll(") ");
if (fn_info.cc != .Unspecified) {
- try buf.appendSlice("callconv(.");
- try buf.appendSlice(@tagName(fn_info.cc));
- try buf.appendSlice(") ");
+ try writer.writeAll("callconv(.");
+ try writer.writeAll(@tagName(fn_info.cc));
+ try writer.writeAll(") ");
}
if (fn_info.alignment != 0) {
- try buf.writer().print("align({d}) ", .{fn_info.alignment});
- }
- {
- const ret_ty_name = try fn_info.return_type.nameAllocAdvanced(ally, is_arena);
- defer if (!is_arena) ally.free(ret_ty_name);
- try buf.appendSlice(ret_ty_name);
+ try writer.print("align({d}) ", .{fn_info.alignment});
}
- return try buf.toOwnedSliceSentinel(0);
+ try print(fn_info.return_type, writer, target);
},
.error_union => {
const error_union = ty.castTag(.error_union).?.data;
+ try print(error_union.error_set, writer, target);
+ try writer.writeAll("!");
+ try print(error_union.payload, writer, target);
+ },
- var buf = std.ArrayList(u8).init(ally);
- defer buf.deinit();
+ .array_u8 => {
+ const len = ty.castTag(.array_u8).?.data;
+ try writer.print("[{d}]u8", .{len});
+ },
+ .array_u8_sentinel_0 => {
+ const len = ty.castTag(.array_u8_sentinel_0).?.data;
+ try writer.print("[{d}:0]u8", .{len});
+ },
+ .vector => {
+ const payload = ty.castTag(.vector).?.data;
+ try writer.print("@Vector({d}, ", .{payload.len});
+ try print(payload.elem_type, writer, target);
+ try writer.writeAll(")");
+ },
+ .array => {
+ const payload = ty.castTag(.array).?.data;
+ try writer.print("[{d}]", .{payload.len});
+ try print(payload.elem_type, writer, target);
+ },
+ .array_sentinel => {
+ const payload = ty.castTag(.array_sentinel).?.data;
+ try writer.print("[{d}:{}]", .{
+ payload.len,
+ payload.sentinel.fmtValue(payload.elem_type, target),
+ });
+ try print(payload.elem_type, writer, target);
+ },
+ .tuple => {
+ const tuple = ty.castTag(.tuple).?.data;
- {
- const err_set_ty_name = try error_union.error_set.nameAllocAdvanced(ally, is_arena);
- defer if (!is_arena) ally.free(err_set_ty_name);
- try buf.appendSlice(err_set_ty_name);
+ 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 print(field_ty, writer, target);
+ if (val.tag() != .unreachable_value) {
+ try writer.print(" = {}", .{val.fmtValue(field_ty, target)});
+ }
+ }
+ try writer.writeAll("}");
+ },
+ .anon_struct => {
+ const anon_struct = ty.castTag(.anon_struct).?.data;
+
+ try writer.writeAll("struct{");
+ for (anon_struct.types) |field_ty, i| {
+ if (i != 0) try writer.writeAll(", ");
+ const val = anon_struct.values[i];
+ if (val.tag() != .unreachable_value) {
+ try writer.writeAll("comptime ");
+ }
+ try writer.writeAll(anon_struct.names[i]);
+ try writer.writeAll(": ");
+
+ try print(field_ty, writer, target);
+
+ if (val.tag() != .unreachable_value) {
+ try writer.print(" = {}", .{val.fmtValue(field_ty, target)});
+ }
}
+ try writer.writeAll("}");
+ },
- try buf.appendSlice("!");
+ .pointer,
+ .single_const_pointer,
+ .single_mut_pointer,
+ .many_const_pointer,
+ .many_mut_pointer,
+ .c_const_pointer,
+ .c_mut_pointer,
+ .const_slice,
+ .mut_slice,
+ => {
+ const info = ty.ptrInfo().data;
- {
- const payload_ty_name = try error_union.payload.nameAllocAdvanced(ally, is_arena);
- defer if (!is_arena) ally.free(payload_ty_name);
- try buf.appendSlice(payload_ty_name);
+ if (info.sentinel) |s| switch (info.size) {
+ .One, .C => unreachable,
+ .Many => try writer.print("[*:{}]", .{s.fmtValue(info.pointee_type, target)}),
+ .Slice => try writer.print("[:{}]", .{s.fmtValue(info.pointee_type, target)}),
+ } else switch (info.size) {
+ .One => try writer.writeAll("*"),
+ .Many => try writer.writeAll("[*]"),
+ .C => try writer.writeAll("[*c]"),
+ .Slice => try writer.writeAll("[]"),
}
+ if (info.@"align" != 0 or info.host_size != 0) {
+ try writer.print("align({d}", .{info.@"align"});
- return try buf.toOwnedSliceSentinel(0);
- },
+ if (info.bit_offset != 0) {
+ try writer.print(":{d}:{d}", .{ info.bit_offset, info.host_size });
+ }
+ try writer.writeAll(") ");
+ }
+ if (info.@"addrspace" != .generic) {
+ try writer.print("addrspace(.{s}) ", .{@tagName(info.@"addrspace")});
+ }
+ if (!info.mutable) try writer.writeAll("const ");
+ if (info.@"volatile") try writer.writeAll("volatile ");
+ if (info.@"allowzero" and info.size != .C) try writer.writeAll("allowzero ");
- else => {
- // TODO this is wasteful and also an incorrect implementation of `@typeName`
- var buf = std.ArrayList(u8).init(ally);
- defer buf.deinit();
- try buf.writer().print("{}", .{ty});
- return try buf.toOwnedSliceSentinel(0);
+ try print(info.pointee_type, writer, target);
},
- }
- }
- fn maybeDupe(s: [:0]const u8, ally: Allocator, is_arena: bool) Allocator.Error![:0]const u8 {
- if (is_arena) {
- return s;
- } else {
- return try ally.dupeZ(u8, s);
+ .int_signed => {
+ const bits = ty.castTag(.int_signed).?.data;
+ return writer.print("i{d}", .{bits});
+ },
+ .int_unsigned => {
+ const bits = ty.castTag(.int_unsigned).?.data;
+ return writer.print("u{d}", .{bits});
+ },
+ .optional => {
+ const child_type = ty.castTag(.optional).?.data;
+ try writer.writeByte('?');
+ try print(child_type, writer, target);
+ },
+ .optional_single_mut_pointer => {
+ const pointee_type = ty.castTag(.optional_single_mut_pointer).?.data;
+ try writer.writeAll("?*");
+ try print(pointee_type, writer, target);
+ },
+ .optional_single_const_pointer => {
+ const pointee_type = ty.castTag(.optional_single_const_pointer).?.data;
+ try writer.writeAll("?*const ");
+ try print(pointee_type, writer, target);
+ },
+ .anyframe_T => {
+ const return_type = ty.castTag(.anyframe_T).?.data;
+ try writer.print("anyframe->", .{});
+ try print(return_type, writer, target);
+ },
+ .error_set => {
+ const names = ty.castTag(.error_set).?.data.names.keys();
+ try writer.writeAll("error{");
+ for (names) |name, i| {
+ if (i != 0) try writer.writeByte(',');
+ try writer.writeAll(name);
+ }
+ try writer.writeAll("}");
+ },
+ .error_set_single => {
+ const name = ty.castTag(.error_set_single).?.data;
+ return writer.print("error{{{s}}}", .{name});
+ },
+ .error_set_merged => {
+ const names = ty.castTag(.error_set_merged).?.data.keys();
+ try writer.writeAll("error{");
+ for (names) |name, i| {
+ if (i != 0) try writer.writeByte(',');
+ try writer.writeAll(name);
+ }
+ try writer.writeAll("}");
+ },
}
}
@@ -2518,8 +2657,33 @@ pub const Type = extern union {
}
/// Returns 0 for 0-bit types.
- pub fn abiAlignment(self: Type, target: Target) u32 {
- return switch (self.tag()) {
+ pub fn abiAlignment(ty: Type, target: Target) u32 {
+ return ty.abiAlignmentAdvanced(target, .eager).scalar;
+ }
+
+ /// May capture a reference to `ty`.
+ pub fn lazyAbiAlignment(ty: Type, target: Target, arena: Allocator) !Value {
+ switch (ty.abiAlignmentAdvanced(target, .{ .lazy = arena })) {
+ .val => |val| return try val,
+ .scalar => |x| return Value.Tag.int_u64.create(arena, x),
+ }
+ }
+
+ /// If you pass `eager` you will get back `scalar` and assert the type is resolved.
+ /// If you pass `lazy` you may get back `scalar` or `val`.
+ /// If `val` is returned, a reference to `ty` has been captured.
+ fn abiAlignmentAdvanced(
+ ty: Type,
+ target: Target,
+ strat: union(enum) {
+ eager,
+ lazy: Allocator,
+ },
+ ) union(enum) {
+ scalar: u32,
+ val: Allocator.Error!Value,
+ } {
+ return switch (ty.tag()) {
.u1,
.u8,
.i8,
@@ -2538,25 +2702,25 @@ pub const Type = extern union {
.extern_options,
.@"opaque",
.anyopaque,
- => return 1,
+ => return .{ .scalar = 1 },
.fn_noreturn_no_args, // represents machine code; not a pointer
.fn_void_no_args, // represents machine code; not a pointer
.fn_naked_noreturn_no_args, // represents machine code; not a pointer
.fn_ccc_void_no_args, // represents machine code; not a pointer
- => return target_util.defaultFunctionAlignment(target),
+ => return .{ .scalar = target_util.defaultFunctionAlignment(target) },
// represents machine code; not a pointer
.function => {
- const alignment = self.castTag(.function).?.data.alignment;
- if (alignment != 0) return alignment;
- return target_util.defaultFunctionAlignment(target);
+ const alignment = ty.castTag(.function).?.data.alignment;
+ if (alignment != 0) return .{ .scalar = alignment };
+ return .{ .scalar = target_util.defaultFunctionAlignment(target) };
},
- .i16, .u16 => return 2,
- .i32, .u32 => return 4,
- .i64, .u64 => return 8,
- .u128, .i128 => return 16,
+ .i16, .u16 => return .{ .scalar = 2 },
+ .i32, .u32 => return .{ .scalar = 4 },
+ .i64, .u64 => return .{ .scalar = 8 },
+ .u128, .i128 => return .{ .scalar = 16 },
.isize,
.usize,
@@ -2579,40 +2743,40 @@ pub const Type = extern union {
.manyptr_const_u8_sentinel_0,
.@"anyframe",
.anyframe_T,
- => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
-
- .c_short => return @divExact(CType.short.sizeInBits(target), 8),
- .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8),
- .c_int => return @divExact(CType.int.sizeInBits(target), 8),
- .c_uint => return @divExact(CType.uint.sizeInBits(target), 8),
- .c_long => return @divExact(CType.long.sizeInBits(target), 8),
- .c_ulong => return @divExact(CType.ulong.sizeInBits(target), 8),
- .c_longlong => return @divExact(CType.longlong.sizeInBits(target), 8),
- .c_ulonglong => return @divExact(CType.ulonglong.sizeInBits(target), 8),
-
- .f16 => return 2,
- .f32 => return 4,
- .f64 => return 8,
- .f128 => return 16,
+ => return .{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) },
+
+ .c_short => return .{ .scalar = @divExact(CType.short.sizeInBits(target), 8) },
+ .c_ushort => return .{ .scalar = @divExact(CType.ushort.sizeInBits(target), 8) },
+ .c_int => return .{ .scalar = @divExact(CType.int.sizeInBits(target), 8) },
+ .c_uint => return .{ .scalar = @divExact(CType.uint.sizeInBits(target), 8) },
+ .c_long => return .{ .scalar = @divExact(CType.long.sizeInBits(target), 8) },
+ .c_ulong => return .{ .scalar = @divExact(CType.ulong.sizeInBits(target), 8) },
+ .c_longlong => return .{ .scalar = @divExact(CType.longlong.sizeInBits(target), 8) },
+ .c_ulonglong => return .{ .scalar = @divExact(CType.ulonglong.sizeInBits(target), 8) },
+
+ .f16 => return .{ .scalar = 2 },
+ .f32 => return .{ .scalar = 4 },
+ .f64 => return .{ .scalar = 8 },
+ .f128 => return .{ .scalar = 16 },
.f80 => switch (target.cpu.arch) {
- .i386 => return 4,
- .x86_64 => return 16,
+ .i386 => return .{ .scalar = 4 },
+ .x86_64 => return .{ .scalar = 16 },
else => {
var payload: Payload.Bits = .{
.base = .{ .tag = .int_unsigned },
.data = 80,
};
const u80_ty = initPayload(&payload.base);
- return abiAlignment(u80_ty, target);
+ return .{ .scalar = abiAlignment(u80_ty, target) };
},
},
.c_longdouble => switch (CType.longdouble.sizeInBits(target)) {
- 16 => return abiAlignment(Type.f16, target),
- 32 => return abiAlignment(Type.f32, target),
- 64 => return abiAlignment(Type.f64, target),
- 80 => return abiAlignment(Type.f80, target),
- 128 => return abiAlignment(Type.f128, target),
+ 16 => return .{ .scalar = abiAlignment(Type.f16, target) },
+ 32 => return .{ .scalar = abiAlignment(Type.f32, target) },
+ 64 => return .{ .scalar = abiAlignment(Type.f64, target) },
+ 80 => return .{ .scalar = abiAlignment(Type.f80, target) },
+ 128 => return .{ .scalar = abiAlignment(Type.f128, target) },
else => unreachable,
},
@@ -2622,60 +2786,93 @@ pub const Type = extern union {
.anyerror,
.error_set_inferred,
.error_set_merged,
- => return 2, // TODO revisit this when we have the concept of the error tag type
+ => return .{ .scalar = 2 }, // TODO revisit this when we have the concept of the error tag type
- .array, .array_sentinel => return self.elemType().abiAlignment(target),
+ .array, .array_sentinel => return ty.elemType().abiAlignmentAdvanced(target, strat),
// TODO audit this - is there any more complicated logic to determine
// ABI alignment of vectors?
- .vector => return 16,
+ .vector => return .{ .scalar = 16 },
.int_signed, .int_unsigned => {
- const bits: u16 = self.cast(Payload.Bits).?.data;
- if (bits == 0) return 0;
- if (bits <= 8) return 1;
- if (bits <= 16) return 2;
- if (bits <= 32) return 4;
- if (bits <= 64) return 8;
- return 16;
+ const bits: u16 = ty.cast(Payload.Bits).?.data;
+ if (bits == 0) return .{ .scalar = 0 };
+ if (bits <= 8) return .{ .scalar = 1 };
+ if (bits <= 16) return .{ .scalar = 2 };
+ if (bits <= 32) return .{ .scalar = 4 };
+ if (bits <= 64) return .{ .scalar = 8 };
+ return .{ .scalar = 16 };
},
.optional => {
var buf: Payload.ElemType = undefined;
- const child_type = self.optionalChild(&buf);
- if (!child_type.hasRuntimeBits()) return 1;
+ const child_type = ty.optionalChild(&buf);
- if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())
- return @divExact(target.cpu.arch.ptrBitWidth(), 8);
+ if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr()) {
+ return .{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) };
+ }
- return child_type.abiAlignment(target);
+ switch (strat) {
+ .eager => {
+ if (!child_type.hasRuntimeBits()) return .{ .scalar = 1 };
+ return .{ .scalar = child_type.abiAlignment(target) };
+ },
+ .lazy => |arena| switch (child_type.abiAlignmentAdvanced(target, strat)) {
+ .scalar => |x| return .{ .scalar = @maximum(x, 1) },
+ .val => return .{ .val = Value.Tag.lazy_align.create(arena, ty) },
+ },
+ }
},
.error_union => {
- const data = self.castTag(.error_union).?.data;
- if (!data.error_set.hasRuntimeBits()) {
- return data.payload.abiAlignment(target);
- } else if (!data.payload.hasRuntimeBits()) {
- return data.error_set.abiAlignment(target);
+ const data = ty.castTag(.error_union).?.data;
+ switch (strat) {
+ .eager => {
+ if (!data.error_set.hasRuntimeBits()) {
+ return .{ .scalar = data.payload.abiAlignment(target) };
+ } else if (!data.payload.hasRuntimeBits()) {
+ return .{ .scalar = data.error_set.abiAlignment(target) };
+ }
+ return .{ .scalar = @maximum(
+ data.payload.abiAlignment(target),
+ data.error_set.abiAlignment(target),
+ ) };
+ },
+ .lazy => |arena| {
+ switch (data.payload.abiAlignmentAdvanced(target, strat)) {
+ .scalar => |payload_align| {
+ if (payload_align == 0) {
+ return data.error_set.abiAlignmentAdvanced(target, strat);
+ }
+ switch (data.error_set.abiAlignmentAdvanced(target, strat)) {
+ .scalar => |err_set_align| {
+ return .{ .scalar = @maximum(payload_align, err_set_align) };
+ },
+ .val => {},
+ }
+ },
+ .val => {},
+ }
+ return .{ .val = Value.Tag.lazy_align.create(arena, ty) };
+ },
}
- return @maximum(
- data.payload.abiAlignment(target),
- data.error_set.abiAlignment(target),
- );
},
.@"struct" => {
- const fields = self.structFields();
- if (self.castTag(.@"struct")) |payload| {
+ if (ty.castTag(.@"struct")) |payload| {
const struct_obj = payload.data;
- assert(struct_obj.haveLayout());
+ if (!struct_obj.haveLayout()) switch (strat) {
+ .eager => unreachable, // struct layout not resolved
+ .lazy => |arena| return .{ .val = Value.Tag.lazy_align.create(arena, ty) },
+ };
if (struct_obj.layout == .Packed) {
var buf: Type.Payload.Bits = undefined;
const int_ty = struct_obj.packedIntegerType(target, &buf);
- return int_ty.abiAlignment(target);
+ return .{ .scalar = int_ty.abiAlignment(target) };
}
}
+ const fields = ty.structFields();
var big_align: u32 = 0;
for (fields.values()) |field| {
if (!field.ty.hasRuntimeBits()) continue;
@@ -2683,31 +2880,45 @@ pub const Type = extern union {
const field_align = field.normalAlignment(target);
big_align = @maximum(big_align, field_align);
}
- return big_align;
+ return .{ .scalar = big_align };
},
.tuple, .anon_struct => {
- const tuple = self.tupleFields();
+ const tuple = ty.tupleFields();
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.hasRuntimeBits()) continue;
- const field_align = field_ty.abiAlignment(target);
- big_align = @maximum(big_align, field_align);
+ switch (field_ty.abiAlignmentAdvanced(target, strat)) {
+ .scalar => |field_align| big_align = @maximum(big_align, field_align),
+ .val => switch (strat) {
+ .eager => unreachable, // field type alignment not resolved
+ .lazy => |arena| return .{ .val = Value.Tag.lazy_align.create(arena, ty) },
+ },
+ }
}
- return big_align;
+ return .{ .scalar = big_align };
},
.enum_full, .enum_nonexhaustive, .enum_simple, .enum_numbered => {
var buffer: Payload.Bits = undefined;
- const int_tag_ty = self.intTagType(&buffer);
- return int_tag_ty.abiAlignment(target);
+ const int_tag_ty = ty.intTagType(&buffer);
+ return .{ .scalar = int_tag_ty.abiAlignment(target) };
+ },
+ .@"union" => switch (strat) {
+ .eager => {
+ // TODO pass `true` for have_tag when unions have a safety tag
+ return .{ .scalar = ty.castTag(.@"union").?.data.abiAlignment(target, false) };
+ },
+ .lazy => |arena| return .{ .val = Value.Tag.lazy_align.create(arena, ty) },
+ },
+ .union_tagged => switch (strat) {
+ .eager => {
+ return .{ .scalar = ty.castTag(.union_tagged).?.data.abiAlignment(target, true) };
+ },
+ .lazy => |arena| return .{ .val = Value.Tag.lazy_align.create(arena, ty) },
},
- // TODO pass `true` for have_tag when unions have a safety tag
- .@"union" => return self.castTag(.@"union").?.data.abiAlignment(target, false),
- .union_tagged => return self.castTag(.union_tagged).?.data.abiAlignment(target, true),
.empty_struct,
.void,
@@ -2719,7 +2930,7 @@ pub const Type = extern union {
.@"undefined",
.enum_literal,
.type_info,
- => return 0,
+ => return .{ .scalar = 0 },
.noreturn,
.inferred_alloc_const,
@@ -3392,10 +3603,7 @@ pub const Type = extern union {
.optional => {
const child_ty = self.castTag(.optional).?.data;
- // optionals of zero sized types behave like bools, not pointers
- if (!child_ty.hasRuntimeBits()) return false;
if (child_ty.zigTypeTag() != .Pointer) return false;
-
const info = child_ty.ptrInfo().data;
switch (info.size) {
.Slice, .C => return false,
@@ -3663,9 +3871,9 @@ pub const Type = extern union {
return union_obj.fields;
}
- pub fn unionFieldType(ty: Type, enum_tag: Value) Type {
+ pub fn unionFieldType(ty: Type, enum_tag: Value, target: Target) Type {
const union_obj = ty.cast(Payload.Union).?.data;
- const index = union_obj.tag_ty.enumTagFieldIndex(enum_tag).?;
+ const index = union_obj.tag_ty.enumTagFieldIndex(enum_tag, target).?;
assert(union_obj.haveFieldTypes());
return union_obj.fields.values()[index].ty;
}
@@ -4679,20 +4887,20 @@ pub const Type = extern union {
/// Asserts `ty` is an enum. `enum_tag` can either be `enum_field_index` or
/// an integer which represents the enum value. Returns the field index in
/// declaration order, or `null` if `enum_tag` does not match any field.
- pub fn enumTagFieldIndex(ty: Type, enum_tag: Value) ?usize {
+ pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, target: Target) ?usize {
if (enum_tag.castTag(.enum_field_index)) |payload| {
return @as(usize, payload.data);
}
const S = struct {
- fn fieldWithRange(int_ty: Type, int_val: Value, end: usize) ?usize {
+ fn fieldWithRange(int_ty: Type, int_val: Value, end: usize, tg: Target) ?usize {
if (int_val.compareWithZero(.lt)) return null;
var end_payload: Value.Payload.U64 = .{
.base = .{ .tag = .int_u64 },
.data = end,
};
const end_val = Value.initPayload(&end_payload.base);
- if (int_val.compare(.gte, end_val, int_ty)) return null;
- return @intCast(usize, int_val.toUnsignedInt());
+ if (int_val.compare(.gte, end_val, int_ty, tg)) return null;
+ return @intCast(usize, int_val.toUnsignedInt(tg));
}
};
switch (ty.tag()) {
@@ -4700,18 +4908,24 @@ pub const Type = extern union {
const enum_full = ty.cast(Payload.EnumFull).?.data;
const tag_ty = enum_full.tag_ty;
if (enum_full.values.count() == 0) {
- return S.fieldWithRange(tag_ty, enum_tag, enum_full.fields.count());
+ return S.fieldWithRange(tag_ty, enum_tag, enum_full.fields.count(), target);
} else {
- return enum_full.values.getIndexContext(enum_tag, .{ .ty = tag_ty });
+ return enum_full.values.getIndexContext(enum_tag, .{
+ .ty = tag_ty,
+ .target = target,
+ });
}
},
.enum_numbered => {
const enum_obj = ty.castTag(.enum_numbered).?.data;
const tag_ty = enum_obj.tag_ty;
if (enum_obj.values.count() == 0) {
- return S.fieldWithRange(tag_ty, enum_tag, enum_obj.fields.count());
+ return S.fieldWithRange(tag_ty, enum_tag, enum_obj.fields.count(), target);
} else {
- return enum_obj.values.getIndexContext(enum_tag, .{ .ty = tag_ty });
+ return enum_obj.values.getIndexContext(enum_tag, .{
+ .ty = tag_ty,
+ .target = target,
+ });
}
},
.enum_simple => {
@@ -4723,7 +4937,7 @@ pub const Type = extern union {
.data = bits,
};
const tag_ty = Type.initPayload(&buffer.base);
- return S.fieldWithRange(tag_ty, enum_tag, fields_len);
+ return S.fieldWithRange(tag_ty, enum_tag, fields_len, target);
},
.atomic_order,
.atomic_rmw_op,
@@ -5018,14 +5232,14 @@ pub const Type = extern union {
/// Asserts the type is an enum.
pub fn enumHasInt(ty: Type, int: Value, target: Target) bool {
const S = struct {
- fn intInRange(tag_ty: Type, int_val: Value, end: usize) bool {
+ fn intInRange(tag_ty: Type, int_val: Value, end: usize, tg: Target) bool {
if (int_val.compareWithZero(.lt)) return false;
var end_payload: Value.Payload.U64 = .{
.base = .{ .tag = .int_u64 },
.data = end,
};
const end_val = Value.initPayload(&end_payload.base);
- if (int_val.compare(.gte, end_val, tag_ty)) return false;
+ if (int_val.compare(.gte, end_val, tag_ty, tg)) return false;
return true;
}
};
@@ -5035,18 +5249,24 @@ pub const Type = extern union {
const enum_full = ty.castTag(.enum_full).?.data;
const tag_ty = enum_full.tag_ty;
if (enum_full.values.count() == 0) {
- return S.intInRange(tag_ty, int, enum_full.fields.count());
+ return S.intInRange(tag_ty, int, enum_full.fields.count(), target);
} else {
- return enum_full.values.containsContext(int, .{ .ty = tag_ty });
+ return enum_full.values.containsContext(int, .{
+ .ty = tag_ty,
+ .target = target,
+ });
}
},
.enum_numbered => {
const enum_obj = ty.castTag(.enum_numbered).?.data;
const tag_ty = enum_obj.tag_ty;
if (enum_obj.values.count() == 0) {
- return S.intInRange(tag_ty, int, enum_obj.fields.count());
+ return S.intInRange(tag_ty, int, enum_obj.fields.count(), target);
} else {
- return enum_obj.values.containsContext(int, .{ .ty = tag_ty });
+ return enum_obj.values.containsContext(int, .{
+ .ty = tag_ty,
+ .target = target,
+ });
}
},
.enum_simple => {
@@ -5058,7 +5278,7 @@ pub const Type = extern union {
.data = bits,
};
const tag_ty = Type.initPayload(&buffer.base);
- return S.intInRange(tag_ty, int, fields_len);
+ return S.intInRange(tag_ty, int, fields_len, target);
},
.atomic_order,
.atomic_rmw_op,
@@ -5070,7 +5290,7 @@ pub const Type = extern union {
.prefetch_options,
.export_options,
.extern_options,
- => @panic("TODO resolve std.builtin types"),
+ => unreachable,
else => unreachable,
}
@@ -5620,7 +5840,7 @@ pub const Type = extern union {
d.bit_offset == 0 and d.host_size == 0 and !d.@"allowzero" and !d.@"volatile")
{
if (d.sentinel) |sent| {
- if (!d.mutable and d.pointee_type.eql(Type.u8)) {
+ if (!d.mutable and d.pointee_type.eql(Type.u8, target)) {
switch (d.size) {
.Slice => {
if (sent.compareWithZero(.eq)) {
@@ -5635,7 +5855,7 @@ pub const Type = extern union {
else => {},
}
}
- } else if (!d.mutable and d.pointee_type.eql(Type.u8)) {
+ } else if (!d.mutable and d.pointee_type.eql(Type.u8, target)) {
switch (d.size) {
.Slice => return Type.initTag(.const_slice_u8),
.Many => return Type.initTag(.manyptr_const_u8),
@@ -5669,10 +5889,11 @@ pub const Type = extern union {
len: u64,
sent: ?Value,
elem_type: Type,
+ target: Target,
) Allocator.Error!Type {
- if (elem_type.eql(Type.u8)) {
+ if (elem_type.eql(Type.u8, target)) {
if (sent) |some| {
- if (some.eql(Value.zero, elem_type)) {
+ if (some.eql(Value.zero, elem_type, target)) {
return Tag.array_u8_sentinel_0.create(arena, len);
}
} else {
@@ -5715,6 +5936,25 @@ pub const Type = extern union {
}
}
+ pub fn errorUnion(
+ arena: Allocator,
+ error_set: Type,
+ payload: Type,
+ target: Target,
+ ) Allocator.Error!Type {
+ assert(error_set.zigTypeTag() == .ErrorSet);
+ if (error_set.eql(Type.@"anyerror", target) and
+ payload.eql(Type.void, target))
+ {
+ return Type.initTag(.anyerror_void_error_union);
+ }
+
+ return Type.Tag.error_union.create(arena, .{
+ .error_set = error_set,
+ .payload = payload,
+ });
+ }
+
pub fn smallestUnsignedBits(max: u64) u16 {
if (max == 0) return 0;
const base = std.math.log2(max);