From b40d36c90ba894a12f2de4e6c881642edffad3ed Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 6 Apr 2021 17:43:56 -0700 Subject: stage2: implement simple enums A simple enum is an enum which has an automatic integer tag type, all tag values automatically assigned, and no top level declarations. Such enums are created directly in AstGen and shared by all the generic/comptime instantiations of the surrounding ZIR code. This commit implements, but does not yet add any test cases for, simple enums. A full enum is an enum for which any of the above conditions are not true. Full enums are created in Sema, and therefore will create a unique type per generic/comptime instantiation. This commit does not implement full enums. However the `enum_decl_nonexhaustive` ZIR instruction is added and the respective Type functions are filled out. This commit makes an improvement to ZIR code, removing the decls array and removing the decl_map from AstGen. Instead, decl_ref and decl_val ZIR instructions index into the `owner_decl.dependencies` ArrayHashMap. We already need this dependencies array for incremental compilation purposes, and so repurposing it to also use it for ZIR decl indexes makes for efficient memory usage. Similarly, this commit fixes up incorrect memory management by removing the `const` ZIR instruction. The two places it was used stored memory in the AstGen arena, which may get freed after Sema. Now it properly sets up a new anonymous Decl for error sets and uses a normal decl_val instruction. The other usage of `const` ZIR instruction was float literals. These are now changed to use `float` ZIR instruction when the value fits inside `zir.Inst.Data` and `float128` otherwise. AstGen + Sema: implement int_to_enum and enum_to_int. No tests yet; I expect to have to make some fixes before they will pass tests. Will do that in the branch before merging. AstGen: fix struct astgen incorrectly counting decls as fields. Type/Value: give up on trying to exhaustively list every tag all the time. This makes the file more manageable. Also found a bug with i128/u128 this way, since the name of the function was more obvious when looking at the tag values. Type: implement abiAlignment and abiSize for structs. This will need to get more sophisticated at some point, but for now it is progress. Value: add new `enum_field_index` tag. Value: add hash_u32, needed when using ArrayHashMap. --- src/type.zig | 1857 ++++++++++------------------------------------------------ 1 file changed, 301 insertions(+), 1556 deletions(-) (limited to 'src/type.zig') diff --git a/src/type.zig b/src/type.zig index f5ce296e4d..c338072c15 100644 --- a/src/type.zig +++ b/src/type.zig @@ -93,9 +93,15 @@ pub const Type = extern union { .anyerror_void_error_union, .error_union => return .ErrorUnion, - .empty_struct => return .Struct, - .empty_struct_literal => return .Struct, - .@"struct" => return .Struct, + .empty_struct, + .empty_struct_literal, + .@"struct", + => return .Struct, + + .enum_full, + .enum_nonexhaustive, + .enum_simple, + => return .Enum, .var_args_param => unreachable, // can be any type } @@ -614,6 +620,8 @@ pub const Type = extern union { .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name), .empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope), .@"struct" => return self.copyPayloadShallow(allocator, Payload.Struct), + .enum_simple => return self.copyPayloadShallow(allocator, Payload.EnumSimple), + .enum_full, .enum_nonexhaustive => return self.copyPayloadShallow(allocator, Payload.EnumFull), .@"opaque" => return self.copyPayloadShallow(allocator, Payload.Opaque), } } @@ -629,8 +637,8 @@ pub const Type = extern union { self: Type, comptime fmt: []const u8, options: std.fmt.FormatOptions, - out_stream: anytype, - ) @TypeOf(out_stream).Error!void { + writer: anytype, + ) @TypeOf(writer).Error!void { comptime assert(fmt.len == 0); var ty = self; while (true) { @@ -670,132 +678,149 @@ pub const Type = extern union { .comptime_float, .noreturn, .var_args_param, - => return out_stream.writeAll(@tagName(t)), - - .enum_literal => return out_stream.writeAll("@Type(.EnumLiteral)"), - .@"null" => return out_stream.writeAll("@Type(.Null)"), - .@"undefined" => return out_stream.writeAll("@Type(.Undefined)"), - - .empty_struct, .empty_struct_literal => return out_stream.writeAll("struct {}"), - .@"struct" => return out_stream.writeAll("(struct)"), - .anyerror_void_error_union => return out_stream.writeAll("anyerror!void"), - .const_slice_u8 => return out_stream.writeAll("[]const u8"), - .fn_noreturn_no_args => return out_stream.writeAll("fn() noreturn"), - .fn_void_no_args => return out_stream.writeAll("fn() void"), - .fn_naked_noreturn_no_args => return out_stream.writeAll("fn() callconv(.Naked) noreturn"), - .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"), + => return writer.writeAll(@tagName(t)), + + .enum_literal => return writer.writeAll("@Type(.EnumLiteral)"), + .@"null" => return writer.writeAll("@Type(.Null)"), + .@"undefined" => return writer.writeAll("@Type(.Undefined)"), + + .empty_struct, .empty_struct_literal => return writer.writeAll("struct {}"), + + .@"struct" => { + const struct_obj = self.castTag(.@"struct").?.data; + return struct_obj.owner_decl.renderFullyQualifiedName(writer); + }, + .enum_full, .enum_nonexhaustive => { + const enum_full = self.castTag(.enum_full).?.data; + return enum_full.owner_decl.renderFullyQualifiedName(writer); + }, + .enum_simple => { + const enum_simple = self.castTag(.enum_simple).?.data; + return enum_simple.owner_decl.renderFullyQualifiedName(writer); + }, + .@"opaque" => { + // TODO use declaration name + return writer.writeAll("opaque {}"); + }, + + .anyerror_void_error_union => return writer.writeAll("anyerror!void"), + .const_slice_u8 => return writer.writeAll("[]const u8"), + .fn_noreturn_no_args => return writer.writeAll("fn() noreturn"), + .fn_void_no_args => return writer.writeAll("fn() void"), + .fn_naked_noreturn_no_args => return writer.writeAll("fn() callconv(.Naked) noreturn"), + .fn_ccc_void_no_args => return writer.writeAll("fn() callconv(.C) void"), + .single_const_pointer_to_comptime_int => return writer.writeAll("*const comptime_int"), .function => { const payload = ty.castTag(.function).?.data; - try out_stream.writeAll("fn("); + try writer.writeAll("fn("); for (payload.param_types) |param_type, i| { - if (i != 0) try out_stream.writeAll(", "); - try param_type.format("", .{}, out_stream); + if (i != 0) try writer.writeAll(", "); + try param_type.format("", .{}, writer); } if (payload.is_var_args) { if (payload.param_types.len != 0) { - try out_stream.writeAll(", "); + try writer.writeAll(", "); } - try out_stream.writeAll("..."); + try writer.writeAll("..."); } - try out_stream.writeAll(") callconv(."); - try out_stream.writeAll(@tagName(payload.cc)); - try out_stream.writeAll(")"); + try writer.writeAll(") callconv(."); + try writer.writeAll(@tagName(payload.cc)); + try writer.writeAll(")"); ty = payload.return_type; continue; }, .array_u8 => { const len = ty.castTag(.array_u8).?.data; - return out_stream.print("[{d}]u8", .{len}); + return writer.print("[{d}]u8", .{len}); }, .array_u8_sentinel_0 => { const len = ty.castTag(.array_u8_sentinel_0).?.data; - return out_stream.print("[{d}:0]u8", .{len}); + return writer.print("[{d}:0]u8", .{len}); }, .array => { const payload = ty.castTag(.array).?.data; - try out_stream.print("[{d}]", .{payload.len}); + try writer.print("[{d}]", .{payload.len}); ty = payload.elem_type; continue; }, .array_sentinel => { const payload = ty.castTag(.array_sentinel).?.data; - try out_stream.print("[{d}:{}]", .{ payload.len, payload.sentinel }); + try writer.print("[{d}:{}]", .{ payload.len, payload.sentinel }); ty = payload.elem_type; continue; }, .single_const_pointer => { const pointee_type = ty.castTag(.single_const_pointer).?.data; - try out_stream.writeAll("*const "); + try writer.writeAll("*const "); ty = pointee_type; continue; }, .single_mut_pointer => { const pointee_type = ty.castTag(.single_mut_pointer).?.data; - try out_stream.writeAll("*"); + try writer.writeAll("*"); ty = pointee_type; continue; }, .many_const_pointer => { const pointee_type = ty.castTag(.many_const_pointer).?.data; - try out_stream.writeAll("[*]const "); + try writer.writeAll("[*]const "); ty = pointee_type; continue; }, .many_mut_pointer => { const pointee_type = ty.castTag(.many_mut_pointer).?.data; - try out_stream.writeAll("[*]"); + try writer.writeAll("[*]"); ty = pointee_type; continue; }, .c_const_pointer => { const pointee_type = ty.castTag(.c_const_pointer).?.data; - try out_stream.writeAll("[*c]const "); + try writer.writeAll("[*c]const "); ty = pointee_type; continue; }, .c_mut_pointer => { const pointee_type = ty.castTag(.c_mut_pointer).?.data; - try out_stream.writeAll("[*c]"); + try writer.writeAll("[*c]"); ty = pointee_type; continue; }, .const_slice => { const pointee_type = ty.castTag(.const_slice).?.data; - try out_stream.writeAll("[]const "); + try writer.writeAll("[]const "); ty = pointee_type; continue; }, .mut_slice => { const pointee_type = ty.castTag(.mut_slice).?.data; - try out_stream.writeAll("[]"); + try writer.writeAll("[]"); ty = pointee_type; continue; }, .int_signed => { const bits = ty.castTag(.int_signed).?.data; - return out_stream.print("i{d}", .{bits}); + return writer.print("i{d}", .{bits}); }, .int_unsigned => { const bits = ty.castTag(.int_unsigned).?.data; - return out_stream.print("u{d}", .{bits}); + return writer.print("u{d}", .{bits}); }, .optional => { const child_type = ty.castTag(.optional).?.data; - try out_stream.writeByte('?'); + try writer.writeByte('?'); ty = child_type; continue; }, .optional_single_const_pointer => { const pointee_type = ty.castTag(.optional_single_const_pointer).?.data; - try out_stream.writeAll("?*const "); + try writer.writeAll("?*const "); ty = pointee_type; continue; }, .optional_single_mut_pointer => { const pointee_type = ty.castTag(.optional_single_mut_pointer).?.data; - try out_stream.writeAll("?*"); + try writer.writeAll("?*"); ty = pointee_type; continue; }, @@ -804,48 +829,46 @@ pub const Type = extern union { const payload = ty.castTag(.pointer).?.data; if (payload.sentinel) |some| switch (payload.size) { .One, .C => unreachable, - .Many => try out_stream.print("[*:{}]", .{some}), - .Slice => try out_stream.print("[:{}]", .{some}), + .Many => try writer.print("[*:{}]", .{some}), + .Slice => try writer.print("[:{}]", .{some}), } else switch (payload.size) { - .One => try out_stream.writeAll("*"), - .Many => try out_stream.writeAll("[*]"), - .C => try out_stream.writeAll("[*c]"), - .Slice => try out_stream.writeAll("[]"), + .One => try writer.writeAll("*"), + .Many => try writer.writeAll("[*]"), + .C => try writer.writeAll("[*c]"), + .Slice => try writer.writeAll("[]"), } if (payload.@"align" != 0) { - try out_stream.print("align({d}", .{payload.@"align"}); + try writer.print("align({d}", .{payload.@"align"}); if (payload.bit_offset != 0) { - try out_stream.print(":{d}:{d}", .{ payload.bit_offset, payload.host_size }); + try writer.print(":{d}:{d}", .{ payload.bit_offset, payload.host_size }); } - try out_stream.writeAll(") "); + try writer.writeAll(") "); } - if (!payload.mutable) try out_stream.writeAll("const "); - if (payload.@"volatile") try out_stream.writeAll("volatile "); - if (payload.@"allowzero") try out_stream.writeAll("allowzero "); + if (!payload.mutable) try writer.writeAll("const "); + if (payload.@"volatile") try writer.writeAll("volatile "); + if (payload.@"allowzero") try writer.writeAll("allowzero "); ty = payload.pointee_type; continue; }, .error_union => { const payload = ty.castTag(.error_union).?.data; - try payload.error_set.format("", .{}, out_stream); - try out_stream.writeAll("!"); + try payload.error_set.format("", .{}, writer); + try writer.writeAll("!"); ty = payload.payload; continue; }, .error_set => { const error_set = ty.castTag(.error_set).?.data; - return out_stream.writeAll(std.mem.spanZ(error_set.owner_decl.name)); + return writer.writeAll(std.mem.spanZ(error_set.owner_decl.name)); }, .error_set_single => { const name = ty.castTag(.error_set_single).?.data; - return out_stream.print("error{{{s}}}", .{name}); + return writer.print("error{{{s}}}", .{name}); }, - .inferred_alloc_const => return out_stream.writeAll("(inferred_alloc_const)"), - .inferred_alloc_mut => return out_stream.writeAll("(inferred_alloc_mut)"), - // TODO use declaration name - .@"opaque" => return out_stream.writeAll("opaque {}"), + .inferred_alloc_const => return writer.writeAll("(inferred_alloc_const)"), + .inferred_alloc_mut => return writer.writeAll("(inferred_alloc_mut)"), } unreachable; } @@ -954,6 +977,19 @@ pub const Type = extern union { return false; } }, + .enum_full => { + const enum_full = self.castTag(.enum_full).?.data; + return enum_full.fields.count() >= 2; + }, + .enum_simple => { + const enum_simple = self.castTag(.enum_simple).?.data; + return enum_simple.fields.count() >= 2; + }, + .enum_nonexhaustive => { + var buffer: Payload.Bits = undefined; + const int_tag_ty = self.intTagType(&buffer); + return int_tag_ty.hasCodeGenBits(); + }, // TODO lazy types .array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0, @@ -1112,13 +1148,37 @@ pub const Type = extern union { } else if (!payload.payload.hasCodeGenBits()) { return payload.error_set.abiAlignment(target); } - @panic("TODO abiAlignment error union"); + return std.math.max( + payload.payload.abiAlignment(target), + payload.error_set.abiAlignment(target), + ); }, .@"struct" => { - @panic("TODO abiAlignment struct"); + // TODO take into account field alignment + // also make this possible to fail, and lazy + // I think we need to move all the functions from type.zig which can + // fail into Sema. + // Probably will need to introduce multi-stage struct resolution just + // like we have in stage1. + const struct_obj = self.castTag(.@"struct").?.data; + var biggest: u32 = 0; + for (struct_obj.fields.entries.items) |entry| { + const field_ty = entry.value.ty; + if (!field_ty.hasCodeGenBits()) continue; + const field_align = field_ty.abiAlignment(target); + if (field_align > biggest) { + return field_align; + } + } + assert(biggest != 0); + return biggest; + }, + .enum_full, .enum_nonexhaustive, .enum_simple => { + var buffer: Payload.Bits = undefined; + const int_tag_ty = self.intTagType(&buffer); + return int_tag_ty.abiAlignment(target); }, - .c_void, .void, .type, @@ -1166,6 +1226,11 @@ pub const Type = extern union { .@"struct" => { @panic("TODO abiSize struct"); }, + .enum_simple, .enum_full, .enum_nonexhaustive => { + var buffer: Payload.Bits = undefined; + const int_tag_ty = self.intTagType(&buffer); + return int_tag_ty.abiSize(target); + }, .u8, .i8, @@ -1276,76 +1341,25 @@ pub const Type = extern union { }; } + /// Asserts the type is an enum. + pub fn intTagType(self: Type, buffer: *Payload.Bits) Type { + switch (self.tag()) { + .enum_full, .enum_nonexhaustive => return self.castTag(.enum_full).?.data.tag_ty, + .enum_simple => { + const enum_simple = self.castTag(.enum_simple).?.data; + const bits = std.math.log2_int_ceil(usize, enum_simple.fields.count()); + buffer.* = .{ + .base = .{ .tag = .int_unsigned }, + .data = bits, + }; + return Type.initPayload(&buffer.base); + }, + else => unreachable, + } + } + pub fn isSinglePointer(self: Type) bool { return switch (self.tag()) { - .u8, - .i8, - .u16, - .i16, - .u32, - .i32, - .u64, - .i64, - .u128, - .i128, - .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, - .@"null", - .@"undefined", - .array, - .array_sentinel, - .array_u8, - .array_u8_sentinel_0, - .const_slice_u8, - .fn_noreturn_no_args, - .fn_void_no_args, - .fn_naked_noreturn_no_args, - .fn_ccc_void_no_args, - .function, - .int_unsigned, - .int_signed, - .optional, - .optional_single_mut_pointer, - .optional_single_const_pointer, - .enum_literal, - .many_const_pointer, - .many_mut_pointer, - .c_const_pointer, - .c_mut_pointer, - .const_slice, - .mut_slice, - .error_union, - .anyerror_void_error_union, - .error_set, - .error_set_single, - .@"struct", - .empty_struct, - .empty_struct_literal, - .@"opaque", - .var_args_param, - => false, - .single_const_pointer, .single_mut_pointer, .single_const_pointer_to_comptime_int, @@ -1354,73 +1368,14 @@ pub const Type = extern union { => true, .pointer => self.castTag(.pointer).?.data.size == .One, + + else => false, }; } /// Asserts the `Type` is a pointer. pub fn ptrSize(self: Type) std.builtin.TypeInfo.Pointer.Size { return switch (self.tag()) { - .u8, - .i8, - .u16, - .i16, - .u32, - .i32, - .u64, - .i64, - .u128, - .i128, - .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, - .@"null", - .@"undefined", - .array, - .array_sentinel, - .array_u8, - .array_u8_sentinel_0, - .fn_noreturn_no_args, - .fn_void_no_args, - .fn_naked_noreturn_no_args, - .fn_ccc_void_no_args, - .function, - .int_unsigned, - .int_signed, - .optional, - .optional_single_mut_pointer, - .optional_single_const_pointer, - .enum_literal, - .error_union, - .anyerror_void_error_union, - .error_set, - .error_set_single, - .empty_struct, - .empty_struct_literal, - .@"opaque", - .@"struct", - .var_args_param, - => unreachable, - .const_slice, .mut_slice, .const_slice_u8, @@ -1442,159 +1397,26 @@ pub const Type = extern union { => .One, .pointer => self.castTag(.pointer).?.data.size, + + else => unreachable, }; } pub fn isSlice(self: Type) bool { return switch (self.tag()) { - .u8, - .i8, - .u16, - .i16, - .u32, - .i32, - .u64, - .i64, - .u128, - .i128, - .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, - .@"null", - .@"undefined", - .array, - .array_sentinel, - .array_u8, - .array_u8_sentinel_0, - .single_const_pointer, - .single_mut_pointer, - .many_const_pointer, - .many_mut_pointer, - .c_const_pointer, - .c_mut_pointer, - .single_const_pointer_to_comptime_int, - .fn_noreturn_no_args, - .fn_void_no_args, - .fn_naked_noreturn_no_args, - .fn_ccc_void_no_args, - .function, - .int_unsigned, - .int_signed, - .optional, - .optional_single_mut_pointer, - .optional_single_const_pointer, - .enum_literal, - .error_union, - .anyerror_void_error_union, - .error_set, - .error_set_single, - .empty_struct, - .empty_struct_literal, - .inferred_alloc_const, - .inferred_alloc_mut, - .@"struct", - .@"opaque", - .var_args_param, - => false, - .const_slice, .mut_slice, .const_slice_u8, => true, .pointer => self.castTag(.pointer).?.data.size == .Slice, + + else => false, }; } pub fn isConstPtr(self: Type) bool { return switch (self.tag()) { - .u8, - .i8, - .u16, - .i16, - .u32, - .i32, - .u64, - .i64, - .u128, - .i128, - .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, - .@"null", - .@"undefined", - .array, - .array_sentinel, - .array_u8, - .array_u8_sentinel_0, - .fn_noreturn_no_args, - .fn_void_no_args, - .fn_naked_noreturn_no_args, - .fn_ccc_void_no_args, - .function, - .int_unsigned, - .int_signed, - .single_mut_pointer, - .many_mut_pointer, - .c_mut_pointer, - .optional, - .optional_single_mut_pointer, - .optional_single_const_pointer, - .enum_literal, - .mut_slice, - .error_union, - .anyerror_void_error_union, - .error_set, - .error_set_single, - .empty_struct, - .empty_struct_literal, - .inferred_alloc_const, - .inferred_alloc_mut, - .@"struct", - .@"opaque", - .var_args_param, - => false, - .single_const_pointer, .many_const_pointer, .c_const_pointer, @@ -1604,170 +1426,40 @@ pub const Type = extern union { => true, .pointer => !self.castTag(.pointer).?.data.mutable, + + else => false, }; } pub fn isVolatilePtr(self: Type) bool { return switch (self.tag()) { - .u8, - .i8, - .u16, - .i16, - .u32, - .i32, - .u64, - .i64, - .u128, - .i128, - .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, - .@"null", - .@"undefined", - .array, - .array_sentinel, - .array_u8, - .array_u8_sentinel_0, - .fn_noreturn_no_args, - .fn_void_no_args, - .fn_naked_noreturn_no_args, - .fn_ccc_void_no_args, - .function, - .int_unsigned, - .int_signed, - .single_mut_pointer, - .single_const_pointer, - .many_const_pointer, - .many_mut_pointer, - .c_const_pointer, - .c_mut_pointer, - .const_slice, - .mut_slice, - .single_const_pointer_to_comptime_int, - .const_slice_u8, - .optional, - .optional_single_mut_pointer, - .optional_single_const_pointer, - .enum_literal, - .error_union, - .anyerror_void_error_union, - .error_set, - .error_set_single, - .empty_struct, - .empty_struct_literal, - .inferred_alloc_const, - .inferred_alloc_mut, - .@"struct", - .@"opaque", - .var_args_param, - => false, - .pointer => { const payload = self.castTag(.pointer).?.data; return payload.@"volatile"; }, + else => false, }; } pub fn isAllowzeroPtr(self: Type) bool { return switch (self.tag()) { - .u8, - .i8, - .u16, - .i16, - .u32, - .i32, - .u64, - .i64, - .u128, - .i128, - .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, - .@"null", - .@"undefined", - .array, - .array_sentinel, - .array_u8, - .array_u8_sentinel_0, - .fn_noreturn_no_args, - .fn_void_no_args, - .fn_naked_noreturn_no_args, - .fn_ccc_void_no_args, - .function, - .int_unsigned, - .int_signed, - .single_mut_pointer, - .single_const_pointer, - .many_const_pointer, - .many_mut_pointer, - .c_const_pointer, - .c_mut_pointer, - .const_slice, - .mut_slice, - .single_const_pointer_to_comptime_int, - .const_slice_u8, - .optional, - .optional_single_mut_pointer, - .optional_single_const_pointer, - .enum_literal, - .error_union, - .anyerror_void_error_union, - .error_set, - .error_set_single, - .empty_struct, - .empty_struct_literal, - .inferred_alloc_const, - .inferred_alloc_mut, - .@"struct", - .@"opaque", - .var_args_param, - => false, - .pointer => { const payload = self.castTag(.pointer).?.data; return payload.@"allowzero"; }, + else => false, + }; + } + + pub fn isCPtr(self: Type) bool { + return switch (self.tag()) { + .c_const_pointer, + .c_mut_pointer, + => return true, + + .pointer => self.castTag(.pointer).?.data.size == .C, + + else => return false, }; } @@ -1833,64 +1525,6 @@ pub const Type = extern union { /// Asserts the type is a pointer or array type. pub fn elemType(self: Type) Type { return switch (self.tag()) { - .u8 => unreachable, - .i8 => unreachable, - .u16 => unreachable, - .i16 => unreachable, - .u32 => unreachable, - .i32 => unreachable, - .u64 => unreachable, - .i64 => unreachable, - .u128 => unreachable, - .i128 => unreachable, - .usize => unreachable, - .isize => unreachable, - .c_short => unreachable, - .c_ushort => unreachable, - .c_int => unreachable, - .c_uint => unreachable, - .c_long => unreachable, - .c_ulong => unreachable, - .c_longlong => unreachable, - .c_ulonglong => unreachable, - .c_longdouble => unreachable, - .f16 => unreachable, - .f32 => unreachable, - .f64 => unreachable, - .f128 => unreachable, - .c_void => unreachable, - .bool => unreachable, - .void => unreachable, - .type => unreachable, - .anyerror => unreachable, - .comptime_int => unreachable, - .comptime_float => unreachable, - .noreturn => unreachable, - .@"null" => unreachable, - .@"undefined" => unreachable, - .fn_noreturn_no_args => unreachable, - .fn_void_no_args => unreachable, - .fn_naked_noreturn_no_args => unreachable, - .fn_ccc_void_no_args => unreachable, - .function => unreachable, - .int_unsigned => unreachable, - .int_signed => unreachable, - .optional => unreachable, - .optional_single_const_pointer => unreachable, - .optional_single_mut_pointer => unreachable, - .enum_literal => unreachable, - .error_union => unreachable, - .anyerror_void_error_union => unreachable, - .error_set => unreachable, - .error_set_single => unreachable, - .@"struct" => unreachable, - .empty_struct => unreachable, - .empty_struct_literal => unreachable, - .inferred_alloc_const => unreachable, - .inferred_alloc_mut => unreachable, - .@"opaque" => unreachable, - .var_args_param => unreachable, - .array => self.castTag(.array).?.data.elem_type, .array_sentinel => self.castTag(.array_sentinel).?.data.elem_type, .single_const_pointer, @@ -1902,9 +1536,12 @@ pub const Type = extern union { .const_slice, .mut_slice, => 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.castTag(.pointer).?.data.pointee_type, + + else => unreachable, }; } @@ -1972,148 +1609,18 @@ pub const Type = extern union { /// Asserts the type is an array or vector. pub fn arrayLen(self: Type) u64 { return switch (self.tag()) { - .u8, - .i8, - .u16, - .i16, - .u32, - .i32, - .u64, - .i64, - .u128, - .i128, - .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, - .@"null", - .@"undefined", - .fn_noreturn_no_args, - .fn_void_no_args, - .fn_naked_noreturn_no_args, - .fn_ccc_void_no_args, - .function, - .pointer, - .single_const_pointer, - .single_mut_pointer, - .many_const_pointer, - .many_mut_pointer, - .c_const_pointer, - .c_mut_pointer, - .const_slice, - .mut_slice, - .single_const_pointer_to_comptime_int, - .const_slice_u8, - .int_unsigned, - .int_signed, - .optional, - .optional_single_mut_pointer, - .optional_single_const_pointer, - .enum_literal, - .error_union, - .anyerror_void_error_union, - .error_set, - .error_set_single, - .@"struct", - .empty_struct, - .empty_struct_literal, - .inferred_alloc_const, - .inferred_alloc_mut, - .@"opaque", - .var_args_param, - => unreachable, - .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, + + else => unreachable, }; } /// Asserts the type is an array, pointer or vector. pub fn sentinel(self: Type) ?Value { return switch (self.tag()) { - .u8, - .i8, - .u16, - .i16, - .u32, - .i32, - .u64, - .i64, - .u128, - .i128, - .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, - .@"null", - .@"undefined", - .fn_noreturn_no_args, - .fn_void_no_args, - .fn_naked_noreturn_no_args, - .fn_ccc_void_no_args, - .function, - .const_slice, - .mut_slice, - .const_slice_u8, - .int_unsigned, - .int_signed, - .optional, - .optional_single_mut_pointer, - .optional_single_const_pointer, - .enum_literal, - .error_union, - .anyerror_void_error_union, - .error_set, - .error_set_single, - .@"struct", - .empty_struct, - .empty_struct_literal, - .inferred_alloc_const, - .inferred_alloc_mut, - .@"opaque", - .var_args_param, - => unreachable, - .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -2128,6 +1635,8 @@ pub const Type = extern union { .pointer => return self.castTag(.pointer).?.data.sentinel, .array_sentinel => return self.castTag(.array_sentinel).?.data.sentinel, .array_u8_sentinel_0 => return Value.initTag(.zero), + + else => unreachable, }; } @@ -2139,68 +1648,6 @@ pub const Type = extern union { /// Returns true if and only if the type is a fixed-width, signed integer. pub fn isSignedInt(self: Type) bool { return switch (self.tag()) { - .f16, - .f32, - .f64, - .f128, - .c_longdouble, - .c_void, - .bool, - .void, - .type, - .anyerror, - .comptime_int, - .comptime_float, - .noreturn, - .@"null", - .@"undefined", - .fn_noreturn_no_args, - .fn_void_no_args, - .fn_naked_noreturn_no_args, - .fn_ccc_void_no_args, - .function, - .array, - .array_sentinel, - .array_u8, - .array_u8_sentinel_0, - .pointer, - .single_const_pointer, - .single_mut_pointer, - .many_const_pointer, - .many_mut_pointer, - .c_const_pointer, - .c_mut_pointer, - .const_slice, - .mut_slice, - .single_const_pointer_to_comptime_int, - .const_slice_u8, - .int_unsigned, - .u8, - .usize, - .c_ushort, - .c_uint, - .c_ulong, - .c_ulonglong, - .u16, - .u32, - .u64, - .optional, - .optional_single_mut_pointer, - .optional_single_const_pointer, - .enum_literal, - .error_union, - .anyerror_void_error_union, - .error_set, - .error_set_single, - .@"struct", - .empty_struct, - .empty_struct_literal, - .inferred_alloc_const, - .inferred_alloc_mut, - .@"opaque", - .var_args_param, - => false, - .int_signed, .i8, .isize, @@ -2211,79 +1658,16 @@ pub const Type = extern union { .i16, .i32, .i64, - .u128, .i128, => true, + + else => false, }; } /// Returns true if and only if the type is a fixed-width, unsigned integer. pub fn isUnsignedInt(self: Type) bool { return switch (self.tag()) { - .f16, - .f32, - .f64, - .f128, - .c_longdouble, - .c_void, - .bool, - .void, - .type, - .anyerror, - .comptime_int, - .comptime_float, - .noreturn, - .@"null", - .@"undefined", - .fn_noreturn_no_args, - .fn_void_no_args, - .fn_naked_noreturn_no_args, - .fn_ccc_void_no_args, - .function, - .array, - .array_sentinel, - .array_u8, - .array_u8_sentinel_0, - .pointer, - .single_const_pointer, - .single_mut_pointer, - .many_const_pointer, - .many_mut_pointer, - .c_const_pointer, - .c_mut_pointer, - .const_slice, - .mut_slice, - .single_const_pointer_to_comptime_int, - .const_slice_u8, - .int_signed, - .i8, - .isize, - .c_short, - .c_int, - .c_long, - .c_longlong, - .i16, - .i32, - .i64, - .u128, - .i128, - .optional, - .optional_single_mut_pointer, - .optional_single_const_pointer, - .enum_literal, - .error_union, - .anyerror_void_error_union, - .error_set, - .error_set_single, - .@"struct", - .empty_struct, - .empty_struct_literal, - .inferred_alloc_const, - .inferred_alloc_mut, - .@"opaque", - .var_args_param, - => false, - .int_unsigned, .u8, .usize, @@ -2294,65 +1678,16 @@ pub const Type = extern union { .u16, .u32, .u64, + .u128, => true, + + else => false, }; } /// Asserts the type is an integer. pub fn intInfo(self: Type, target: Target) struct { signedness: std.builtin.Signedness, bits: u16 } { return switch (self.tag()) { - .f16, - .f32, - .f64, - .f128, - .c_longdouble, - .c_void, - .bool, - .void, - .type, - .anyerror, - .comptime_int, - .comptime_float, - .noreturn, - .@"null", - .@"undefined", - .fn_noreturn_no_args, - .fn_void_no_args, - .fn_naked_noreturn_no_args, - .fn_ccc_void_no_args, - .function, - .array, - .array_sentinel, - .array_u8, - .array_u8_sentinel_0, - .pointer, - .single_const_pointer, - .single_mut_pointer, - .many_const_pointer, - .many_mut_pointer, - .c_const_pointer, - .c_mut_pointer, - .const_slice, - .mut_slice, - .single_const_pointer_to_comptime_int, - .const_slice_u8, - .optional, - .optional_single_mut_pointer, - .optional_single_const_pointer, - .enum_literal, - .error_union, - .anyerror_void_error_union, - .error_set, - .error_set_single, - .@"struct", - .empty_struct, - .empty_struct_literal, - .inferred_alloc_const, - .inferred_alloc_mut, - .@"opaque", - .var_args_param, - => unreachable, - .int_unsigned => .{ .signedness = .unsigned, .bits = self.castTag(.int_unsigned).?.data, @@ -2381,75 +1716,13 @@ pub const Type = extern union { .c_ulong => .{ .signedness = .unsigned, .bits = CType.ulong.sizeInBits(target) }, .c_longlong => .{ .signedness = .signed, .bits = CType.longlong.sizeInBits(target) }, .c_ulonglong => .{ .signedness = .unsigned, .bits = CType.ulonglong.sizeInBits(target) }, + + else => unreachable, }; } pub fn isNamedInt(self: Type) bool { return switch (self.tag()) { - .f16, - .f32, - .f64, - .f128, - .c_longdouble, - .c_void, - .bool, - .void, - .type, - .anyerror, - .comptime_int, - .comptime_float, - .noreturn, - .@"null", - .@"undefined", - .fn_noreturn_no_args, - .fn_void_no_args, - .fn_naked_noreturn_no_args, - .fn_ccc_void_no_args, - .function, - .array, - .array_sentinel, - .array_u8, - .array_u8_sentinel_0, - .pointer, - .single_const_pointer, - .single_mut_pointer, - .many_const_pointer, - .many_mut_pointer, - .c_const_pointer, - .c_mut_pointer, - .const_slice, - .mut_slice, - .single_const_pointer_to_comptime_int, - .const_slice_u8, - .int_unsigned, - .int_signed, - .u8, - .i8, - .u16, - .i16, - .u32, - .i32, - .u64, - .i64, - .u128, - .i128, - .optional, - .optional_single_mut_pointer, - .optional_single_const_pointer, - .enum_literal, - .error_union, - .anyerror_void_error_union, - .error_set, - .error_set_single, - .@"struct", - .empty_struct, - .empty_struct_literal, - .inferred_alloc_const, - .inferred_alloc_mut, - .@"opaque", - .var_args_param, - => false, - .usize, .isize, .c_short, @@ -2461,6 +1734,8 @@ pub const Type = extern union { .c_longlong, .c_ulonglong, => true, + + else => false, }; } @@ -2499,74 +1774,7 @@ pub const Type = extern union { .fn_ccc_void_no_args => 0, .function => self.castTag(.function).?.data.param_types.len, - .f16, - .f32, - .f64, - .f128, - .c_longdouble, - .c_void, - .bool, - .void, - .type, - .anyerror, - .comptime_int, - .comptime_float, - .noreturn, - .@"null", - .@"undefined", - .array, - .array_sentinel, - .array_u8, - .array_u8_sentinel_0, - .pointer, - .single_const_pointer, - .single_mut_pointer, - .many_const_pointer, - .many_mut_pointer, - .c_const_pointer, - .c_mut_pointer, - .const_slice, - .mut_slice, - .single_const_pointer_to_comptime_int, - .const_slice_u8, - .u8, - .i8, - .u16, - .i16, - .u32, - .i32, - .u64, - .i64, - .u128, - .i128, - .usize, - .isize, - .c_short, - .c_ushort, - .c_int, - .c_uint, - .c_long, - .c_ulong, - .c_longlong, - .c_ulonglong, - .int_unsigned, - .int_signed, - .optional, - .optional_single_mut_pointer, - .optional_single_const_pointer, - .enum_literal, - .error_union, - .anyerror_void_error_union, - .error_set, - .error_set_single, - .@"struct", - .empty_struct, - .empty_struct_literal, - .inferred_alloc_const, - .inferred_alloc_mut, - .@"opaque", - .var_args_param, - => unreachable, + else => unreachable, }; } @@ -2583,74 +1791,7 @@ pub const Type = extern union { std.mem.copy(Type, types, payload.param_types); }, - .f16, - .f32, - .f64, - .f128, - .c_longdouble, - .c_void, - .bool, - .void, - .type, - .anyerror, - .comptime_int, - .comptime_float, - .noreturn, - .@"null", - .@"undefined", - .array, - .array_sentinel, - .array_u8, - .array_u8_sentinel_0, - .pointer, - .single_const_pointer, - .single_mut_pointer, - .many_const_pointer, - .many_mut_pointer, - .c_const_pointer, - .c_mut_pointer, - .const_slice, - .mut_slice, - .single_const_pointer_to_comptime_int, - .const_slice_u8, - .u8, - .i8, - .u16, - .i16, - .u32, - .i32, - .u64, - .i64, - .u128, - .i128, - .usize, - .isize, - .c_short, - .c_ushort, - .c_int, - .c_uint, - .c_long, - .c_ulong, - .c_longlong, - .c_ulonglong, - .int_unsigned, - .int_signed, - .optional, - .optional_single_mut_pointer, - .optional_single_const_pointer, - .enum_literal, - .error_union, - .anyerror_void_error_union, - .error_set, - .error_set_single, - .@"struct", - .empty_struct, - .empty_struct_literal, - .inferred_alloc_const, - .inferred_alloc_mut, - .@"opaque", - .var_args_param, - => unreachable, + else => unreachable, } } @@ -2662,321 +1803,49 @@ pub const Type = extern union { return payload.param_types[index]; }, - .fn_noreturn_no_args, - .fn_void_no_args, - .fn_naked_noreturn_no_args, - .fn_ccc_void_no_args, - .f16, - .f32, - .f64, - .f128, - .c_longdouble, - .c_void, - .bool, - .void, - .type, - .anyerror, - .comptime_int, - .comptime_float, - .noreturn, - .@"null", - .@"undefined", - .array, - .array_sentinel, - .array_u8, - .array_u8_sentinel_0, - .pointer, - .single_const_pointer, - .single_mut_pointer, - .many_const_pointer, - .many_mut_pointer, - .c_const_pointer, - .c_mut_pointer, - .const_slice, - .mut_slice, - .single_const_pointer_to_comptime_int, - .const_slice_u8, - .u8, - .i8, - .u16, - .i16, - .u32, - .i32, - .u64, - .i64, - .u128, - .i128, - .usize, - .isize, - .c_short, - .c_ushort, - .c_int, - .c_uint, - .c_long, - .c_ulong, - .c_longlong, - .c_ulonglong, - .int_unsigned, - .int_signed, - .optional, - .optional_single_mut_pointer, - .optional_single_const_pointer, - .enum_literal, - .error_union, - .anyerror_void_error_union, - .error_set, - .error_set_single, - .@"struct", - .empty_struct, - .empty_struct_literal, - .inferred_alloc_const, - .inferred_alloc_mut, - .@"opaque", - .var_args_param, - => unreachable, - } - } - - /// Asserts the type is a function. - pub fn fnReturnType(self: Type) Type { - return switch (self.tag()) { - .fn_noreturn_no_args => Type.initTag(.noreturn), - .fn_naked_noreturn_no_args => Type.initTag(.noreturn), - + else => unreachable, + } + } + + /// Asserts the type is a function. + pub fn fnReturnType(self: Type) Type { + return switch (self.tag()) { + .fn_noreturn_no_args => Type.initTag(.noreturn), + .fn_naked_noreturn_no_args => Type.initTag(.noreturn), + .fn_void_no_args, .fn_ccc_void_no_args, => Type.initTag(.void), .function => self.castTag(.function).?.data.return_type, - - .f16, - .f32, - .f64, - .f128, - .c_longdouble, - .c_void, - .bool, - .void, - .type, - .anyerror, - .comptime_int, - .comptime_float, - .noreturn, - .@"null", - .@"undefined", - .array, - .array_sentinel, - .array_u8, - .array_u8_sentinel_0, - .pointer, - .single_const_pointer, - .single_mut_pointer, - .many_const_pointer, - .many_mut_pointer, - .c_const_pointer, - .c_mut_pointer, - .const_slice, - .mut_slice, - .single_const_pointer_to_comptime_int, - .const_slice_u8, - .u8, - .i8, - .u16, - .i16, - .u32, - .i32, - .u64, - .i64, - .u128, - .i128, - .usize, - .isize, - .c_short, - .c_ushort, - .c_int, - .c_uint, - .c_long, - .c_ulong, - .c_longlong, - .c_ulonglong, - .int_unsigned, - .int_signed, - .optional, - .optional_single_mut_pointer, - .optional_single_const_pointer, - .enum_literal, - .error_union, - .anyerror_void_error_union, - .error_set, - .error_set_single, - .@"struct", - .empty_struct, - .empty_struct_literal, - .inferred_alloc_const, - .inferred_alloc_mut, - .@"opaque", - .var_args_param, - => unreachable, - }; - } - - /// Asserts the type is a function. - pub fn fnCallingConvention(self: Type) std.builtin.CallingConvention { - return switch (self.tag()) { - .fn_noreturn_no_args => .Unspecified, - .fn_void_no_args => .Unspecified, - .fn_naked_noreturn_no_args => .Naked, - .fn_ccc_void_no_args => .C, - .function => self.castTag(.function).?.data.cc, - - .f16, - .f32, - .f64, - .f128, - .c_longdouble, - .c_void, - .bool, - .void, - .type, - .anyerror, - .comptime_int, - .comptime_float, - .noreturn, - .@"null", - .@"undefined", - .array, - .array_sentinel, - .array_u8, - .array_u8_sentinel_0, - .pointer, - .single_const_pointer, - .single_mut_pointer, - .many_const_pointer, - .many_mut_pointer, - .c_const_pointer, - .c_mut_pointer, - .const_slice, - .mut_slice, - .single_const_pointer_to_comptime_int, - .const_slice_u8, - .u8, - .i8, - .u16, - .i16, - .u32, - .i32, - .u64, - .i64, - .u128, - .i128, - .usize, - .isize, - .c_short, - .c_ushort, - .c_int, - .c_uint, - .c_long, - .c_ulong, - .c_longlong, - .c_ulonglong, - .int_unsigned, - .int_signed, - .optional, - .optional_single_mut_pointer, - .optional_single_const_pointer, - .enum_literal, - .error_union, - .anyerror_void_error_union, - .error_set, - .error_set_single, - .@"struct", - .empty_struct, - .empty_struct_literal, - .inferred_alloc_const, - .inferred_alloc_mut, - .@"opaque", - .var_args_param, - => unreachable, - }; - } - - /// Asserts the type is a function. - pub fn fnIsVarArgs(self: Type) bool { - return switch (self.tag()) { - .fn_noreturn_no_args => false, - .fn_void_no_args => false, - .fn_naked_noreturn_no_args => false, - .fn_ccc_void_no_args => false, - .function => self.castTag(.function).?.data.is_var_args, - - .f16, - .f32, - .f64, - .f128, - .c_longdouble, - .c_void, - .bool, - .void, - .type, - .anyerror, - .comptime_int, - .comptime_float, - .noreturn, - .@"null", - .@"undefined", - .array, - .array_sentinel, - .array_u8, - .array_u8_sentinel_0, - .pointer, - .single_const_pointer, - .single_mut_pointer, - .many_const_pointer, - .many_mut_pointer, - .c_const_pointer, - .c_mut_pointer, - .const_slice, - .mut_slice, - .single_const_pointer_to_comptime_int, - .const_slice_u8, - .u8, - .i8, - .u16, - .i16, - .u32, - .i32, - .u64, - .i64, - .u128, - .i128, - .usize, - .isize, - .c_short, - .c_ushort, - .c_int, - .c_uint, - .c_long, - .c_ulong, - .c_longlong, - .c_ulonglong, - .int_unsigned, - .int_signed, - .optional, - .optional_single_mut_pointer, - .optional_single_const_pointer, - .enum_literal, - .error_union, - .anyerror_void_error_union, - .error_set, - .error_set_single, - .@"struct", - .empty_struct, - .empty_struct_literal, - .inferred_alloc_const, - .inferred_alloc_mut, - .@"opaque", - .var_args_param, - => unreachable, + + else => unreachable, + }; + } + + /// Asserts the type is a function. + pub fn fnCallingConvention(self: Type) std.builtin.CallingConvention { + return switch (self.tag()) { + .fn_noreturn_no_args => .Unspecified, + .fn_void_no_args => .Unspecified, + .fn_naked_noreturn_no_args => .Naked, + .fn_ccc_void_no_args => .C, + .function => self.castTag(.function).?.data.cc, + + else => unreachable, + }; + } + + /// Asserts the type is a function. + pub fn fnIsVarArgs(self: Type) bool { + return switch (self.tag()) { + .fn_noreturn_no_args => false, + .fn_void_no_args => false, + .fn_naked_noreturn_no_args => false, + .fn_ccc_void_no_args => false, + .function => self.castTag(.function).?.data.is_var_args, + + else => unreachable, }; } @@ -3013,50 +1882,7 @@ pub const Type = extern union { .int_signed, => true, - .c_void, - .bool, - .void, - .type, - .anyerror, - .noreturn, - .@"null", - .@"undefined", - .fn_noreturn_no_args, - .fn_void_no_args, - .fn_naked_noreturn_no_args, - .fn_ccc_void_no_args, - .function, - .array, - .array_sentinel, - .array_u8, - .array_u8_sentinel_0, - .pointer, - .single_const_pointer, - .single_mut_pointer, - .many_const_pointer, - .many_mut_pointer, - .c_const_pointer, - .c_mut_pointer, - .const_slice, - .mut_slice, - .single_const_pointer_to_comptime_int, - .const_slice_u8, - .optional, - .optional_single_mut_pointer, - .optional_single_const_pointer, - .enum_literal, - .error_union, - .anyerror_void_error_union, - .error_set, - .error_set_single, - .@"struct", - .empty_struct, - .empty_struct_literal, - .inferred_alloc_const, - .inferred_alloc_mut, - .@"opaque", - .var_args_param, - => false, + else => false, }; } @@ -3127,6 +1953,23 @@ pub const Type = extern union { } return Value.initTag(.empty_struct_value); }, + .enum_full => { + const enum_full = self.castTag(.enum_full).?.data; + if (enum_full.fields.count() == 1) { + return enum_full.values.entries.items[0].key; + } else { + return null; + } + }, + .enum_simple => { + const enum_simple = self.castTag(.enum_simple).?.data; + if (enum_simple.fields.count() == 1) { + return Value.initTag(.zero); + } else { + return null; + } + }, + .enum_nonexhaustive => return self.castTag(.enum_full).?.data.tag_ty.onePossibleValue(), .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value), .void => return Value.initTag(.void_value), @@ -3166,87 +2009,6 @@ pub const Type = extern union { }; } - pub fn isCPtr(self: Type) bool { - return switch (self.tag()) { - .f16, - .f32, - .f64, - .f128, - .c_longdouble, - .comptime_int, - .comptime_float, - .u8, - .i8, - .u16, - .i16, - .u32, - .i32, - .u64, - .i64, - .u128, - .i128, - .usize, - .isize, - .c_short, - .c_ushort, - .c_int, - .c_uint, - .c_long, - .c_ulong, - .c_longlong, - .c_ulonglong, - .bool, - .type, - .anyerror, - .fn_noreturn_no_args, - .fn_void_no_args, - .fn_naked_noreturn_no_args, - .fn_ccc_void_no_args, - .function, - .single_const_pointer_to_comptime_int, - .const_slice_u8, - .c_void, - .void, - .noreturn, - .@"null", - .@"undefined", - .int_unsigned, - .int_signed, - .array, - .array_sentinel, - .array_u8, - .array_u8_sentinel_0, - .single_const_pointer, - .single_mut_pointer, - .many_const_pointer, - .many_mut_pointer, - .const_slice, - .mut_slice, - .optional, - .optional_single_mut_pointer, - .optional_single_const_pointer, - .enum_literal, - .error_union, - .anyerror_void_error_union, - .error_set, - .error_set_single, - .@"struct", - .empty_struct, - .empty_struct_literal, - .inferred_alloc_const, - .inferred_alloc_mut, - .@"opaque", - .var_args_param, - => return false, - - .c_const_pointer, - .c_mut_pointer, - => return true, - - .pointer => self.castTag(.pointer).?.data.size == .C, - }; - } - pub fn isIndexable(self: Type) bool { const zig_tag = self.zigTypeTag(); // TODO tuples are indexable @@ -3257,80 +2019,12 @@ pub const Type = extern union { /// Asserts that the type is a container. (note: ErrorSet is not a container). pub fn getContainerScope(self: Type) *Module.Scope.Container { return switch (self.tag()) { - .f16, - .f32, - .f64, - .f128, - .c_longdouble, - .comptime_int, - .comptime_float, - .u8, - .i8, - .u16, - .i16, - .u32, - .i32, - .u64, - .i64, - .u128, - .i128, - .usize, - .isize, - .c_short, - .c_ushort, - .c_int, - .c_uint, - .c_long, - .c_ulong, - .c_longlong, - .c_ulonglong, - .bool, - .type, - .anyerror, - .fn_noreturn_no_args, - .fn_void_no_args, - .fn_naked_noreturn_no_args, - .fn_ccc_void_no_args, - .function, - .single_const_pointer_to_comptime_int, - .const_slice_u8, - .c_void, - .void, - .noreturn, - .@"null", - .@"undefined", - .int_unsigned, - .int_signed, - .array, - .array_sentinel, - .array_u8, - .array_u8_sentinel_0, - .single_const_pointer, - .single_mut_pointer, - .many_const_pointer, - .many_mut_pointer, - .const_slice, - .mut_slice, - .optional, - .optional_single_mut_pointer, - .optional_single_const_pointer, - .enum_literal, - .error_union, - .anyerror_void_error_union, - .error_set, - .error_set_single, - .c_const_pointer, - .c_mut_pointer, - .pointer, - .inferred_alloc_const, - .inferred_alloc_mut, - .var_args_param, - .empty_struct_literal, - => unreachable, - .@"struct" => &self.castTag(.@"struct").?.data.container, + .enum_full => &self.castTag(.enum_full).?.data.container, .empty_struct => self.castTag(.empty_struct).?.data, .@"opaque" => &self.castTag(.@"opaque").?.data, + + else => unreachable, }; } @@ -3390,7 +2084,43 @@ pub const Type = extern union { } pub fn isExhaustiveEnum(ty: Type) bool { - return false; // TODO + return switch (ty.tag()) { + .enum_full, .enum_simple => true, + else => false, + }; + } + + /// Asserts the type is an enum. + pub fn enumHasInt(ty: Type, int: Value, target: Target) bool { + const S = struct { + fn intInRange(int_val: Value, end: usize) 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)) return false; + return true; + } + }; + switch (ty.tag()) { + .enum_nonexhaustive => return int.intFitsInType(ty, target), + .enum_full => { + const enum_full = ty.castTag(.enum_full).?.data; + if (enum_full.values.count() == 0) { + return S.intInRange(int, enum_full.fields.count()); + } else { + return enum_full.values.contains(int); + } + }, + .enum_simple => { + const enum_simple = ty.castTag(.enum_simple).?.data; + return S.intInRange(int, enum_simple.fields.count()); + }, + + else => unreachable, + } } /// This enum does not directly correspond to `std.builtin.TypeId` because @@ -3482,6 +2212,9 @@ pub const Type = extern union { empty_struct, @"opaque", @"struct", + enum_simple, + enum_full, + enum_nonexhaustive, pub const last_no_payload_tag = Tag.inferred_alloc_const; pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; @@ -3568,6 +2301,8 @@ pub const Type = extern union { .error_set_single => Payload.Name, .@"opaque" => Payload.Opaque, .@"struct" => Payload.Struct, + .enum_full, .enum_nonexhaustive => Payload.EnumFull, + .enum_simple => Payload.EnumSimple, .empty_struct => Payload.ContainerScope, }; } @@ -3705,6 +2440,16 @@ pub const Type = extern union { base: Payload = .{ .tag = .@"struct" }, data: *Module.Struct, }; + + pub const EnumFull = struct { + base: Payload, + data: *Module.EnumFull, + }; + + pub const EnumSimple = struct { + base: Payload = .{ .tag = .enum_simple }, + data: *Module.EnumSimple, + }; }; }; -- cgit v1.2.3