diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2023-05-20 12:09:07 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2023-06-10 20:47:53 -0700 |
| commit | 9ff514b6a35b7201f45f8bff31c61b4f8cfa7a7a (patch) | |
| tree | dda74acc00690d1b3d31fd6e43d7ec0aa4acc882 /src/type.zig | |
| parent | 7bf91fc79ac9e4eae575baf3a2ca9549bc3bf6c2 (diff) | |
| download | zig-9ff514b6a35b7201f45f8bff31c61b4f8cfa7a7a.tar.gz zig-9ff514b6a35b7201f45f8bff31c61b4f8cfa7a7a.zip | |
compiler: move error union types and error set types to InternPool
One change worth noting in this commit is that `module.global_error_set`
is no longer kept strictly up-to-date. The previous code reserved
integer error values when dealing with error set types, but this is no
longer needed because the integer values are not needed for semantic
analysis unless `@errorToInt` or `@intToError` are used and therefore
may be assigned lazily.
Diffstat (limited to 'src/type.zig')
| -rw-r--r-- | src/type.zig | 1251 |
1 files changed, 389 insertions, 862 deletions
diff --git a/src/type.zig b/src/type.zig index ebe3d52b05..4e90cbd34d 100644 --- a/src/type.zig +++ b/src/type.zig @@ -36,17 +36,9 @@ pub const Type = struct { pub fn zigTypeTagOrPoison(ty: Type, mod: *const Module) error{GenericPoison}!std.builtin.TypeId { switch (ty.ip_index) { .none => switch (ty.tag()) { - .error_set, - .error_set_single, - .error_set_inferred, - .error_set_merged, - => return .ErrorSet, - .inferred_alloc_const, .inferred_alloc_mut, => return .Pointer, - - .error_union => return .ErrorUnion, }, else => return switch (mod.intern_pool.indexToKey(ty.ip_index)) { .int_type => .Int, @@ -55,6 +47,7 @@ pub const Type = struct { .vector_type => .Vector, .opt_type => .Optional, .error_union_type => .ErrorUnion, + .error_set_type, .inferred_error_set_type => .ErrorSet, .struct_type, .anon_struct_type => .Struct, .union_type => .Union, .opaque_type => .Opaque, @@ -130,9 +123,9 @@ pub const Type = struct { } } - pub fn baseZigTypeTag(self: Type, mod: *const Module) std.builtin.TypeId { + pub fn baseZigTypeTag(self: Type, mod: *Module) std.builtin.TypeId { return switch (self.zigTypeTag(mod)) { - .ErrorUnion => self.errorUnionPayload().baseZigTypeTag(mod), + .ErrorUnion => self.errorUnionPayload(mod).baseZigTypeTag(mod), .Optional => { return self.optionalChild(mod).baseZigTypeTag(mod); }, @@ -294,35 +287,6 @@ pub const Type = struct { if (a.legacy.tag_if_small_enough == b.legacy.tag_if_small_enough) return true; switch (a.tag()) { - .error_set_inferred => { - // Inferred error sets are only equal if both are inferred - // and they share the same pointer. - const a_ies = a.castTag(.error_set_inferred).?.data; - const b_ies = (b.castTag(.error_set_inferred) orelse return false).data; - return a_ies == b_ies; - }, - - .error_set, - .error_set_single, - .error_set_merged, - => { - switch (b.tag()) { - .error_set, .error_set_single, .error_set_merged => {}, - else => return false, - } - - // Two resolved sets match if their error set names match. - // Since they are pre-sorted we compare them element-wise. - const a_set = a.errorSetNames(); - const b_set = b.errorSetNames(); - if (a_set.len != b_set.len) return false; - for (a_set, 0..) |a_item, i| { - const b_item = b_set[i]; - if (!std.mem.eql(u8, a_item, b_item)) return false; - } - return true; - }, - .inferred_alloc_const, .inferred_alloc_mut, => { @@ -367,20 +331,6 @@ pub const Type = struct { return true; }, - - .error_union => { - if (b.zigTypeTag(mod) != .ErrorUnion) return false; - - const a_set = a.errorUnionSet(); - const b_set = b.errorUnionSet(); - if (!a_set.eql(b_set, mod)) return false; - - const a_payload = a.errorUnionPayload(); - const b_payload = b.errorUnionPayload(); - if (!a_payload.eql(b_payload, mod)) return false; - - return true; - }, } } @@ -399,28 +349,6 @@ pub const Type = struct { return; } switch (ty.tag()) { - .error_set, - .error_set_single, - .error_set_merged, - => { - // all are treated like an "error set" for hashing - std.hash.autoHash(hasher, std.builtin.TypeId.ErrorSet); - std.hash.autoHash(hasher, Tag.error_set); - - const names = ty.errorSetNames(); - std.hash.autoHash(hasher, names.len); - assert(std.sort.isSorted([]const u8, names, u8, std.mem.lessThan)); - for (names) |name| hasher.update(name); - }, - - .error_set_inferred => { - // inferred error sets are compared using their data pointer - const ies: *Module.Fn.InferredErrorSet = ty.castTag(.error_set_inferred).?.data; - std.hash.autoHash(hasher, std.builtin.TypeId.ErrorSet); - std.hash.autoHash(hasher, Tag.error_set_inferred); - std.hash.autoHash(hasher, ies); - }, - .inferred_alloc_const, .inferred_alloc_mut, => { @@ -439,16 +367,6 @@ pub const Type = struct { std.hash.autoHash(hasher, info.@"volatile"); std.hash.autoHash(hasher, info.size); }, - - .error_union => { - std.hash.autoHash(hasher, std.builtin.TypeId.ErrorUnion); - - const set_ty = ty.errorUnionSet(); - hashWithHasher(set_ty, hasher, mod); - - const payload_ty = ty.errorUnionPayload(); - hashWithHasher(payload_ty, hasher, mod); - }, } } @@ -484,52 +402,6 @@ pub const Type = struct { } }; - pub fn copy(self: Type, allocator: Allocator) error{OutOfMemory}!Type { - if (self.ip_index != .none) { - return Type{ .ip_index = self.ip_index, .legacy = undefined }; - } - if (@enumToInt(self.legacy.tag_if_small_enough) < Tag.no_payload_count) { - return Type{ - .ip_index = .none, - .legacy = .{ .tag_if_small_enough = self.legacy.tag_if_small_enough }, - }; - } else switch (self.legacy.ptr_otherwise.tag) { - .inferred_alloc_const, - .inferred_alloc_mut, - => unreachable, - - .error_union => { - const payload = self.castTag(.error_union).?.data; - return Tag.error_union.create(allocator, .{ - .error_set = try payload.error_set.copy(allocator), - .payload = try payload.payload.copy(allocator), - }); - }, - .error_set_merged => { - const names = self.castTag(.error_set_merged).?.data.keys(); - var duped_names = Module.ErrorSet.NameMap{}; - try duped_names.ensureTotalCapacity(allocator, names.len); - for (names) |name| { - duped_names.putAssumeCapacityNoClobber(name, {}); - } - return Tag.error_set_merged.create(allocator, duped_names); - }, - .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet), - .error_set_inferred => return self.copyPayloadShallow(allocator, Payload.ErrorSetInferred), - .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name), - } - } - - fn copyPayloadShallow(self: Type, allocator: Allocator, comptime T: type) error{OutOfMemory}!Type { - const payload = self.cast(T).?; - const new_payload = try allocator.create(T); - new_payload.* = payload.*; - return Type{ - .ip_index = .none, - .legacy = .{ .ptr_otherwise = &new_payload.base }, - }; - } - pub fn format(ty: Type, comptime unused_fmt_string: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { _ = ty; _ = unused_fmt_string; @@ -575,62 +447,7 @@ pub const Type = struct { ) @TypeOf(writer).Error!void { _ = options; comptime assert(unused_format_string.len == 0); - if (start_type.ip_index != .none) { - return writer.print("(intern index: {d})", .{@enumToInt(start_type.ip_index)}); - } - if (true) { - // This is disabled to work around a stage2 bug where this function recursively - // causes more generic function instantiations resulting in an infinite loop - // in the compiler. - try writer.writeAll("[TODO fix internal compiler bug regarding dump]"); - return; - } - var ty = start_type; - while (true) { - const t = ty.tag(); - switch (t) { - .error_union => { - const payload = ty.castTag(.error_union).?.data; - try payload.error_set.dump("", .{}, writer); - try writer.writeAll("!"); - ty = payload.payload; - continue; - }, - .error_set => { - const names = ty.castTag(.error_set).?.data.names.keys(); - try writer.writeAll("error{"); - for (names, 0..) |name, i| { - if (i != 0) try writer.writeByte(','); - try writer.writeAll(name); - } - try writer.writeAll("}"); - return; - }, - .error_set_inferred => { - const func = ty.castTag(.error_set_inferred).?.data.func; - return writer.print("({s} func={d})", .{ - @tagName(t), func.owner_decl, - }); - }, - .error_set_merged => { - const names = ty.castTag(.error_set_merged).?.data.keys(); - try writer.writeAll("error{"); - for (names, 0..) |name, i| { - if (i != 0) try writer.writeByte(','); - try writer.writeAll(name); - } - try writer.writeAll("}"); - return; - }, - .error_set_single => { - const name = ty.castTag(.error_set_single).?.data; - return writer.print("error{{{s}}}", .{name}); - }, - .inferred_alloc_const => return writer.writeAll("(inferred_alloc_const)"), - .inferred_alloc_mut => return writer.writeAll("(inferred_alloc_mut)"), - } - unreachable; - } + return writer.print("{any}", .{start_type.ip_index}); } pub const nameAllocArena = nameAlloc; @@ -648,45 +465,6 @@ pub const Type = struct { .none => switch (ty.tag()) { .inferred_alloc_const => unreachable, .inferred_alloc_mut => unreachable, - - .error_set_inferred => { - const func = ty.castTag(.error_set_inferred).?.data.func; - - try writer.writeAll("@typeInfo(@typeInfo(@TypeOf("); - const owner_decl = mod.declPtr(func.owner_decl); - try owner_decl.renderFullyQualifiedName(mod, writer); - try writer.writeAll(")).Fn.return_type.?).ErrorUnion.error_set"); - }, - - .error_union => { - const error_union = ty.castTag(.error_union).?.data; - try print(error_union.error_set, writer, mod); - try writer.writeAll("!"); - try print(error_union.payload, writer, mod); - }, - - .error_set => { - const names = ty.castTag(.error_set).?.data.names.keys(); - try writer.writeAll("error{"); - for (names, 0..) |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, 0..) |name, i| { - if (i != 0) try writer.writeByte(','); - try writer.writeAll(name); - } - try writer.writeAll("}"); - }, }, else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { .int_type => |int_type| { @@ -766,6 +544,24 @@ pub const Type = struct { try print(error_union_type.payload_type.toType(), writer, mod); return; }, + .inferred_error_set_type => |index| { + const ies = mod.inferredErrorSetPtr(index); + const func = ies.func; + + try writer.writeAll("@typeInfo(@typeInfo(@TypeOf("); + const owner_decl = mod.declPtr(func.owner_decl); + try owner_decl.renderFullyQualifiedName(mod, writer); + try writer.writeAll(")).Fn.return_type.?).ErrorUnion.error_set"); + }, + .error_set_type => |error_set_type| { + const names = error_set_type.names; + try writer.writeAll("error{"); + for (names, 0..) |name, i| { + if (i != 0) try writer.writeByte(','); + try writer.writeAll(mod.intern_pool.stringToSlice(name)); + } + try writer.writeAll("}"); + }, .simple_type => |s| return writer.writeAll(@tagName(s)), .struct_type => |struct_type| { if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| { @@ -881,13 +677,8 @@ pub const Type = struct { return ty.ip_index; } - pub fn toValue(self: Type, allocator: Allocator) Allocator.Error!Value { - if (self.ip_index != .none) return self.ip_index.toValue(); - switch (self.tag()) { - .inferred_alloc_const => unreachable, - .inferred_alloc_mut => unreachable, - else => return Value.Tag.ty.create(allocator, self), - } + pub fn toValue(self: Type) Value { + return self.toIntern().toValue(); } const RuntimeBitsError = Module.CompileError || error{NeedLazy}; @@ -914,14 +705,6 @@ pub const Type = struct { .empty_struct_type => return false, .none => switch (ty.tag()) { - .error_set_inferred, - - .error_set_single, - .error_union, - .error_set, - .error_set_merged, - => return true, - .inferred_alloc_const => unreachable, .inferred_alloc_mut => unreachable, }, @@ -951,7 +734,7 @@ pub const Type = struct { }, .opt_type => |child| { const child_ty = child.toType(); - if (child_ty.isNoReturn()) { + if (child_ty.isNoReturn(mod)) { // Then the optional is comptime-known to be null. return false; } @@ -963,7 +746,10 @@ pub const Type = struct { return !comptimeOnly(child_ty, mod); } }, - .error_union_type => @panic("TODO"), + .error_union_type, + .error_set_type, + .inferred_error_set_type, + => true, // These are function *bodies*, not pointers. // They return false here because they are comptime-only types. @@ -1103,112 +889,99 @@ pub const Type = struct { /// readFrom/writeToMemory are supported only for types with a well- /// defined memory layout pub fn hasWellDefinedLayout(ty: Type, mod: *Module) bool { - return switch (ty.ip_index) { - .empty_struct_type => false, + return switch (mod.intern_pool.indexToKey(ty.ip_index)) { + .int_type, + .ptr_type, + .vector_type, + => true, - .none => switch (ty.tag()) { - .error_set, - .error_set_single, - .error_set_inferred, - .error_set_merged, - .error_union, - => false, + .error_union_type, + .error_set_type, + .inferred_error_set_type, + .anon_struct_type, + .opaque_type, + .anyframe_type, + // These are function bodies, not function pointers. + .func_type, + => false, - .inferred_alloc_mut => unreachable, - .inferred_alloc_const => unreachable, - }, - else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { - .int_type, - .ptr_type, - .vector_type, + .array_type => |array_type| array_type.child.toType().hasWellDefinedLayout(mod), + .opt_type => ty.isPtrLikeOptional(mod), + + .simple_type => |t| switch (t) { + .f16, + .f32, + .f64, + .f80, + .f128, + .usize, + .isize, + .c_char, + .c_short, + .c_ushort, + .c_int, + .c_uint, + .c_long, + .c_ulong, + .c_longlong, + .c_ulonglong, + .c_longdouble, + .bool, + .void, => true, - .error_union_type, - .anon_struct_type, - .opaque_type, - .anyframe_type, - // These are function bodies, not function pointers. - .func_type, + .anyerror, + .anyopaque, + .atomic_order, + .atomic_rmw_op, + .calling_convention, + .address_space, + .float_mode, + .reduce_op, + .call_modifier, + .prefetch_options, + .export_options, + .extern_options, + .type, + .comptime_int, + .comptime_float, + .noreturn, + .null, + .undefined, + .enum_literal, + .type_info, + .generic_poison, => false, - .array_type => |array_type| array_type.child.toType().hasWellDefinedLayout(mod), - .opt_type => ty.isPtrLikeOptional(mod), - - .simple_type => |t| switch (t) { - .f16, - .f32, - .f64, - .f80, - .f128, - .usize, - .isize, - .c_char, - .c_short, - .c_ushort, - .c_int, - .c_uint, - .c_long, - .c_ulong, - .c_longlong, - .c_ulonglong, - .c_longdouble, - .bool, - .void, - => true, - - .anyerror, - .anyopaque, - .atomic_order, - .atomic_rmw_op, - .calling_convention, - .address_space, - .float_mode, - .reduce_op, - .call_modifier, - .prefetch_options, - .export_options, - .extern_options, - .type, - .comptime_int, - .comptime_float, - .noreturn, - .null, - .undefined, - .enum_literal, - .type_info, - .generic_poison, - => false, - - .var_args_param => unreachable, - }, - .struct_type => |struct_type| { - const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse { - // Struct with no fields has a well-defined layout of no bits. - return true; - }; - return struct_obj.layout != .Auto; - }, - .union_type => |union_type| switch (union_type.runtime_tag) { - .none, .safety => mod.unionPtr(union_type.index).layout != .Auto, - .tagged => false, - }, - .enum_type => |enum_type| switch (enum_type.tag_mode) { - .auto => false, - .explicit, .nonexhaustive => true, - }, - - // values, not types - .undef => unreachable, - .un => unreachable, - .simple_value => unreachable, - .extern_func => unreachable, - .int => unreachable, - .float => unreachable, - .ptr => unreachable, - .opt => unreachable, - .enum_tag => unreachable, - .aggregate => unreachable, + .var_args_param => unreachable, }, + .struct_type => |struct_type| { + const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse { + // Struct with no fields has a well-defined layout of no bits. + return true; + }; + return struct_obj.layout != .Auto; + }, + .union_type => |union_type| switch (union_type.runtime_tag) { + .none, .safety => mod.unionPtr(union_type.index).layout != .Auto, + .tagged => false, + }, + .enum_type => |enum_type| switch (enum_type.tag_mode) { + .auto => false, + .explicit, .nonexhaustive => true, + }, + + // values, not types + .undef => unreachable, + .un => unreachable, + .simple_value => unreachable, + .extern_func => unreachable, + .int => unreachable, + .float => unreachable, + .ptr => unreachable, + .opt => unreachable, + .enum_tag => unreachable, + .aggregate => unreachable, }; } @@ -1247,35 +1020,8 @@ pub const Type = struct { }; } - pub fn isNoReturn(ty: Type) bool { - switch (@enumToInt(ty.ip_index)) { - @enumToInt(InternPool.Index.first_type)...@enumToInt(InternPool.Index.noreturn_type) - 1 => return false, - - @enumToInt(InternPool.Index.noreturn_type) => return true, - - @enumToInt(InternPool.Index.noreturn_type) + 1...@enumToInt(InternPool.Index.last_type) => return false, - - @enumToInt(InternPool.Index.first_value)...@enumToInt(InternPool.Index.last_value) => unreachable, - @enumToInt(InternPool.Index.generic_poison) => unreachable, - - // TODO add empty error sets here - // TODO add enums with no fields here - else => return false, - - @enumToInt(InternPool.Index.none) => switch (ty.tag()) { - .error_set => { - const err_set_obj = ty.castTag(.error_set).?.data; - const names = err_set_obj.names.keys(); - return names.len == 0; - }, - .error_set_merged => { - const name_map = ty.castTag(.error_set_merged).?.data; - const names = name_map.keys(); - return names.len == 0; - }, - else => return false, - }, - } + pub fn isNoReturn(ty: Type, mod: *Module) bool { + return mod.intern_pool.isNoReturn(ty.ip_index); } /// Returns 0 if the pointer is naturally aligned and the element type is 0-bit. @@ -1353,21 +1099,6 @@ pub const Type = struct { switch (ty.ip_index) { .empty_struct_type => return AbiAlignmentAdvanced{ .scalar = 0 }, - .none => switch (ty.tag()) { - - // TODO revisit this when we have the concept of the error tag type - .error_set_inferred, - .error_set_single, - .error_set, - .error_set_merged, - => return AbiAlignmentAdvanced{ .scalar = 2 }, - - .error_union => return abiAlignmentAdvancedErrorUnion(ty, mod, strat), - - .inferred_alloc_const, - .inferred_alloc_mut, - => unreachable, - }, else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { .int_type => |int_type| { if (int_type.bits == 0) return AbiAlignmentAdvanced{ .scalar = 0 }; @@ -1388,7 +1119,11 @@ pub const Type = struct { }, .opt_type => return abiAlignmentAdvancedOptional(ty, mod, strat), - .error_union_type => return abiAlignmentAdvancedErrorUnion(ty, mod, strat), + .error_union_type => |info| return abiAlignmentAdvancedErrorUnion(ty, mod, strat, info.payload_type.toType()), + + // TODO revisit this when we have the concept of the error tag type + .error_set_type, .inferred_error_set_type => return AbiAlignmentAdvanced{ .scalar = 2 }, + // represents machine code; not a pointer .func_type => |func_type| return AbiAlignmentAdvanced{ .scalar = if (func_type.alignment.toByteUnitsOptional()) |a| @@ -1572,14 +1307,14 @@ pub const Type = struct { ty: Type, mod: *Module, strat: AbiAlignmentAdvancedStrat, + payload_ty: Type, ) Module.CompileError!AbiAlignmentAdvanced { // This code needs to be kept in sync with the equivalent switch prong // in abiSizeAdvanced. - const data = ty.castTag(.error_union).?.data; const code_align = abiAlignment(Type.anyerror, mod); switch (strat) { .eager, .sema => { - if (!(data.payload.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { + if (!(payload_ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) }, else => |e| return e, })) { @@ -1587,11 +1322,11 @@ pub const Type = struct { } return AbiAlignmentAdvanced{ .scalar = @max( code_align, - (try data.payload.abiAlignmentAdvanced(mod, strat)).scalar, + (try payload_ty.abiAlignmentAdvanced(mod, strat)).scalar, ) }; }, .lazy => |arena| { - switch (try data.payload.abiAlignmentAdvanced(mod, strat)) { + switch (try payload_ty.abiAlignmentAdvanced(mod, strat)) { .scalar => |payload_align| { return AbiAlignmentAdvanced{ .scalar = @max(code_align, payload_align), @@ -1728,55 +1463,6 @@ pub const Type = struct { switch (ty.ip_index) { .empty_struct_type => return AbiSizeAdvanced{ .scalar = 0 }, - .none => switch (ty.tag()) { - .inferred_alloc_const => unreachable, - .inferred_alloc_mut => unreachable, - - // TODO revisit this when we have the concept of the error tag type - .error_set_inferred, - .error_set, - .error_set_merged, - .error_set_single, - => return AbiSizeAdvanced{ .scalar = 2 }, - - .error_union => { - // This code needs to be kept in sync with the equivalent switch prong - // in abiAlignmentAdvanced. - const data = ty.castTag(.error_union).?.data; - const code_size = abiSize(Type.anyerror, mod); - if (!(data.payload.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { - error.NeedLazy => return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(strat.lazy, ty) }, - else => |e| return e, - })) { - // Same as anyerror. - return AbiSizeAdvanced{ .scalar = code_size }; - } - const code_align = abiAlignment(Type.anyerror, mod); - const payload_align = abiAlignment(data.payload, mod); - const payload_size = switch (try data.payload.abiSizeAdvanced(mod, strat)) { - .scalar => |elem_size| elem_size, - .val => switch (strat) { - .sema => unreachable, - .eager => unreachable, - .lazy => |arena| return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }, - }, - }; - - var size: u64 = 0; - if (code_align > payload_align) { - size += code_size; - size = std.mem.alignForwardGeneric(u64, size, payload_align); - size += payload_size; - size = std.mem.alignForwardGeneric(u64, size, code_align); - } else { - size += payload_size; - size = std.mem.alignForwardGeneric(u64, size, code_align); - size += code_size; - size = std.mem.alignForwardGeneric(u64, size, payload_align); - } - return AbiSizeAdvanced{ .scalar = size }; - }, - }, else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { .int_type => |int_type| { if (int_type.bits == 0) return AbiSizeAdvanced{ .scalar = 0 }; @@ -1821,7 +1507,47 @@ pub const Type = struct { }, .opt_type => return ty.abiSizeAdvancedOptional(mod, strat), - .error_union_type => @panic("TODO"), + + // TODO revisit this when we have the concept of the error tag type + .error_set_type, .inferred_error_set_type => return AbiSizeAdvanced{ .scalar = 2 }, + + .error_union_type => |error_union_type| { + const payload_ty = error_union_type.payload_type.toType(); + // This code needs to be kept in sync with the equivalent switch prong + // in abiAlignmentAdvanced. + const code_size = abiSize(Type.anyerror, mod); + if (!(payload_ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { + error.NeedLazy => return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(strat.lazy, ty) }, + else => |e| return e, + })) { + // Same as anyerror. + return AbiSizeAdvanced{ .scalar = code_size }; + } + const code_align = abiAlignment(Type.anyerror, mod); + const payload_align = abiAlignment(payload_ty, mod); + const payload_size = switch (try payload_ty.abiSizeAdvanced(mod, strat)) { + .scalar => |elem_size| elem_size, + .val => switch (strat) { + .sema => unreachable, + .eager => unreachable, + .lazy => |arena| return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }, + }, + }; + + var size: u64 = 0; + if (code_align > payload_align) { + size += code_size; + size = std.mem.alignForwardGeneric(u64, size, payload_align); + size += payload_size; + size = std.mem.alignForwardGeneric(u64, size, code_align); + } else { + size += payload_size; + size = std.mem.alignForwardGeneric(u64, size, code_align); + size += code_size; + size = std.mem.alignForwardGeneric(u64, size, payload_align); + } + return AbiSizeAdvanced{ .scalar = size }; + }, .func_type => unreachable, // represents machine code; not a pointer .simple_type => |t| switch (t) { .bool, @@ -1982,7 +1708,7 @@ pub const Type = struct { ) Module.CompileError!AbiSizeAdvanced { const child_ty = ty.optionalChild(mod); - if (child_ty.isNoReturn()) { + if (child_ty.isNoReturn(mod)) { return AbiSizeAdvanced{ .scalar = 0 }; } @@ -2041,147 +1767,137 @@ pub const Type = struct { const strat: AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager; - switch (ty.ip_index) { - .none => switch (ty.tag()) { - .inferred_alloc_const => unreachable, - .inferred_alloc_mut => unreachable, - - .error_set, - .error_set_single, - .error_set_inferred, - .error_set_merged, - => return 16, // TODO revisit this when we have the concept of the error tag type + switch (mod.intern_pool.indexToKey(ty.ip_index)) { + .int_type => |int_type| return int_type.bits, + .ptr_type => |ptr_type| switch (ptr_type.size) { + .Slice => return target.ptrBitWidth() * 2, + else => return target.ptrBitWidth() * 2, + }, + .anyframe_type => return target.ptrBitWidth(), + + .array_type => |array_type| { + const len = array_type.len + @boolToInt(array_type.sentinel != .none); + if (len == 0) return 0; + const elem_ty = array_type.child.toType(); + const elem_size = std.math.max(elem_ty.abiAlignment(mod), elem_ty.abiSize(mod)); + if (elem_size == 0) return 0; + const elem_bit_size = try bitSizeAdvanced(elem_ty, mod, opt_sema); + return (len - 1) * 8 * elem_size + elem_bit_size; + }, + .vector_type => |vector_type| { + const child_ty = vector_type.child.toType(); + const elem_bit_size = try bitSizeAdvanced(child_ty, mod, opt_sema); + return elem_bit_size * vector_type.len; + }, + .opt_type => { + // Optionals and error unions are not packed so their bitsize + // includes padding bits. + return (try abiSizeAdvanced(ty, mod, strat)).scalar * 8; + }, + + // TODO revisit this when we have the concept of the error tag type + .error_set_type, .inferred_error_set_type => return 16, + + .error_union_type => { + // Optionals and error unions are not packed so their bitsize + // includes padding bits. + return (try abiSizeAdvanced(ty, mod, strat)).scalar * 8; + }, + .func_type => unreachable, // represents machine code; not a pointer + .simple_type => |t| switch (t) { + .f16 => return 16, + .f32 => return 32, + .f64 => return 64, + .f80 => return 80, + .f128 => return 128, + + .usize, + .isize, + => return target.ptrBitWidth(), + + .c_char => return target.c_type_bit_size(.char), + .c_short => return target.c_type_bit_size(.short), + .c_ushort => return target.c_type_bit_size(.ushort), + .c_int => return target.c_type_bit_size(.int), + .c_uint => return target.c_type_bit_size(.uint), + .c_long => return target.c_type_bit_size(.long), + .c_ulong => return target.c_type_bit_size(.ulong), + .c_longlong => return target.c_type_bit_size(.longlong), + .c_ulonglong => return target.c_type_bit_size(.ulonglong), + .c_longdouble => return target.c_type_bit_size(.longdouble), + + .bool => return 1, + .void => return 0, - .error_union => { - // Optionals and error unions are not packed so their bitsize - // includes padding bits. - return (try abiSizeAdvanced(ty, mod, strat)).scalar * 8; - }, + // TODO revisit this when we have the concept of the error tag type + .anyerror => return 16, + + .anyopaque => unreachable, + .type => unreachable, + .comptime_int => unreachable, + .comptime_float => unreachable, + .noreturn => unreachable, + .null => unreachable, + .undefined => unreachable, + .enum_literal => unreachable, + .generic_poison => unreachable, + .var_args_param => unreachable, + + .atomic_order => unreachable, // missing call to resolveTypeFields + .atomic_rmw_op => unreachable, // missing call to resolveTypeFields + .calling_convention => unreachable, // missing call to resolveTypeFields + .address_space => unreachable, // missing call to resolveTypeFields + .float_mode => unreachable, // missing call to resolveTypeFields + .reduce_op => unreachable, // missing call to resolveTypeFields + .call_modifier => unreachable, // missing call to resolveTypeFields + .prefetch_options => unreachable, // missing call to resolveTypeFields + .export_options => unreachable, // missing call to resolveTypeFields + .extern_options => unreachable, // missing call to resolveTypeFields + .type_info => unreachable, // missing call to resolveTypeFields }, - else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { - .int_type => |int_type| return int_type.bits, - .ptr_type => |ptr_type| switch (ptr_type.size) { - .Slice => return target.ptrBitWidth() * 2, - else => return target.ptrBitWidth() * 2, - }, - .anyframe_type => return target.ptrBitWidth(), - - .array_type => |array_type| { - const len = array_type.len + @boolToInt(array_type.sentinel != .none); - if (len == 0) return 0; - const elem_ty = array_type.child.toType(); - const elem_size = std.math.max(elem_ty.abiAlignment(mod), elem_ty.abiSize(mod)); - if (elem_size == 0) return 0; - const elem_bit_size = try bitSizeAdvanced(elem_ty, mod, opt_sema); - return (len - 1) * 8 * elem_size + elem_bit_size; - }, - .vector_type => |vector_type| { - const child_ty = vector_type.child.toType(); - const elem_bit_size = try bitSizeAdvanced(child_ty, mod, opt_sema); - return elem_bit_size * vector_type.len; - }, - .opt_type => { - // Optionals and error unions are not packed so their bitsize - // includes padding bits. - return (try abiSizeAdvanced(ty, mod, strat)).scalar * 8; - }, - .error_union_type => @panic("TODO"), - .func_type => unreachable, // represents machine code; not a pointer - .simple_type => |t| switch (t) { - .f16 => return 16, - .f32 => return 32, - .f64 => return 64, - .f80 => return 80, - .f128 => return 128, - - .usize, - .isize, - => return target.ptrBitWidth(), - - .c_char => return target.c_type_bit_size(.char), - .c_short => return target.c_type_bit_size(.short), - .c_ushort => return target.c_type_bit_size(.ushort), - .c_int => return target.c_type_bit_size(.int), - .c_uint => return target.c_type_bit_size(.uint), - .c_long => return target.c_type_bit_size(.long), - .c_ulong => return target.c_type_bit_size(.ulong), - .c_longlong => return target.c_type_bit_size(.longlong), - .c_ulonglong => return target.c_type_bit_size(.ulonglong), - .c_longdouble => return target.c_type_bit_size(.longdouble), - - .bool => return 1, - .void => return 0, - - // TODO revisit this when we have the concept of the error tag type - .anyerror => return 16, - - .anyopaque => unreachable, - .type => unreachable, - .comptime_int => unreachable, - .comptime_float => unreachable, - .noreturn => unreachable, - .null => unreachable, - .undefined => unreachable, - .enum_literal => unreachable, - .generic_poison => unreachable, - .var_args_param => unreachable, - - .atomic_order => unreachable, // missing call to resolveTypeFields - .atomic_rmw_op => unreachable, // missing call to resolveTypeFields - .calling_convention => unreachable, // missing call to resolveTypeFields - .address_space => unreachable, // missing call to resolveTypeFields - .float_mode => unreachable, // missing call to resolveTypeFields - .reduce_op => unreachable, // missing call to resolveTypeFields - .call_modifier => unreachable, // missing call to resolveTypeFields - .prefetch_options => unreachable, // missing call to resolveTypeFields - .export_options => unreachable, // missing call to resolveTypeFields - .extern_options => unreachable, // missing call to resolveTypeFields - .type_info => unreachable, // missing call to resolveTypeFields - }, - .struct_type => |struct_type| { - const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return 0; - if (struct_obj.layout != .Packed) { - return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8; - } - if (opt_sema) |sema| _ = try sema.resolveTypeLayout(ty); - assert(struct_obj.haveLayout()); - return try struct_obj.backing_int_ty.bitSizeAdvanced(mod, opt_sema); - }, - - .anon_struct_type => { - if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty); + .struct_type => |struct_type| { + const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return 0; + if (struct_obj.layout != .Packed) { return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8; - }, + } + if (opt_sema) |sema| _ = try sema.resolveTypeLayout(ty); + assert(struct_obj.haveLayout()); + return try struct_obj.backing_int_ty.bitSizeAdvanced(mod, opt_sema); + }, - .union_type => |union_type| { - if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty); - if (ty.containerLayout(mod) != .Packed) { - return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8; - } - const union_obj = mod.unionPtr(union_type.index); - assert(union_obj.haveFieldTypes()); + .anon_struct_type => { + if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty); + return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8; + }, - var size: u64 = 0; - for (union_obj.fields.values()) |field| { - size = @max(size, try bitSizeAdvanced(field.ty, mod, opt_sema)); - } - return size; - }, - .opaque_type => unreachable, - .enum_type => |enum_type| return bitSizeAdvanced(enum_type.tag_ty.toType(), mod, opt_sema), + .union_type => |union_type| { + if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty); + if (ty.containerLayout(mod) != .Packed) { + return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8; + } + const union_obj = mod.unionPtr(union_type.index); + assert(union_obj.haveFieldTypes()); - // values, not types - .undef => unreachable, - .un => unreachable, - .simple_value => unreachable, - .extern_func => unreachable, - .int => unreachable, - .float => unreachable, - .ptr => unreachable, - .opt => unreachable, - .enum_tag => unreachable, - .aggregate => unreachable, + var size: u64 = 0; + for (union_obj.fields.values()) |field| { + size = @max(size, try bitSizeAdvanced(field.ty, mod, opt_sema)); + } + return size; }, + .opaque_type => unreachable, + .enum_type => |enum_type| return bitSizeAdvanced(enum_type.tag_ty.toType(), mod, opt_sema), + + // values, not types + .undef => unreachable, + .un => unreachable, + .simple_value => unreachable, + .extern_func => unreachable, + .int => unreachable, + .float => unreachable, + .ptr => unreachable, + .opt => unreachable, + .enum_tag => unreachable, + .aggregate => unreachable, } } @@ -2210,7 +1926,7 @@ pub const Type = struct { return payload_ty.layoutIsResolved(mod); }, .ErrorUnion => { - const payload_ty = ty.errorUnionPayload(); + const payload_ty = ty.errorUnionPayload(mod); return payload_ty.layoutIsResolved(mod); }, else => return true, @@ -2223,8 +1939,6 @@ pub const Type = struct { .inferred_alloc_const, .inferred_alloc_mut, => true, - - else => false, }, else => return switch (mod.intern_pool.indexToKey(ty.ip_index)) { .ptr_type => |ptr_info| ptr_info.size == .One, @@ -2245,8 +1959,6 @@ pub const Type = struct { .inferred_alloc_const, .inferred_alloc_mut, => .One, - - else => null, }, else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { .ptr_type => |ptr_info| ptr_info.size, @@ -2534,69 +2246,43 @@ pub const Type = struct { } /// Asserts that the type is an error union. - pub fn errorUnionPayload(ty: Type) Type { - return switch (ty.ip_index) { - .anyerror_void_error_union_type => Type.void, - .none => switch (ty.tag()) { - .error_union => ty.castTag(.error_union).?.data.payload, - else => unreachable, - }, - else => @panic("TODO"), - }; + pub fn errorUnionPayload(ty: Type, mod: *Module) Type { + return mod.intern_pool.indexToKey(ty.ip_index).error_union_type.payload_type.toType(); } - pub fn errorUnionSet(ty: Type) Type { - return switch (ty.ip_index) { - .anyerror_void_error_union_type => Type.anyerror, - .none => switch (ty.tag()) { - .error_union => ty.castTag(.error_union).?.data.error_set, - else => unreachable, - }, - else => @panic("TODO"), - }; + /// Asserts that the type is an error union. + pub fn errorUnionSet(ty: Type, mod: *Module) Type { + return mod.intern_pool.indexToKey(ty.ip_index).error_union_type.error_set_type.toType(); } /// Returns false for unresolved inferred error sets. - pub fn errorSetIsEmpty(ty: Type, mod: *const Module) bool { - switch (ty.ip_index) { - .none => switch (ty.tag()) { - .error_set_inferred => { - const inferred_error_set = ty.castTag(.error_set_inferred).?.data; + pub fn errorSetIsEmpty(ty: Type, mod: *Module) bool { + return switch (ty.ip_index) { + .anyerror_type => false, + else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { + .error_set_type => |error_set_type| error_set_type.names.len == 0, + .inferred_error_set_type => |index| { + const inferred_error_set = mod.inferredErrorSetPtr(index); // Can't know for sure. if (!inferred_error_set.is_resolved) return false; if (inferred_error_set.is_anyerror) return false; return inferred_error_set.errors.count() == 0; }, - .error_set_single => return false, - .error_set => { - const err_set_obj = ty.castTag(.error_set).?.data; - return err_set_obj.names.count() == 0; - }, - .error_set_merged => { - const name_map = ty.castTag(.error_set_merged).?.data; - return name_map.count() == 0; - }, else => unreachable, }, - .anyerror_type => return false, - else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { - else => @panic("TODO"), - }, - } + }; } /// Returns true if it is an error set that includes anyerror, false otherwise. /// Note that the result may be a false negative if the type did not get error set /// resolution prior to this call. - pub fn isAnyError(ty: Type) bool { + pub fn isAnyError(ty: Type, mod: *Module) bool { return switch (ty.ip_index) { - .none => switch (ty.tag()) { - .error_set_inferred => ty.castTag(.error_set_inferred).?.data.is_anyerror, + .anyerror_type => true, + else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { + .inferred_error_set_type => |i| mod.inferredErrorSetPtr(i).is_anyerror, else => false, }, - .anyerror_type => true, - // TODO handle error_set_inferred here - else => false, }; } @@ -2610,30 +2296,50 @@ pub const Type = struct { /// Returns whether ty, which must be an error set, includes an error `name`. /// Might return a false negative if `ty` is an inferred error set and not fully /// resolved yet. - pub fn errorSetHasField(ty: Type, name: []const u8) bool { - if (ty.isAnyError()) { - return true; - } - - switch (ty.tag()) { - .error_set_single => { - const data = ty.castTag(.error_set_single).?.data; - return std.mem.eql(u8, data, name); - }, - .error_set_inferred => { - const data = ty.castTag(.error_set_inferred).?.data; - return data.errors.contains(name); - }, - .error_set_merged => { - const data = ty.castTag(.error_set_merged).?.data; - return data.contains(name); + pub fn errorSetHasFieldIp( + ip: *const InternPool, + ty: InternPool.Index, + name: InternPool.NullTerminatedString, + ) bool { + return switch (ty) { + .anyerror_type => true, + else => switch (ip.indexToKey(ty)) { + .error_set_type => |error_set_type| { + return error_set_type.nameIndex(ip, name) != null; + }, + .inferred_error_set_type => |index| { + const ies = ip.inferredErrorSetPtrConst(index); + if (ies.is_anyerror) return true; + return ies.errors.contains(name); + }, + else => unreachable, }, - .error_set => { - const data = ty.castTag(.error_set).?.data; - return data.names.contains(name); + }; + } + + /// Returns whether ty, which must be an error set, includes an error `name`. + /// Might return a false negative if `ty` is an inferred error set and not fully + /// resolved yet. + pub fn errorSetHasField(ty: Type, name: []const u8, mod: *Module) bool { + const ip = &mod.intern_pool; + return switch (ty.ip_index) { + .anyerror_type => true, + else => switch (ip.indexToKey(ty.ip_index)) { + .error_set_type => |error_set_type| { + // If the string is not interned, then the field certainly is not present. + const field_name_interned = ip.getString(name).unwrap() orelse return false; + return error_set_type.nameIndex(ip, field_name_interned) != null; + }, + .inferred_error_set_type => |index| { + const ies = ip.inferredErrorSetPtr(index); + if (ies.is_anyerror) return true; + // If the string is not interned, then the field certainly is not present. + const field_name_interned = ip.getString(name).unwrap() orelse return false; + return ies.errors.contains(field_name_interned); + }, + else => unreachable, }, - else => unreachable, - } + }; } /// Asserts the type is an array or vector or struct. @@ -2727,14 +2433,6 @@ pub const Type = struct { var ty = starting_ty; while (true) switch (ty.ip_index) { - .none => switch (ty.tag()) { - .error_set, .error_set_single, .error_set_inferred, .error_set_merged => { - // TODO revisit this when error sets support custom int types - return .{ .signedness = .unsigned, .bits = 16 }; - }, - - else => unreachable, - }, .anyerror_type => { // TODO revisit this when error sets support custom int types return .{ .signedness = .unsigned, .bits = 16 }; @@ -2760,6 +2458,9 @@ pub const Type = struct { .enum_type => |enum_type| ty = enum_type.tag_ty.toType(), .vector_type => |vector_type| ty = vector_type.child.toType(), + // TODO revisit this when error sets support custom int types + .error_set_type, .inferred_error_set_type => return .{ .signedness = .unsigned, .bits = 16 }, + .anon_struct_type => unreachable, .ptr_type => unreachable, @@ -2932,13 +2633,6 @@ pub const Type = struct { .empty_struct_type => return Value.empty_struct, .none => switch (ty.tag()) { - .error_union, - .error_set_single, - .error_set, - .error_set_merged, - .error_set_inferred, - => return null, - .inferred_alloc_const => unreachable, .inferred_alloc_mut => unreachable, }, @@ -2955,6 +2649,8 @@ pub const Type = struct { .error_union_type, .func_type, .anyframe_type, + .error_set_type, + .inferred_error_set_type, => return null, .array_type => |array_type| { @@ -3130,18 +2826,6 @@ pub const Type = struct { return switch (ty.ip_index) { .empty_struct_type => false, - .none => switch (ty.tag()) { - .error_set, - .error_set_single, - .error_set_inferred, - .error_set_merged, - => false, - - .inferred_alloc_mut => unreachable, - .inferred_alloc_const => unreachable, - - .error_union => return ty.errorUnionPayload().comptimeOnly(mod), - }, else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { .int_type => false, .ptr_type => |ptr_type| { @@ -3160,6 +2844,11 @@ pub const Type = struct { .vector_type => |vector_type| vector_type.child.toType().comptimeOnly(mod), .opt_type => |child| child.toType().comptimeOnly(mod), .error_union_type => |error_union_type| error_union_type.payload_type.toType().comptimeOnly(mod), + + .error_set_type, + .inferred_error_set_type, + => false, + // These are function bodies, not function pointers. .func_type => true, @@ -3418,17 +3107,11 @@ pub const Type = struct { } // Asserts that `ty` is an error set and not `anyerror`. - pub fn errorSetNames(ty: Type) []const []const u8 { - return switch (ty.tag()) { - .error_set_single => blk: { - // Work around coercion problems - const tmp: *const [1][]const u8 = &ty.castTag(.error_set_single).?.data; - break :blk tmp; - }, - .error_set_merged => ty.castTag(.error_set_merged).?.data.keys(), - .error_set => ty.castTag(.error_set).?.data.names.keys(), - .error_set_inferred => { - const inferred_error_set = ty.castTag(.error_set_inferred).?.data; + pub fn errorSetNames(ty: Type, mod: *Module) []const InternPool.NullTerminatedString { + return switch (mod.intern_pool.indexToKey(ty.ip_index)) { + .error_set_type => |x| x.names, + .inferred_error_set_type => |index| { + const inferred_error_set = mod.inferredErrorSetPtr(index); assert(inferred_error_set.is_resolved); assert(!inferred_error_set.is_anyerror); return inferred_error_set.errors.keys(); @@ -3437,26 +3120,6 @@ pub const Type = struct { }; } - /// Merge lhs with rhs. - /// Asserts that lhs and rhs are both error sets and are resolved. - pub fn errorSetMerge(lhs: Type, arena: Allocator, rhs: Type) !Type { - const lhs_names = lhs.errorSetNames(); - const rhs_names = rhs.errorSetNames(); - var names: Module.ErrorSet.NameMap = .{}; - try names.ensureUnusedCapacity(arena, lhs_names.len); - for (lhs_names) |name| { - names.putAssumeCapacityNoClobber(name, {}); - } - for (rhs_names) |name| { - try names.put(arena, name, {}); - } - - // names must be sorted - Module.ErrorSet.sortNames(&names); - - return try Tag.error_set_merged.create(arena, names); - } - pub fn enumFields(ty: Type, mod: *Module) []const InternPool.NullTerminatedString { return mod.intern_pool.indexToKey(ty.ip_index).enum_type.names; } @@ -3748,30 +3411,19 @@ pub const Type = struct { } pub fn declSrcLocOrNull(ty: Type, mod: *Module) ?Module.SrcLoc { - switch (ty.ip_index) { - .empty_struct_type => return null, - .none => switch (ty.tag()) { - .error_set => { - const error_set = ty.castTag(.error_set).?.data; - return error_set.srcLoc(mod); - }, - - else => return null, + return switch (mod.intern_pool.indexToKey(ty.ip_index)) { + .struct_type => |struct_type| { + const struct_obj = mod.structPtrUnwrap(struct_type.index).?; + return struct_obj.srcLoc(mod); }, - else => return switch (mod.intern_pool.indexToKey(ty.ip_index)) { - .struct_type => |struct_type| { - const struct_obj = mod.structPtrUnwrap(struct_type.index).?; - return struct_obj.srcLoc(mod); - }, - .union_type => |union_type| { - const union_obj = mod.unionPtr(union_type.index); - return union_obj.srcLoc(mod); - }, - .opaque_type => |opaque_type| mod.opaqueSrcLoc(opaque_type), - .enum_type => |enum_type| mod.declPtr(enum_type.decl).srcLoc(mod), - else => null, + .union_type => |union_type| { + const union_obj = mod.unionPtr(union_type.index); + return union_obj.srcLoc(mod); }, - } + .opaque_type => |opaque_type| mod.opaqueSrcLoc(opaque_type), + .enum_type => |enum_type| mod.declPtr(enum_type.decl).srcLoc(mod), + else => null, + }; } pub fn getOwnerDecl(ty: Type, mod: *Module) Module.Decl.Index { @@ -3779,39 +3431,25 @@ pub const Type = struct { } pub fn getOwnerDeclOrNull(ty: Type, mod: *Module) ?Module.Decl.Index { - switch (ty.ip_index) { - .none => switch (ty.tag()) { - .error_set => { - const error_set = ty.castTag(.error_set).?.data; - return error_set.owner_decl; - }, - - else => return null, + return switch (mod.intern_pool.indexToKey(ty.ip_index)) { + .struct_type => |struct_type| { + const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return null; + return struct_obj.owner_decl; }, - else => return switch (mod.intern_pool.indexToKey(ty.ip_index)) { - .struct_type => |struct_type| { - const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return null; - return struct_obj.owner_decl; - }, - .union_type => |union_type| { - const union_obj = mod.unionPtr(union_type.index); - return union_obj.owner_decl; - }, - .opaque_type => |opaque_type| opaque_type.decl, - .enum_type => |enum_type| enum_type.decl, - else => null, + .union_type => |union_type| { + const union_obj = mod.unionPtr(union_type.index); + return union_obj.owner_decl; }, - } + .opaque_type => |opaque_type| opaque_type.decl, + .enum_type => |enum_type| enum_type.decl, + else => null, + }; } pub fn isGenericPoison(ty: Type) bool { return ty.ip_index == .generic_poison_type; } - pub fn isBoundFn(ty: Type) bool { - return ty.ip_index == .none and ty.tag() == .bound_fn; - } - /// This enum does not directly correspond to `std.builtin.TypeId` because /// it has extra enum tags in it, as a way of using less memory. For example, /// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types @@ -3827,54 +3465,8 @@ pub const Type = struct { inferred_alloc_const, // See last_no_payload_tag below. // After this, the tag requires a payload. - error_union, - error_set, - error_set_single, - /// The type is the inferred error set of a specific function. - error_set_inferred, - error_set_merged, - pub const last_no_payload_tag = Tag.inferred_alloc_const; pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; - - pub fn Type(comptime t: Tag) type { - return switch (t) { - .inferred_alloc_const, - .inferred_alloc_mut, - => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"), - - .error_set => Payload.ErrorSet, - .error_set_inferred => Payload.ErrorSetInferred, - .error_set_merged => Payload.ErrorSetMerged, - - .error_union => Payload.ErrorUnion, - .error_set_single => Payload.Name, - }; - } - - pub fn init(comptime t: Tag) file_struct.Type { - comptime std.debug.assert(@enumToInt(t) < Tag.no_payload_count); - return file_struct.Type{ - .ip_index = .none, - .legacy = .{ .tag_if_small_enough = t }, - }; - } - - pub fn create(comptime t: Tag, ally: Allocator, data: Data(t)) error{OutOfMemory}!file_struct.Type { - const p = try ally.create(t.Type()); - p.* = .{ - .base = .{ .tag = t }, - .data = data, - }; - return file_struct.Type{ - .ip_index = .none, - .legacy = .{ .ptr_otherwise = &p.base }, - }; - } - - pub fn Data(comptime t: Tag) type { - return std.meta.fieldInfo(t.Type(), .data).type; - } }; pub fn isTuple(ty: Type, mod: *Module) bool { @@ -3928,37 +3520,6 @@ pub const Type = struct { pub const Payload = struct { tag: Tag, - pub const Len = struct { - base: Payload, - data: u64, - }; - - pub const Bits = struct { - base: Payload, - data: u16, - }; - - pub const ErrorSet = struct { - pub const base_tag = Tag.error_set; - - base: Payload = Payload{ .tag = base_tag }, - data: *Module.ErrorSet, - }; - - pub const ErrorSetMerged = struct { - pub const base_tag = Tag.error_set_merged; - - base: Payload = Payload{ .tag = base_tag }, - data: Module.ErrorSet.NameMap, - }; - - pub const ErrorSetInferred = struct { - pub const base_tag = Tag.error_set_inferred; - - base: Payload = Payload{ .tag = base_tag }, - data: *Module.Fn.InferredErrorSet, - }; - /// TODO: remove this data structure since we have `InternPool.Key.PtrType`. pub const Pointer = struct { data: Data, @@ -4010,27 +3571,6 @@ pub const Type = struct { } }; }; - - pub const ErrorUnion = struct { - pub const base_tag = Tag.error_union; - - base: Payload = Payload{ .tag = base_tag }, - data: struct { - error_set: Type, - payload: Type, - }, - }; - - pub const Decl = struct { - base: Payload, - data: *Module.Decl, - }; - - pub const Name = struct { - base: Payload, - /// memory is owned by `Module` - data: []const u8, - }; }; pub const @"u1": Type = .{ .ip_index = .u1_type, .legacy = undefined }; @@ -4164,19 +3704,6 @@ pub const Type = struct { return mod.optionalType(child_type.ip_index); } - pub fn errorUnion( - arena: Allocator, - error_set: Type, - payload: Type, - mod: *Module, - ) Allocator.Error!Type { - assert(error_set.zigTypeTag(mod) == .ErrorSet); - 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); |
