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 | |
| 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')
| -rw-r--r-- | src/Air.zig | 2 | ||||
| -rw-r--r-- | src/InternPool.zig | 176 | ||||
| -rw-r--r-- | src/Liveness.zig | 2 | ||||
| -rw-r--r-- | src/Liveness/Verify.zig | 2 | ||||
| -rw-r--r-- | src/Module.zig | 169 | ||||
| -rw-r--r-- | src/Sema.zig | 821 | ||||
| -rw-r--r-- | src/TypedValue.zig | 6 | ||||
| -rw-r--r-- | src/arch/aarch64/CodeGen.zig | 18 | ||||
| -rw-r--r-- | src/arch/arm/CodeGen.zig | 18 | ||||
| -rw-r--r-- | src/arch/sparc64/CodeGen.zig | 20 | ||||
| -rw-r--r-- | src/arch/wasm/CodeGen.zig | 41 | ||||
| -rw-r--r-- | src/arch/x86_64/CodeGen.zig | 28 | ||||
| -rw-r--r-- | src/codegen.zig | 12 | ||||
| -rw-r--r-- | src/codegen/c.zig | 39 | ||||
| -rw-r--r-- | src/codegen/c/type.zig | 4 | ||||
| -rw-r--r-- | src/codegen/llvm.zig | 74 | ||||
| -rw-r--r-- | src/codegen/spirv.zig | 13 | ||||
| -rw-r--r-- | src/link/Dwarf.zig | 54 | ||||
| -rw-r--r-- | src/print_air.zig | 1 | ||||
| -rw-r--r-- | src/type.zig | 1251 | ||||
| -rw-r--r-- | src/value.zig | 18 |
21 files changed, 1191 insertions, 1578 deletions
diff --git a/src/Air.zig b/src/Air.zig index 09f8d6c9e2..6673a37fb6 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -1411,7 +1411,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index, ip: InternPool) Type { .@"try" => { const err_union_ty = air.typeOf(datas[inst].pl_op.operand, ip); - return err_union_ty.errorUnionPayload(); + return ip.indexToKey(err_union_ty.ip_index).error_union_type.payload_type.toType(); }, .work_item_id, diff --git a/src/InternPool.zig b/src/InternPool.zig index 81035bffc5..79506c4404 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -34,6 +34,14 @@ allocated_unions: std.SegmentedList(Module.Union, 0) = .{}, /// When a Union object is freed from `allocated_unions`, it is pushed into this stack. unions_free_list: std.ArrayListUnmanaged(Module.Union.Index) = .{}, +/// InferredErrorSet objects are stored in this data structure because: +/// * They contain pointers such as the errors map and the set of other inferred error sets. +/// * They need to be mutated after creation. +allocated_inferred_error_sets: std.SegmentedList(Module.Fn.InferredErrorSet, 0) = .{}, +/// When a Struct object is freed from `allocated_inferred_error_sets`, it is +/// pushed into this stack. +inferred_error_sets_free_list: std.ArrayListUnmanaged(Module.Fn.InferredErrorSet.Index) = .{}, + /// Some types such as enums, structs, and unions need to store mappings from field names /// to field index, or value to field index. In such cases, they will store the underlying /// field names and values directly, relying on one of these maps, stored separately, @@ -113,6 +121,12 @@ pub const NullTerminatedString = enum(u32) { return std.hash.uint32(@enumToInt(a)); } }; + + /// Compare based on integer value alone, ignoring the string contents. + pub fn indexLessThan(ctx: void, a: NullTerminatedString, b: NullTerminatedString) bool { + _ = ctx; + return @enumToInt(a) < @enumToInt(b); + } }; /// An index into `string_bytes` which might be `none`. @@ -135,10 +149,7 @@ pub const Key = union(enum) { /// `anyframe->T`. The payload is the child type, which may be `none` to indicate /// `anyframe`. anyframe_type: Index, - error_union_type: struct { - error_set_type: Index, - payload_type: Index, - }, + error_union_type: ErrorUnionType, simple_type: SimpleType, /// This represents a struct that has been explicitly declared in source code, /// or was created with `@Type`. It is unique and based on a declaration. @@ -152,6 +163,8 @@ pub const Key = union(enum) { opaque_type: OpaqueType, enum_type: EnumType, func_type: FuncType, + error_set_type: ErrorSetType, + inferred_error_set_type: Module.Fn.InferredErrorSet.Index, /// Typed `undefined`. This will never be `none`; untyped `undefined` is represented /// via `simple_value` and has a named `Index` tag for it. @@ -183,6 +196,26 @@ pub const Key = union(enum) { pub const IntType = std.builtin.Type.Int; + pub const ErrorUnionType = struct { + error_set_type: Index, + payload_type: Index, + }; + + pub const ErrorSetType = struct { + /// Set of error names, sorted by null terminated string index. + names: []const NullTerminatedString, + /// This is ignored by `get` but will always be provided by `indexToKey`. + names_map: OptionalMapIndex = .none, + + /// Look up field index based on field name. + pub fn nameIndex(self: ErrorSetType, ip: *const InternPool, name: NullTerminatedString) ?u32 { + const map = &ip.maps.items[@enumToInt(self.names_map.unwrap().?)]; + const adapter: NullTerminatedString.Adapter = .{ .strings = self.names }; + const field_index = map.getIndexAdapted(name, adapter) orelse return null; + return @intCast(u32, field_index); + } + }; + pub const PtrType = struct { elem_type: Index, sentinel: Index = .none, @@ -507,6 +540,7 @@ pub const Key = union(enum) { .un, .undef, .enum_tag, + .inferred_error_set_type, => |info| std.hash.autoHash(hasher, info), .opaque_type => |opaque_type| std.hash.autoHash(hasher, opaque_type.decl), @@ -535,7 +569,7 @@ pub const Key = union(enum) { .ptr => |ptr| { std.hash.autoHash(hasher, ptr.ty); // Int-to-ptr pointers are hashed separately than decl-referencing pointers. - // This is sound due to pointer province rules. + // This is sound due to pointer provenance rules. switch (ptr.addr) { .int => |int| std.hash.autoHash(hasher, int), .decl => @panic("TODO"), @@ -547,6 +581,10 @@ pub const Key = union(enum) { for (aggregate.fields) |field| std.hash.autoHash(hasher, field); }, + .error_set_type => |error_set_type| { + for (error_set_type.names) |elem| std.hash.autoHash(hasher, elem); + }, + .anon_struct_type => |anon_struct_type| { for (anon_struct_type.types) |elem| std.hash.autoHash(hasher, elem); for (anon_struct_type.values) |elem| std.hash.autoHash(hasher, elem); @@ -726,6 +764,14 @@ pub const Key = union(enum) { std.mem.eql(Index, a_info.values, b_info.values) and std.mem.eql(NullTerminatedString, a_info.names, b_info.names); }, + .error_set_type => |a_info| { + const b_info = b.error_set_type; + return std.mem.eql(NullTerminatedString, a_info.names, b_info.names); + }, + .inferred_error_set_type => |a_info| { + const b_info = b.inferred_error_set_type; + return a_info == b_info; + }, .func_type => |a_info| { const b_info = b.func_type; @@ -752,6 +798,8 @@ pub const Key = union(enum) { .opt_type, .anyframe_type, .error_union_type, + .error_set_type, + .inferred_error_set_type, .simple_type, .struct_type, .union_type, @@ -1207,8 +1255,14 @@ pub const Tag = enum(u8) { /// If the child type is `none`, the type is `anyframe`. type_anyframe, /// An error union type. - /// data is payload to ErrorUnion. + /// data is payload to `Key.ErrorUnionType`. type_error_union, + /// An error set type. + /// data is payload to `ErrorSet`. + type_error_set, + /// The inferred error set type of a function. + /// data is `Module.Fn.InferredErrorSet.Index`. + type_inferred_error_set, /// An enum type with auto-numbered tag values. /// The enum is exhaustive. /// data is payload index to `EnumAuto`. @@ -1356,6 +1410,12 @@ pub const Tag = enum(u8) { }; /// Trailing: +/// 0. name: NullTerminatedString for each names_len +pub const ErrorSet = struct { + names_len: u32, +}; + +/// Trailing: /// 0. param_type: Index for each params_len pub const TypeFunction = struct { params_len: u32, @@ -1539,11 +1599,6 @@ pub const Array = struct { } }; -pub const ErrorUnion = struct { - error_set_type: Index, - payload_type: Index, -}; - /// Trailing: /// 0. field name: NullTerminatedString for each fields_len; declaration order /// 1. tag value: Index for each fields_len; declaration order @@ -1719,6 +1774,9 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void { ip.unions_free_list.deinit(gpa); ip.allocated_unions.deinit(gpa); + ip.inferred_error_sets_free_list.deinit(gpa); + ip.allocated_inferred_error_sets.deinit(gpa); + for (ip.maps.items) |*map| map.deinit(gpa); ip.maps.deinit(gpa); @@ -1798,7 +1856,18 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { .type_optional => .{ .opt_type = @intToEnum(Index, data) }, .type_anyframe => .{ .anyframe_type = @intToEnum(Index, data) }, - .type_error_union => @panic("TODO"), + .type_error_union => .{ .error_union_type = ip.extraData(Key.ErrorUnionType, data) }, + .type_error_set => { + const error_set = ip.extraDataTrail(ErrorSet, data); + const names_len = error_set.data.names_len; + const names = ip.extra.items[error_set.end..][0..names_len]; + return .{ .error_set_type = .{ + .names = @ptrCast([]const NullTerminatedString, names), + } }; + }, + .type_inferred_error_set => .{ + .inferred_error_set_type = @intToEnum(Module.Fn.InferredErrorSet.Index, data), + }, .type_opaque => .{ .opaque_type = ip.extraData(Key.OpaqueType, data) }, .type_struct => { @@ -2179,11 +2248,29 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { .error_union_type => |error_union_type| { ip.items.appendAssumeCapacity(.{ .tag = .type_error_union, - .data = try ip.addExtra(gpa, ErrorUnion{ - .error_set_type = error_union_type.error_set_type, - .payload_type = error_union_type.payload_type, + .data = try ip.addExtra(gpa, error_union_type), + }); + }, + .error_set_type => |error_set_type| { + assert(error_set_type.names_map == .none); + assert(std.sort.isSorted(NullTerminatedString, error_set_type.names, {}, NullTerminatedString.indexLessThan)); + const names_map = try ip.addMap(gpa); + try addStringsToMap(ip, gpa, names_map, error_set_type.names); + const names_len = @intCast(u32, error_set_type.names.len); + try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(ErrorSet).Struct.fields.len + names_len); + ip.items.appendAssumeCapacity(.{ + .tag = .type_error_set, + .data = ip.addExtraAssumeCapacity(ErrorSet{ + .names_len = names_len, }), }); + ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, error_set_type.names)); + }, + .inferred_error_set_type => |ies_index| { + ip.items.appendAssumeCapacity(.{ + .tag = .type_inferred_error_set, + .data = @enumToInt(ies_index), + }); }, .simple_type => |simple_type| { ip.items.appendAssumeCapacity(.{ @@ -3192,12 +3279,26 @@ pub fn indexToFuncType(ip: InternPool, val: Index) ?Key.FuncType { } } +pub fn indexToInferredErrorSetType(ip: InternPool, val: Index) Module.Fn.InferredErrorSet.OptionalIndex { + assert(val != .none); + const tags = ip.items.items(.tag); + if (tags[@enumToInt(val)] != .type_inferred_error_set) return .none; + const datas = ip.items.items(.data); + return @intToEnum(Module.Fn.InferredErrorSet.Index, datas[@enumToInt(val)]).toOptional(); +} + pub fn isOptionalType(ip: InternPool, ty: Index) bool { const tags = ip.items.items(.tag); if (ty == .none) return false; return tags[@enumToInt(ty)] == .type_optional; } +pub fn isInferredErrorSetType(ip: InternPool, ty: Index) bool { + const tags = ip.items.items(.tag); + assert(ty != .none); + return tags[@enumToInt(ty)] == .type_inferred_error_set; +} + pub fn dump(ip: InternPool) void { dumpFallible(ip, std.heap.page_allocator) catch return; } @@ -3258,7 +3359,12 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { .type_slice => 0, .type_optional => 0, .type_anyframe => 0, - .type_error_union => @sizeOf(ErrorUnion), + .type_error_union => @sizeOf(Key.ErrorUnionType), + .type_error_set => b: { + const info = ip.extraData(ErrorSet, data); + break :b @sizeOf(ErrorSet) + (@sizeOf(u32) * info.names_len); + }, + .type_inferred_error_set => @sizeOf(Module.Fn.InferredErrorSet), .type_enum_explicit, .type_enum_nonexhaustive => @sizeOf(EnumExplicit), .type_enum_auto => @sizeOf(EnumAuto), .type_opaque => @sizeOf(Key.OpaqueType), @@ -3359,6 +3465,14 @@ pub fn unionPtr(ip: *InternPool, index: Module.Union.Index) *Module.Union { return ip.allocated_unions.at(@enumToInt(index)); } +pub fn inferredErrorSetPtr(ip: *InternPool, index: Module.Fn.InferredErrorSet.Index) *Module.Fn.InferredErrorSet { + return ip.allocated_inferred_error_sets.at(@enumToInt(index)); +} + +pub fn inferredErrorSetPtrConst(ip: InternPool, index: Module.Fn.InferredErrorSet.Index) *const Module.Fn.InferredErrorSet { + return ip.allocated_inferred_error_sets.at(@enumToInt(index)); +} + pub fn createStruct( ip: *InternPool, gpa: Allocator, @@ -3397,6 +3511,25 @@ pub fn destroyUnion(ip: *InternPool, gpa: Allocator, index: Module.Union.Index) }; } +pub fn createInferredErrorSet( + ip: *InternPool, + gpa: Allocator, + initialization: Module.Fn.InferredErrorSet, +) Allocator.Error!Module.Fn.InferredErrorSet.Index { + if (ip.inferred_error_sets_free_list.popOrNull()) |index| return index; + const ptr = try ip.allocated_inferred_error_sets.addOne(gpa); + ptr.* = initialization; + return @intToEnum(Module.Fn.InferredErrorSet.Index, ip.allocated_inferred_error_sets.len - 1); +} + +pub fn destroyInferredErrorSet(ip: *InternPool, gpa: Allocator, index: Module.Fn.InferredErrorSet.Index) void { + ip.inferredErrorSetPtr(index).* = undefined; + ip.inferred_error_sets_free_list.append(gpa, index) catch { + // In order to keep `destroyInferredErrorSet` a non-fallible function, we ignore memory + // allocation failures here, instead leaking the InferredErrorSet until garbage collection. + }; +} + pub fn getOrPutString( ip: *InternPool, gpa: Allocator, @@ -3459,3 +3592,14 @@ pub fn aggregateTypeLen(ip: InternPool, ty: Index) u64 { else => unreachable, }; } + +pub fn isNoReturn(ip: InternPool, ty: InternPool.Index) bool { + return switch (ty) { + .noreturn_type => true, + else => switch (ip.indexToKey(ty)) { + .error_set_type => |error_set_type| error_set_type.names.len == 0, + .enum_type => |enum_type| enum_type.names.len == 0, + else => false, + }, + }; +} diff --git a/src/Liveness.zig b/src/Liveness.zig index da705cfab8..856123fa9d 100644 --- a/src/Liveness.zig +++ b/src/Liveness.zig @@ -1416,7 +1416,7 @@ fn analyzeInstBlock( // If the block is noreturn, block deaths not only aren't useful, they're impossible to // find: there could be more stuff alive after the block than before it! - if (!a.air.getRefType(ty_pl.ty).isNoReturn()) { + if (!a.intern_pool.isNoReturn(a.air.getRefType(ty_pl.ty).ip_index)) { // The block kills the difference in the live sets const block_scope = data.block_scopes.get(inst).?; const num_deaths = data.live_set.count() - block_scope.live_set.count(); diff --git a/src/Liveness/Verify.zig b/src/Liveness/Verify.zig index dbdbf32174..923e6f5658 100644 --- a/src/Liveness/Verify.zig +++ b/src/Liveness/Verify.zig @@ -453,7 +453,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { for (block_liveness.deaths) |death| try self.verifyDeath(inst, death); - if (block_ty.isNoReturn()) { + if (ip.isNoReturn(block_ty.toIntern())) { assert(!self.blocks.contains(inst)); } else { var live = self.blocks.fetchRemove(inst).?.value; diff --git a/src/Module.zig b/src/Module.zig index 5cd0d237b4..70b08ea3a9 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -960,38 +960,6 @@ pub const EmitH = struct { fwd_decl: ArrayListUnmanaged(u8) = .{}, }; -/// Represents the data that an explicit error set syntax provides. -pub const ErrorSet = struct { - /// The Decl that corresponds to the error set itself. - owner_decl: Decl.Index, - /// The string bytes are stored in the owner Decl arena. - /// These must be in sorted order. See sortNames. - names: NameMap, - - pub const NameMap = std.StringArrayHashMapUnmanaged(void); - - pub fn srcLoc(self: ErrorSet, mod: *Module) SrcLoc { - const owner_decl = mod.declPtr(self.owner_decl); - return .{ - .file_scope = owner_decl.getFileScope(mod), - .parent_decl_node = owner_decl.src_node, - .lazy = LazySrcLoc.nodeOffset(0), - }; - } - - /// sort the NameMap. This should be called whenever the map is modified. - /// alloc should be the allocator used for the NameMap data. - pub fn sortNames(names: *NameMap) void { - const Context = struct { - keys: [][]const u8, - pub fn lessThan(ctx: @This(), a_index: usize, b_index: usize) bool { - return std.mem.lessThan(u8, ctx.keys[a_index], ctx.keys[b_index]); - } - }; - names.sort(Context{ .keys = names.keys() }); - } -}; - pub const PropertyBoolean = enum { no, yes, unknown, wip }; /// Represents the data that a struct declaration provides. @@ -1530,13 +1498,6 @@ pub const Fn = struct { is_noinline: bool, calls_or_awaits_errorable_fn: bool = false, - /// Any inferred error sets that this function owns, both its own inferred error set and - /// inferred error sets of any inline/comptime functions called. Not to be confused - /// with inferred error sets of generic instantiations of this function, which are - /// *not* tracked here - they are tracked in the new `Fn` object created for the - /// instantiations. - inferred_error_sets: InferredErrorSetList = .{}, - pub const Analysis = enum { /// This function has not yet undergone analysis, because we have not /// seen a potential runtime call. It may be analyzed in future. @@ -1568,10 +1529,10 @@ pub const Fn = struct { /// direct additions via `return error.Foo;`, and possibly also errors that /// are returned from any dependent functions. When the inferred error set is /// fully resolved, this map contains all the errors that the function might return. - errors: ErrorSet.NameMap = .{}, + errors: NameMap = .{}, /// Other inferred error sets which this inferred error set should include. - inferred_error_sets: std.AutoArrayHashMapUnmanaged(*InferredErrorSet, void) = .{}, + inferred_error_sets: std.AutoArrayHashMapUnmanaged(InferredErrorSet.Index, void) = .{}, /// Whether the function returned anyerror. This is true if either of /// the dependent functions returns anyerror. @@ -1581,51 +1542,59 @@ pub const Fn = struct { /// can skip resolving any dependents of this inferred error set. is_resolved: bool = false, - pub fn addErrorSet(self: *InferredErrorSet, gpa: Allocator, err_set_ty: Type) !void { + pub const NameMap = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void); + + pub const Index = enum(u32) { + _, + + pub fn toOptional(i: Index) OptionalIndex { + return @intToEnum(OptionalIndex, @enumToInt(i)); + } + }; + + pub const OptionalIndex = enum(u32) { + none = std.math.maxInt(u32), + _, + + pub fn init(oi: ?Index) OptionalIndex { + return @intToEnum(OptionalIndex, @enumToInt(oi orelse return .none)); + } + + pub fn unwrap(oi: OptionalIndex) ?Index { + if (oi == .none) return null; + return @intToEnum(Index, @enumToInt(oi)); + } + }; + + pub fn addErrorSet( + self: *InferredErrorSet, + err_set_ty: Type, + ip: *InternPool, + gpa: Allocator, + ) !void { switch (err_set_ty.ip_index) { .anyerror_type => { self.is_anyerror = true; }, - .none => switch (err_set_ty.tag()) { - .error_set => { - const names = err_set_ty.castTag(.error_set).?.data.names.keys(); - for (names) |name| { + else => switch (ip.indexToKey(err_set_ty.ip_index)) { + .error_set_type => |error_set_type| { + for (error_set_type.names) |name| { try self.errors.put(gpa, name, {}); } }, - .error_set_single => { - const name = err_set_ty.castTag(.error_set_single).?.data; - try self.errors.put(gpa, name, {}); - }, - .error_set_inferred => { - const ies = err_set_ty.castTag(.error_set_inferred).?.data; - try self.inferred_error_sets.put(gpa, ies, {}); - }, - .error_set_merged => { - const names = err_set_ty.castTag(.error_set_merged).?.data.keys(); - for (names) |name| { - try self.errors.put(gpa, name, {}); - } + .inferred_error_set_type => |ies_index| { + try self.inferred_error_sets.put(gpa, ies_index, {}); }, else => unreachable, }, - else => @panic("TODO"), } } }; - pub const InferredErrorSetList = std.SinglyLinkedList(InferredErrorSet); - pub const InferredErrorSetListNode = InferredErrorSetList.Node; - + /// TODO: remove this function pub fn deinit(func: *Fn, gpa: Allocator) void { - var it = func.inferred_error_sets.first; - while (it) |node| { - const next = node.next; - node.data.errors.deinit(gpa); - node.data.inferred_error_sets.deinit(gpa); - gpa.destroy(node); - it = next; - } + _ = func; + _ = gpa; } pub fn isAnytypeParam(func: Fn, mod: *Module, index: u32) bool { @@ -3508,6 +3477,10 @@ pub fn structPtr(mod: *Module, index: Struct.Index) *Struct { return mod.intern_pool.structPtr(index); } +pub fn inferredErrorSetPtr(mod: *Module, index: Fn.InferredErrorSet.Index) *Fn.InferredErrorSet { + return mod.intern_pool.inferredErrorSetPtr(index); +} + /// This one accepts an index from the InternPool and asserts that it is not /// the anonymous empty struct type. pub fn structPtrUnwrap(mod: *Module, index: Struct.OptionalIndex) ?*Struct { @@ -4722,7 +4695,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { decl_tv.ty.fmt(mod), }); } - const ty = try decl_tv.val.toType().copy(decl_arena_allocator); + const ty = decl_tv.val.toType(); if (ty.getNamespace(mod) == null) { return sema.fail(&block_scope, ty_src, "type {} has no namespace", .{ty.fmt(mod)}); } @@ -4756,7 +4729,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { } decl.clearValues(mod); - decl.ty = try decl_tv.ty.copy(decl_arena_allocator); + decl.ty = decl_tv.ty; decl.val = try decl_tv.val.copy(decl_arena_allocator); // linksection, align, and addrspace were already set by Sema decl.has_tv = true; @@ -4823,7 +4796,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { }, } - decl.ty = try decl_tv.ty.copy(decl_arena_allocator); + decl.ty = decl_tv.ty; decl.val = try decl_tv.val.copy(decl_arena_allocator); decl.@"align" = blk: { const align_ref = decl.zirAlignRef(mod); @@ -6599,7 +6572,7 @@ pub fn populateTestFunctions( // This copy accesses the old Decl Type/Value so it must be done before `clearValues`. const new_ty = try Type.ptr(arena, mod, .{ .size = .Slice, - .pointee_type = try tmp_test_fn_ty.copy(arena), + .pointee_type = tmp_test_fn_ty, .mutable = false, .@"addrspace" = .generic, }); @@ -6877,6 +6850,42 @@ pub fn anyframeType(mod: *Module, payload_ty: Type) Allocator.Error!Type { return (try intern(mod, .{ .anyframe_type = payload_ty.toIntern() })).toType(); } +pub fn errorUnionType(mod: *Module, error_set_ty: Type, payload_ty: Type) Allocator.Error!Type { + return (try intern(mod, .{ .error_union_type = .{ + .error_set_type = error_set_ty.toIntern(), + .payload_type = payload_ty.toIntern(), + } })).toType(); +} + +pub fn singleErrorSetType(mod: *Module, name: []const u8) Allocator.Error!Type { + const gpa = mod.gpa; + const ip = &mod.intern_pool; + return singleErrorSetTypeNts(mod, try ip.getOrPutString(gpa, name)); +} + +pub fn singleErrorSetTypeNts(mod: *Module, name: InternPool.NullTerminatedString) Allocator.Error!Type { + const gpa = mod.gpa; + const ip = &mod.intern_pool; + const names = [1]InternPool.NullTerminatedString{name}; + const i = try ip.get(gpa, .{ .error_set_type = .{ .names = &names } }); + return i.toType(); +} + +/// Sorts `names` in place. +pub fn errorSetFromUnsortedNames( + mod: *Module, + names: []InternPool.NullTerminatedString, +) Allocator.Error!Type { + std.mem.sort( + InternPool.NullTerminatedString, + names, + {}, + InternPool.NullTerminatedString.indexLessThan, + ); + const new_ty = try mod.intern(.{ .error_set_type = .{ .names = names } }); + return new_ty.toType(); +} + /// Supports optionals in addition to pointers. pub fn ptrIntValue(mod: *Module, ty: Type, x: u64) Allocator.Error!Value { if (ty.isPtrLikeOptional(mod)) { @@ -7240,6 +7249,16 @@ pub fn typeToFunc(mod: *Module, ty: Type) ?InternPool.Key.FuncType { return mod.intern_pool.indexToFuncType(ty.ip_index); } +pub fn typeToInferredErrorSet(mod: *Module, ty: Type) ?*Fn.InferredErrorSet { + const index = typeToInferredErrorSetIndex(mod, ty).unwrap() orelse return null; + return mod.inferredErrorSetPtr(index); +} + +pub fn typeToInferredErrorSetIndex(mod: *Module, ty: Type) Fn.InferredErrorSet.OptionalIndex { + if (ty.ip_index == .none) return .none; + return mod.intern_pool.indexToInferredErrorSetType(ty.ip_index); +} + pub fn fieldSrcLoc(mod: *Module, owner_decl_index: Decl.Index, query: FieldSrcQuery) SrcLoc { @setCold(true); const owner_decl = mod.declPtr(owner_decl_index); diff --git a/src/Sema.zig b/src/Sema.zig index 74efe9d141..be505d74a3 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -825,12 +825,13 @@ pub fn analyzeBodyBreak( block: *Block, body: []const Zir.Inst.Index, ) CompileError!?BreakData { + const mod = sema.mod; const break_inst = sema.analyzeBodyInner(block, body) catch |err| switch (err) { error.ComptimeBreak => sema.comptime_break_inst, else => |e| return e, }; if (block.instructions.items.len != 0 and - sema.typeOf(Air.indexToRef(block.instructions.items[block.instructions.items.len - 1])).isNoReturn()) + sema.typeOf(Air.indexToRef(block.instructions.items[block.instructions.items.len - 1])).isNoReturn(mod)) return null; const break_data = sema.code.instructions.items(.data)[break_inst].@"break"; const extra = sema.code.extraData(Zir.Inst.Break, break_data.payload_index).data; @@ -1701,7 +1702,7 @@ fn analyzeBodyInner( break :blk Air.Inst.Ref.void_value; }, }; - if (sema.typeOf(air_inst).isNoReturn()) + if (sema.typeOf(air_inst).isNoReturn(mod)) break always_noreturn; map.putAssumeCapacity(inst, air_inst); i += 1; @@ -1796,8 +1797,7 @@ fn analyzeAsType( const wanted_type = Type.type; const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); const val = try sema.resolveConstValue(block, src, coerced_inst, "types must be comptime-known"); - const ty = val.toType(); - return ty.copy(sema.arena); + return val.toType(); } pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) !void { @@ -2004,7 +2004,7 @@ fn resolveMaybeUndefValAllowVariablesMaybeRuntime( if (val.isPtrToThreadLocal(sema.mod)) make_runtime.* = true; return val; }, - .const_ty => return try air_datas[i].ty.toValue(sema.arena), + .const_ty => return air_datas[i].ty.toValue(), .interned => return air_datas[i].interned.toValue(), else => return null, } @@ -2131,7 +2131,7 @@ fn failWithInvalidFieldAccess(sema: *Sema, block: *Block, src: LazySrcLoc, objec }; return sema.failWithOwnedErrorMsg(msg); } else if (inner_ty.zigTypeTag(mod) == .ErrorUnion) err: { - const child_ty = inner_ty.errorUnionPayload(); + const child_ty = inner_ty.errorUnionPayload(mod); if (!typeSupportsFieldAccess(mod, child_ty, field_name)) break :err; const msg = msg: { const msg = try sema.errMsg(block, src, "error union type '{}' does not support field access", .{object_ty.fmt(sema.mod)}); @@ -2473,7 +2473,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE var anon_decl = try block.startAnonDecl(); defer anon_decl.deinit(); iac.data.decl_index = try anon_decl.finish( - try pointee_ty.copy(anon_decl.arena()), + pointee_ty, Value.undef, iac.data.alignment, ); @@ -3250,47 +3250,35 @@ fn zirErrorSetDecl( const tracy = trace(@src()); defer tracy.end(); + const mod = sema.mod; const gpa = sema.gpa; const inst_data = sema.code.instructions.items(.data)[inst].pl_node; const src = inst_data.src(); const extra = sema.code.extraData(Zir.Inst.ErrorSetDecl, inst_data.payload_index); - var new_decl_arena = std.heap.ArenaAllocator.init(gpa); - errdefer new_decl_arena.deinit(); - const new_decl_arena_allocator = new_decl_arena.allocator(); - - const error_set = try new_decl_arena_allocator.create(Module.ErrorSet); - const error_set_ty = try Type.Tag.error_set.create(new_decl_arena_allocator, error_set); - const error_set_val = try Value.Tag.ty.create(new_decl_arena_allocator, error_set_ty); - const mod = sema.mod; - const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ - .ty = Type.type, - .val = error_set_val, - }, name_strategy, "error", inst); - const new_decl = mod.declPtr(new_decl_index); - new_decl.owns_tv = true; - errdefer mod.abortAnonDecl(new_decl_index); - - var names = Module.ErrorSet.NameMap{}; - try names.ensureUnusedCapacity(new_decl_arena_allocator, extra.data.fields_len); + var names: Module.Fn.InferredErrorSet.NameMap = .{}; + try names.ensureUnusedCapacity(sema.arena, extra.data.fields_len); var extra_index = @intCast(u32, extra.end); const extra_index_end = extra_index + (extra.data.fields_len * 2); while (extra_index < extra_index_end) : (extra_index += 2) { // +2 to skip over doc_string const str_index = sema.code.extra[extra_index]; - const kv = try mod.getErrorValue(sema.code.nullTerminatedString(str_index)); - const result = names.getOrPutAssumeCapacity(kv.key); + const name = sema.code.nullTerminatedString(str_index); + const name_ip = try mod.intern_pool.getOrPutString(gpa, name); + const result = names.getOrPutAssumeCapacity(name_ip); assert(!result.found_existing); // verified in AstGen } - // names must be sorted. - Module.ErrorSet.sortNames(&names); + const error_set_ty = try mod.errorSetFromUnsortedNames(names.keys()); + + const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ + .ty = Type.type, + .val = error_set_ty.toValue(), + }, name_strategy, "error", inst); + const new_decl = mod.declPtr(new_decl_index); + new_decl.owns_tv = true; + errdefer mod.abortAnonDecl(new_decl_index); - error_set.* = .{ - .owner_decl = new_decl_index, - .names = names, - }; - try new_decl.finalizeNewArena(&new_decl_arena); return sema.analyzeDeclVal(block, src, new_decl_index); } @@ -3407,7 +3395,7 @@ fn zirEnsureErrUnionPayloadVoid(sema: *Sema, block: *Block, inst: Zir.Inst.Index else operand_ty; if (err_union_ty.zigTypeTag(mod) != .ErrorUnion) return; - const payload_ty = err_union_ty.errorUnionPayload().zigTypeTag(mod); + const payload_ty = err_union_ty.errorUnionPayload(mod).zigTypeTag(mod); if (payload_ty != .Void and payload_ty != .NoReturn) { const msg = msg: { const msg = try sema.errMsg(block, src, "error union payload is ignored", .{}); @@ -3590,7 +3578,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro var anon_decl = try block.startAnonDecl(); defer anon_decl.deinit(); return sema.analyzeDeclRef(try anon_decl.finish( - try elem_ty.copy(anon_decl.arena()), + elem_ty, try store_val.copy(anon_decl.arena()), ptr_info.@"align", )); @@ -3722,7 +3710,6 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com const var_is_mut = switch (sema.typeOf(ptr).tag()) { .inferred_alloc_const => false, .inferred_alloc_mut => true, - else => unreachable, }; const target = sema.mod.getTarget(); @@ -3733,7 +3720,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com try sema.mod.declareDeclDependency(sema.owner_decl_index, decl_index); const decl = sema.mod.declPtr(decl_index); - const final_elem_ty = try decl.ty.copy(sema.arena); + const final_elem_ty = decl.ty; const final_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ .pointee_type = final_elem_ty, .mutable = true, @@ -3833,7 +3820,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com var anon_decl = try block.startAnonDecl(); defer anon_decl.deinit(); const new_decl_index = try anon_decl.finish( - try final_elem_ty.copy(anon_decl.arena()), + final_elem_ty, try store_val.copy(anon_decl.arena()), inferred_alloc.data.alignment, ); @@ -5042,7 +5029,7 @@ fn storeToInferredAllocComptime( var anon_decl = try block.startAnonDecl(); defer anon_decl.deinit(); iac.data.decl_index = try anon_decl.finish( - try operand_ty.copy(anon_decl.arena()), + operand_ty, try operand_val.copy(anon_decl.arena()), iac.data.alignment, ); @@ -5286,6 +5273,7 @@ fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError const tracy = trace(@src()); defer tracy.end(); + const mod = sema.mod; const inst_data = sema.code.instructions.items(.data)[inst].pl_node; const src = inst_data.src(); const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index); @@ -5335,7 +5323,7 @@ fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError try sema.analyzeBody(&loop_block, body); const loop_block_len = loop_block.instructions.items.len; - if (loop_block_len > 0 and sema.typeOf(Air.indexToRef(loop_block.instructions.items[loop_block_len - 1])).isNoReturn()) { + if (loop_block_len > 0 and sema.typeOf(Air.indexToRef(loop_block.instructions.items[loop_block_len - 1])).isNoReturn(mod)) { // If the loop ended with a noreturn terminator, then there is no way for it to loop, // so we can just use the block instead. try child_block.instructions.appendSlice(gpa, loop_block.instructions.items); @@ -5588,7 +5576,7 @@ fn analyzeBlockBody( // Blocks must terminate with noreturn instruction. assert(child_block.instructions.items.len != 0); - assert(sema.typeOf(Air.indexToRef(child_block.instructions.items[child_block.instructions.items.len - 1])).isNoReturn()); + assert(sema.typeOf(Air.indexToRef(child_block.instructions.items[child_block.instructions.items.len - 1])).isNoReturn(mod)); if (merges.results.items.len == 0) { // No need for a block instruction. We can put the new instructions @@ -5755,7 +5743,7 @@ fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError var anon_decl = try block.startAnonDecl(); defer anon_decl.deinit(); break :blk try anon_decl.finish( - try operand.ty.copy(anon_decl.arena()), + operand.ty, try operand.val.copy(anon_decl.arena()), 0, ); @@ -6434,7 +6422,7 @@ fn zirCall( }; const return_ty = sema.typeOf(call_inst); - if (modifier != .always_tail and return_ty.isNoReturn()) + if (modifier != .always_tail and return_ty.isNoReturn(mod)) return call_inst; // call to "fn(...) noreturn", don't pop // If any input is an error-type, we might need to pop any trace it generated. Otherwise, we only @@ -6957,17 +6945,11 @@ fn analyzeCall( // Create a fresh inferred error set type for inline/comptime calls. const fn_ret_ty = blk: { if (module_fn.hasInferredErrorSet(mod)) { - const node = try sema.gpa.create(Module.Fn.InferredErrorSetListNode); - node.data = .{ .func = module_fn }; - if (parent_func) |some| { - some.inferred_error_sets.prepend(node); - } - - const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, &node.data); - break :blk try Type.Tag.error_union.create(sema.arena, .{ - .error_set = error_set_ty, - .payload = bare_return_type, + const ies_index = try mod.intern_pool.createInferredErrorSet(gpa, .{ + .func = module_fn, }); + const error_set_ty = try mod.intern(.{ .inferred_error_set_type = ies_index }); + break :blk try mod.errorUnionType(error_set_ty.toType(), bare_return_type); } break :blk bare_return_type; }; @@ -7843,21 +7825,21 @@ fn resolveGenericInstantiationType( // `GenericCallAdapter.eql` as well as function body analysis. // Whether it is anytype is communicated by `isAnytypeParam`. const arg = child_sema.inst_map.get(inst).?; - const copied_arg_ty = try child_sema.typeOf(arg).copy(new_decl_arena_allocator); + const arg_ty = child_sema.typeOf(arg); - if (try sema.typeRequiresComptime(copied_arg_ty)) { + if (try sema.typeRequiresComptime(arg_ty)) { is_comptime = true; } if (is_comptime) { const arg_val = (child_sema.resolveMaybeUndefValAllowVariables(arg) catch unreachable).?; child_sema.comptime_args[arg_i] = .{ - .ty = copied_arg_ty, + .ty = arg_ty, .val = try arg_val.copy(new_decl_arena_allocator), }; } else { child_sema.comptime_args[arg_i] = .{ - .ty = copied_arg_ty, + .ty = arg_ty, .val = Value.generic_poison, }; } @@ -7868,7 +7850,7 @@ fn resolveGenericInstantiationType( try wip_captures.finalize(); // Populate the Decl ty/val with the function and its type. - new_decl.ty = try child_sema.typeOf(new_func_inst).copy(new_decl_arena_allocator); + new_decl.ty = child_sema.typeOf(new_func_inst); // If the call evaluated to a return type that requires comptime, never mind // our generic instantiation. Instead we need to perform a comptime call. const new_fn_info = mod.typeToFunc(new_decl.ty).?; @@ -8068,7 +8050,7 @@ fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr }); } try sema.validateErrorUnionPayloadType(block, payload, rhs_src); - const err_union_ty = try Type.errorUnion(sema.arena, error_set, payload, sema.mod); + const err_union_ty = try mod.errorUnionType(error_set, payload); return sema.addType(err_union_ty); } @@ -8087,16 +8069,13 @@ fn validateErrorUnionPayloadType(sema: *Sema, block: *Block, payload_ty: Type, p fn zirErrorValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { _ = block; - const tracy = trace(@src()); - defer tracy.end(); - + const mod = sema.mod; const inst_data = sema.code.instructions.items(.data)[inst].str_tok; - - // Create an anonymous error set type with only this error value, and return the value. - const kv = try sema.mod.getErrorValue(inst_data.get(sema.code)); - const result_type = try Type.Tag.error_set_single.create(sema.arena, kv.key); + const name = inst_data.get(sema.code); + // Create an error set type with only this error value, and return the value. + const kv = try sema.mod.getErrorValue(name); return sema.addConstant( - result_type, + try mod.singleErrorSetType(kv.key), try Value.Tag.@"error".create(sema.arena, .{ .name = kv.key, }), @@ -8139,11 +8118,14 @@ fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat const op_ty = sema.typeOf(uncasted_operand); try sema.resolveInferredErrorSetTy(block, src, op_ty); - if (!op_ty.isAnyError()) { - const names = op_ty.errorSetNames(); + if (!op_ty.isAnyError(mod)) { + const names = op_ty.errorSetNames(mod); switch (names.len) { 0 => return sema.addConstant(Type.err_int, try mod.intValue(Type.err_int, 0)), - 1 => return sema.addIntUnsigned(Type.err_int, sema.mod.global_error_set.get(names[0]).?), + 1 => { + const name = mod.intern_pool.stringToSlice(names[0]); + return sema.addIntUnsigned(Type.err_int, mod.global_error_set.get(name).?); + }, else => {}, } } @@ -8224,22 +8206,22 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr return Air.Inst.Ref.anyerror_type; } - if (lhs_ty.castTag(.error_set_inferred)) |payload| { - try sema.resolveInferredErrorSet(block, src, payload.data); + if (mod.typeToInferredErrorSetIndex(lhs_ty).unwrap()) |ies_index| { + try sema.resolveInferredErrorSet(block, src, ies_index); // isAnyError might have changed from a false negative to a true positive after resolution. - if (lhs_ty.isAnyError()) { + if (lhs_ty.isAnyError(mod)) { return Air.Inst.Ref.anyerror_type; } } - if (rhs_ty.castTag(.error_set_inferred)) |payload| { - try sema.resolveInferredErrorSet(block, src, payload.data); + if (mod.typeToInferredErrorSetIndex(rhs_ty).unwrap()) |ies_index| { + try sema.resolveInferredErrorSet(block, src, ies_index); // isAnyError might have changed from a false negative to a true positive after resolution. - if (rhs_ty.isAnyError()) { + if (rhs_ty.isAnyError(mod)) { return Air.Inst.Ref.anyerror_type; } } - const err_set_ty = try lhs_ty.errorSetMerge(sema.arena, rhs_ty); + const err_set_ty = try sema.errorSetMerge(lhs_ty, rhs_ty); return sema.addType(err_set_ty); } @@ -8484,7 +8466,7 @@ fn zirOptionalPayload( if (true) break :t operand_ty; const ptr_info = operand_ty.ptrInfo(mod); break :t try Type.ptr(sema.arena, sema.mod, .{ - .pointee_type = try ptr_info.pointee_type.copy(sema.arena), + .pointee_type = ptr_info.pointee_type, .@"align" = ptr_info.@"align", .@"addrspace" = ptr_info.@"addrspace", .mutable = ptr_info.mutable, @@ -8547,7 +8529,7 @@ fn analyzeErrUnionPayload( safety_check: bool, ) CompileError!Air.Inst.Ref { const mod = sema.mod; - const payload_ty = err_union_ty.errorUnionPayload(); + const payload_ty = err_union_ty.errorUnionPayload(mod); if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| { if (val.getError()) |name| { return sema.fail(block, src, "caught unexpected error '{s}'", .{name}); @@ -8560,7 +8542,7 @@ fn analyzeErrUnionPayload( // If the error set has no fields then no safety check is needed. if (safety_check and block.wantSafety() and - !err_union_ty.errorUnionSet().errorSetIsEmpty(mod)) + !err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { try sema.panicUnwrapError(block, operand, .unwrap_errunion_err, .is_non_err); } @@ -8603,7 +8585,7 @@ fn analyzeErrUnionPayloadPtr( } const err_union_ty = operand_ty.childType(mod); - const payload_ty = err_union_ty.errorUnionPayload(); + const payload_ty = err_union_ty.errorUnionPayload(mod); const operand_pointer_ty = try Type.ptr(sema.arena, sema.mod, .{ .pointee_type = payload_ty, .mutable = !operand_ty.isConstPtr(mod), @@ -8646,7 +8628,7 @@ fn analyzeErrUnionPayloadPtr( // If the error set has no fields then no safety check is needed. if (safety_check and block.wantSafety() and - !err_union_ty.errorUnionSet().errorSetIsEmpty(mod)) + !err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { try sema.panicUnwrapError(block, operand, .unwrap_errunion_err_ptr, .is_non_err_ptr); } @@ -8678,7 +8660,7 @@ fn analyzeErrUnionCode(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air }); } - const result_ty = operand_ty.errorUnionSet(); + const result_ty = operand_ty.errorUnionSet(mod); if (try sema.resolveDefinedValue(block, src, operand)) |val| { assert(val.getError() != null); @@ -8707,7 +8689,7 @@ fn zirErrUnionCodePtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE }); } - const result_ty = operand_ty.childType(mod).errorUnionSet(); + const result_ty = operand_ty.childType(mod).errorUnionSet(mod); if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| { if (try sema.pointerDeref(block, src, pointer_val, operand_ty)) |val| { @@ -8755,7 +8737,7 @@ fn zirFunc( extra_index += ret_ty_body.len; const ret_ty_val = try sema.resolveGenericBody(block, ret_ty_src, ret_ty_body, inst, Type.type, "return type must be comptime-known"); - break :blk try ret_ty_val.toType().copy(sema.arena); + break :blk ret_ty_val.toType(); }, }; @@ -8927,6 +8909,7 @@ fn funcCommon( is_noinline: bool, ) CompileError!Air.Inst.Ref { const mod = sema.mod; + const gpa = sema.gpa; const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset }; const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = src_node_offset }; const func_src = LazySrcLoc.nodeOffset(src_node_offset); @@ -8955,16 +8938,12 @@ fn funcCommon( break :new_func new_func; } destroy_fn_on_error = true; - const new_func = try sema.gpa.create(Module.Fn); + const new_func = try gpa.create(Module.Fn); // Set this here so that the inferred return type can be printed correctly if it appears in an error. new_func.owner_decl = sema.owner_decl_index; break :new_func new_func; }; - errdefer if (destroy_fn_on_error) sema.gpa.destroy(new_func); - - var maybe_inferred_error_set_node: ?*Module.Fn.InferredErrorSetListNode = null; - errdefer if (maybe_inferred_error_set_node) |node| sema.gpa.destroy(node); - // Note: no need to errdefer since this will still be in its default state at the end of the function. + errdefer if (destroy_fn_on_error) gpa.destroy(new_func); const target = sema.mod.getTarget(); const fn_ty: Type = fn_ty: { @@ -9027,15 +9006,11 @@ fn funcCommon( bare_return_type else blk: { try sema.validateErrorUnionPayloadType(block, bare_return_type, ret_ty_src); - const node = try sema.gpa.create(Module.Fn.InferredErrorSetListNode); - node.data = .{ .func = new_func }; - maybe_inferred_error_set_node = node; - - const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, &node.data); - break :blk try Type.Tag.error_union.create(sema.arena, .{ - .error_set = error_set_ty, - .payload = bare_return_type, + const ies_index = try mod.intern_pool.createInferredErrorSet(gpa, .{ + .func = new_func, }); + const error_set_ty = try mod.intern(.{ .inferred_error_set_type = ies_index }); + break :blk try mod.errorUnionType(error_set_ty.toType(), bare_return_type); }; if (!return_type.isValidReturnType(mod)) { @@ -9044,7 +9019,7 @@ fn funcCommon( const msg = try sema.errMsg(block, ret_ty_src, "{s}return type '{}' not allowed", .{ opaque_str, return_type.fmt(sema.mod), }); - errdefer msg.destroy(sema.gpa); + errdefer msg.destroy(gpa); try sema.addDeclaredHereNote(msg, return_type); break :msg msg; @@ -9058,7 +9033,7 @@ fn funcCommon( const msg = try sema.errMsg(block, ret_ty_src, "return type '{}' not allowed in function with calling convention '{s}'", .{ return_type.fmt(sema.mod), @tagName(cc_resolved), }); - errdefer msg.destroy(sema.gpa); + errdefer msg.destroy(gpa); const src_decl = sema.mod.declPtr(block.src_decl); try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src.toSrcLoc(src_decl, mod), return_type, .ret_ty); @@ -9182,8 +9157,8 @@ fn funcCommon( sema.owner_decl.@"addrspace" = address_space orelse .generic; if (is_extern) { - const new_extern_fn = try sema.gpa.create(Module.ExternFn); - errdefer sema.gpa.destroy(new_extern_fn); + const new_extern_fn = try gpa.create(Module.ExternFn); + errdefer gpa.destroy(new_extern_fn); new_extern_fn.* = Module.ExternFn{ .owner_decl = sema.owner_decl_index, @@ -9232,10 +9207,6 @@ fn funcCommon( .branch_quota = default_branch_quota, .is_noinline = is_noinline, }; - if (maybe_inferred_error_set_node) |node| { - new_func.inferred_error_sets.prepend(node); - } - maybe_inferred_error_set_node = null; fn_payload.* = .{ .base = .{ .tag = .function }, .data = new_func, @@ -10139,6 +10110,7 @@ fn zirSwitchCapture( defer tracy.end(); const mod = sema.mod; + const gpa = sema.gpa; const zir_datas = sema.code.instructions.items(.data); const capture_info = zir_datas[inst].switch_capture; const switch_info = zir_datas[capture_info.switch_inst].pl_node; @@ -10248,7 +10220,7 @@ fn zirSwitchCapture( const capture_src = raw_capture_src.resolve(mod, sema.mod.declPtr(block.src_decl), switch_info.src_node, .first); const msg = try sema.errMsg(block, capture_src, "capture group with incompatible types", .{}); - errdefer msg.destroy(sema.gpa); + errdefer msg.destroy(gpa); const raw_first_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = capture_info.prong_index, .item = 0 } }; const first_item_src = raw_first_item_src.resolve(mod, sema.mod.declPtr(block.src_decl), switch_info.src_node, .first); @@ -10294,20 +10266,16 @@ fn zirSwitchCapture( }, .ErrorSet => { if (is_multi) { - var names: Module.ErrorSet.NameMap = .{}; + var names: Module.Fn.InferredErrorSet.NameMap = .{}; try names.ensureUnusedCapacity(sema.arena, items.len); for (items) |item| { const item_ref = try sema.resolveInst(item); // Previous switch validation ensured this will succeed const item_val = sema.resolveConstValue(block, .unneeded, item_ref, "") catch unreachable; - names.putAssumeCapacityNoClobber( - item_val.getError().?, - {}, - ); + const name_ip = try mod.intern_pool.getOrPutString(gpa, item_val.getError().?); + names.putAssumeCapacityNoClobber(name_ip, {}); } - // names must be sorted - Module.ErrorSet.sortNames(&names); - const else_error_ty = try Type.Tag.error_set_merged.create(sema.arena, names); + const else_error_ty = try mod.errorSetFromUnsortedNames(names.keys()); return sema.bitCast(block, else_error_ty, operand, operand_src, null); } else { @@ -10315,7 +10283,7 @@ fn zirSwitchCapture( // Previous switch validation ensured this will succeed const item_val = sema.resolveConstValue(block, .unneeded, item_ref, "") catch unreachable; - const item_ty = try Type.Tag.error_set_single.create(sema.arena, item_val.getError().?); + const item_ty = try mod.singleErrorSetType(item_val.getError().?); return sema.bitCast(block, item_ty, operand, operand_src, null); } }, @@ -10678,7 +10646,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError try sema.resolveInferredErrorSetTy(block, src, operand_ty); - if (operand_ty.isAnyError()) { + if (operand_ty.isAnyError(mod)) { if (special_prong != .@"else") { return sema.fail( block, @@ -10692,7 +10660,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError var maybe_msg: ?*Module.ErrorMsg = null; errdefer if (maybe_msg) |msg| msg.destroy(sema.gpa); - for (operand_ty.errorSetNames()) |error_name| { + for (operand_ty.errorSetNames(mod)) |error_name_ip| { + const error_name = mod.intern_pool.stringToSlice(error_name_ip); if (!seen_errors.contains(error_name) and special_prong != .@"else") { const msg = maybe_msg orelse blk: { maybe_msg = try sema.errMsg( @@ -10720,7 +10689,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError return sema.failWithOwnedErrorMsg(msg); } - if (special_prong == .@"else" and seen_errors.count() == operand_ty.errorSetNames().len) { + if (special_prong == .@"else" and seen_errors.count() == operand_ty.errorSetNames(mod).len) { // In order to enable common patterns for generic code allow simple else bodies // else => unreachable, // else => return, @@ -10757,18 +10726,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError ); } - const error_names = operand_ty.errorSetNames(); - var names: Module.ErrorSet.NameMap = .{}; + const error_names = operand_ty.errorSetNames(mod); + var names: Module.Fn.InferredErrorSet.NameMap = .{}; try names.ensureUnusedCapacity(sema.arena, error_names.len); - for (error_names) |error_name| { + for (error_names) |error_name_ip| { + const error_name = mod.intern_pool.stringToSlice(error_name_ip); if (seen_errors.contains(error_name)) continue; - names.putAssumeCapacityNoClobber(error_name, {}); + names.putAssumeCapacityNoClobber(error_name_ip, {}); } - - // names must be sorted - Module.ErrorSet.sortNames(&names); - else_error_ty = try Type.Tag.error_set_merged.create(sema.arena, names); + // No need to keep the hash map metadata correct; here we + // extract the (sorted) keys only. + else_error_ty = try mod.errorSetFromUnsortedNames(names.keys()); } }, .Int, .ComptimeInt => { @@ -11513,12 +11482,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError } }, .ErrorSet => { - if (operand_ty.isAnyError()) { + if (operand_ty.isAnyError(mod)) { return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{ operand_ty.fmt(mod), }); } - for (operand_ty.errorSetNames()) |error_name| { + for (operand_ty.errorSetNames(mod)) |error_name_ip| { + const error_name = mod.intern_pool.stringToSlice(error_name_ip); if (seen_errors.contains(error_name)) continue; cases_len += 1; @@ -11931,7 +11901,8 @@ fn validateSwitchNoRange( } fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, operand: Air.Inst.Ref) !bool { - if (!sema.mod.backendSupportsFeature(.panic_unwrap_error)) return false; + const mod = sema.mod; + if (!mod.backendSupportsFeature(.panic_unwrap_error)) return false; const tags = sema.code.instructions.items(.tag); for (body) |inst| { @@ -11967,7 +11938,7 @@ fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, op .as_node => try sema.zirAsNode(block, inst), .field_val => try sema.zirFieldVal(block, inst), .@"unreachable" => { - if (!sema.mod.comp.formatted_panics) { + if (!mod.comp.formatted_panics) { try sema.safetyPanic(block, .unwrap_error); return true; } @@ -11990,7 +11961,7 @@ fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, op }, else => unreachable, }; - if (sema.typeOf(air_inst).isNoReturn()) + if (sema.typeOf(air_inst).isNoReturn(mod)) return true; sema.inst_map.putAssumeCapacity(inst, air_inst); } @@ -12194,13 +12165,14 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A } fn zirRetErrValueCode(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { + const mod = sema.mod; const inst_data = sema.code.instructions.items(.data)[inst].str_tok; const err_name = inst_data.get(sema.code); // Return the error code from the function. - const kv = try sema.mod.getErrorValue(err_name); + const kv = try mod.getErrorValue(err_name); const result_inst = try sema.addConstant( - try Type.Tag.error_set_single.create(sema.arena, kv.key), + try mod.singleErrorSetType(kv.key), try Value.Tag.@"error".create(sema.arena, .{ .name = kv.key }), ); return result_inst; @@ -15737,7 +15709,7 @@ fn zirClosureCapture( Value.@"unreachable"; try block.wip_capture_scope.captures.putNoClobber(sema.gpa, inst, .{ - .ty = try sema.typeOf(operand).copy(sema.perm_arena), + .ty = sema.typeOf(operand), .val = try val.copy(sema.perm_arena), }); } @@ -16223,10 +16195,10 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai try mod.declareDeclDependency(sema.owner_decl_index, set_field_ty_decl_index); try sema.ensureDeclAnalyzed(set_field_ty_decl_index); const set_field_ty_decl = mod.declPtr(set_field_ty_decl_index); - break :t try set_field_ty_decl.val.toType().copy(fields_anon_decl.arena()); + break :t set_field_ty_decl.val.toType(); }; - try sema.queueFullTypeResolution(try error_field_ty.copy(sema.arena)); + try sema.queueFullTypeResolution(error_field_ty); // If the error set is inferred it must be resolved at this point try sema.resolveInferredErrorSetTy(block, src, ty); @@ -16234,11 +16206,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // Build our list of Error values // Optional value is only null if anyerror // Value can be zero-length slice otherwise - const error_field_vals: ?[]Value = if (ty.isAnyError()) null else blk: { - const names = ty.errorSetNames(); + const error_field_vals: ?[]Value = if (ty.isAnyError(mod)) null else blk: { + const names = ty.errorSetNames(mod); const vals = try fields_anon_decl.arena().alloc(Value, names.len); - for (vals, 0..) |*field_val, i| { - const name = names[i]; + for (vals, names) |*field_val, name_ip| { + const name = mod.intern_pool.stringToSlice(name_ip); const name_val = v: { var anon_decl = try block.startAnonDecl(); defer anon_decl.deinit(); @@ -16301,9 +16273,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .ErrorUnion => { const field_values = try sema.arena.alloc(Value, 2); // error_set: type, - field_values[0] = try Value.Tag.ty.create(sema.arena, ty.errorUnionSet()); + field_values[0] = try Value.Tag.ty.create(sema.arena, ty.errorUnionSet(mod)); // payload: type, - field_values[1] = try Value.Tag.ty.create(sema.arena, ty.errorUnionPayload()); + field_values[1] = try Value.Tag.ty.create(sema.arena, ty.errorUnionPayload(mod)); return sema.addConstant( type_info_ty, @@ -16332,7 +16304,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai try mod.declareDeclDependency(sema.owner_decl_index, enum_field_ty_decl_index); try sema.ensureDeclAnalyzed(enum_field_ty_decl_index); const enum_field_ty_decl = mod.declPtr(enum_field_ty_decl_index); - break :t try enum_field_ty_decl.val.toType().copy(fields_anon_decl.arena()); + break :t enum_field_ty_decl.val.toType(); }; const enum_field_vals = try fields_anon_decl.arena().alloc(Value, enum_type.names.len); @@ -16416,7 +16388,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai try mod.declareDeclDependency(sema.owner_decl_index, union_field_ty_decl_index); try sema.ensureDeclAnalyzed(union_field_ty_decl_index); const union_field_ty_decl = mod.declPtr(union_field_ty_decl_index); - break :t try union_field_ty_decl.val.toType().copy(fields_anon_decl.arena()); + break :t union_field_ty_decl.val.toType(); }; const union_ty = try sema.resolveTypeFields(ty); @@ -16523,7 +16495,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai try mod.declareDeclDependency(sema.owner_decl_index, struct_field_ty_decl_index); try sema.ensureDeclAnalyzed(struct_field_ty_decl_index); const struct_field_ty_decl = mod.declPtr(struct_field_ty_decl_index); - break :t try struct_field_ty_decl.val.toType().copy(fields_anon_decl.arena()); + break :t struct_field_ty_decl.val.toType(); }; const struct_ty = try sema.resolveTypeFields(ty); try sema.resolveTypeLayout(ty); // Getting alignment requires type layout @@ -16733,9 +16705,9 @@ fn typeInfoDecls( try mod.declareDeclDependency(sema.owner_decl_index, declaration_ty_decl_index); try sema.ensureDeclAnalyzed(declaration_ty_decl_index); const declaration_ty_decl = mod.declPtr(declaration_ty_decl_index); - break :t try declaration_ty_decl.val.toType().copy(decls_anon_decl.arena()); + break :t declaration_ty_decl.val.toType(); }; - try sema.queueFullTypeResolution(try declaration_ty.copy(sema.arena)); + try sema.queueFullTypeResolution(declaration_ty); var decl_vals = std.ArrayList(Value).init(sema.gpa); defer decl_vals.deinit(); @@ -17018,12 +16990,12 @@ fn zirBoolBr( _ = try lhs_block.addBr(block_inst, lhs_result); const rhs_result = try sema.resolveBody(rhs_block, body, inst); - if (!sema.typeOf(rhs_result).isNoReturn()) { + if (!sema.typeOf(rhs_result).isNoReturn(mod)) { _ = try rhs_block.addBr(block_inst, rhs_result); } const result = sema.finishCondBr(parent_block, &child_block, &then_block, &else_block, lhs, block_inst); - if (!sema.typeOf(rhs_result).isNoReturn()) { + if (!sema.typeOf(rhs_result).isNoReturn(mod)) { if (try sema.resolveDefinedValue(rhs_block, sema.src, rhs_result)) |rhs_val| { if (is_bool_or and rhs_val.toBool(mod)) { return Air.Inst.Ref.bool_true; @@ -17211,7 +17183,7 @@ fn zirCondbr( const err_operand = try sema.resolveInst(err_inst_data.operand); const operand_ty = sema.typeOf(err_operand); assert(operand_ty.zigTypeTag(mod) == .ErrorUnion); - const result_ty = operand_ty.errorUnionSet(); + const result_ty = operand_ty.errorUnionSet(mod); break :blk try sub_block.addTyOp(.unwrap_errunion_err, result_ty, err_operand); }; @@ -17318,7 +17290,7 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr const operand_ty = sema.typeOf(operand); const ptr_info = operand_ty.ptrInfo(mod); const res_ty = try Type.ptr(sema.arena, sema.mod, .{ - .pointee_type = err_union_ty.errorUnionPayload(), + .pointee_type = err_union_ty.errorUnionPayload(mod), .@"addrspace" = ptr_info.@"addrspace", .mutable = ptr_info.mutable, .@"allowzero" = ptr_info.@"allowzero", @@ -17414,14 +17386,15 @@ fn zirRetErrValue( block: *Block, inst: Zir.Inst.Index, ) CompileError!Zir.Inst.Index { + const mod = sema.mod; const inst_data = sema.code.instructions.items(.data)[inst].str_tok; const err_name = inst_data.get(sema.code); const src = inst_data.src(); // Return the error code from the function. - const kv = try sema.mod.getErrorValue(err_name); + const kv = try mod.getErrorValue(err_name); const result_inst = try sema.addConstant( - try Type.Tag.error_set_single.create(sema.arena, kv.key), + try mod.singleErrorSetType(err_name), try Value.Tag.@"error".create(sema.arena, .{ .name = kv.key }), ); return sema.analyzeRet(block, result_inst, src); @@ -17632,17 +17605,15 @@ fn zirRestoreErrRetIndex(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void { const mod = sema.mod; + const gpa = sema.gpa; + const ip = &mod.intern_pool; assert(sema.fn_ret_ty.zigTypeTag(mod) == .ErrorUnion); - if (sema.fn_ret_ty.errorUnionSet().castTag(.error_set_inferred)) |payload| { + if (mod.typeToInferredErrorSet(sema.fn_ret_ty.errorUnionSet(mod))) |ies| { const op_ty = sema.typeOf(uncasted_operand); switch (op_ty.zigTypeTag(mod)) { - .ErrorSet => { - try payload.data.addErrorSet(sema.gpa, op_ty); - }, - .ErrorUnion => { - try payload.data.addErrorSet(sema.gpa, op_ty.errorUnionSet()); - }, + .ErrorSet => try ies.addErrorSet(op_ty, ip, gpa), + .ErrorUnion => try ies.addErrorSet(op_ty.errorUnionSet(mod), ip, gpa), else => {}, } } @@ -18521,7 +18492,7 @@ fn addConstantMaybeRef( var anon_decl = try block.startAnonDecl(); defer anon_decl.deinit(); const decl = try anon_decl.finish( - try ty.copy(anon_decl.arena()), + ty, try val.copy(anon_decl.arena()), 0, // default alignment ); @@ -18595,7 +18566,7 @@ fn fieldType( continue; }, .ErrorUnion => { - cur_ty = cur_ty.errorUnionPayload(); + cur_ty = cur_ty.errorUnionPayload(mod); continue; }, else => {}, @@ -18641,7 +18612,7 @@ fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const inst_data = sema.code.instructions.items(.data)[inst].un_node; const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; const ty = try sema.resolveType(block, operand_src, inst_data.operand); - if (ty.isNoReturn()) { + if (ty.isNoReturn(mod)) { return sema.fail(block, operand_src, "no align available for type '{}'", .{ty.fmt(sema.mod)}); } const val = try ty.lazyAbiAlignment(mod, sema.arena); @@ -18929,7 +18900,7 @@ fn zirReify( const sentinel_ptr_val = sentinel_val.castTag(.opt_payload).?.data; const ptr_ty = try Type.ptr(sema.arena, mod, .{ .@"addrspace" = .generic, - .pointee_type = try elem_ty.copy(sema.arena), + .pointee_type = elem_ty, }); const sent_val = (try sema.pointerDeref(block, src, sentinel_ptr_val, ptr_ty)).?; break :s sent_val.toIntern(); @@ -18993,7 +18964,7 @@ fn zirReify( const sentinel_val = struct_val[2]; const len = len_val.toUnsignedInt(mod); - const child_ty = try child_val.toType().copy(sema.arena); + const child_ty = child_val.toType(); const sentinel = if (sentinel_val.castTag(.opt_payload)) |p| blk: { const ptr_ty = try Type.ptr(sema.arena, mod, .{ .@"addrspace" = .generic, @@ -19011,7 +18982,7 @@ fn zirReify( // child: type, const child_val = struct_val[0]; - const child_ty = try child_val.toType().copy(sema.arena); + const child_ty = child_val.toType(); const ty = try Type.optional(sema.arena, child_ty, mod); return sema.addType(ty); @@ -19024,17 +18995,14 @@ fn zirReify( // payload: type, const payload_val = struct_val[1]; - const error_set_ty = try error_set_val.toType().copy(sema.arena); - const payload_ty = try payload_val.toType().copy(sema.arena); + const error_set_ty = error_set_val.toType(); + const payload_ty = payload_val.toType(); if (error_set_ty.zigTypeTag(mod) != .ErrorSet) { return sema.fail(block, src, "Type.ErrorUnion.error_set must be an error set type", .{}); } - const ty = try Type.Tag.error_union.create(sema.arena, .{ - .error_set = error_set_ty, - .payload = payload_ty, - }); + const ty = try mod.errorUnionType(error_set_ty, payload_ty); return sema.addType(ty); }, .ErrorSet => { @@ -19043,27 +19011,23 @@ fn zirReify( const slice_val = payload_val.castTag(.slice).?.data; const len = try sema.usizeCast(block, src, slice_val.len.toUnsignedInt(mod)); - var names: Module.ErrorSet.NameMap = .{}; + var names: Module.Fn.InferredErrorSet.NameMap = .{}; try names.ensureUnusedCapacity(sema.arena, len); - var i: usize = 0; - while (i < len) : (i += 1) { + for (0..len) |i| { const elem_val = try slice_val.ptr.elemValue(mod, i); const struct_val = elem_val.castTag(.aggregate).?.data; // TODO use reflection instead of magic numbers here // error_set: type, const name_val = struct_val[0]; const name_str = try name_val.toAllocatedBytes(Type.const_slice_u8, sema.arena, mod); - - const kv = try mod.getErrorValue(name_str); - const gop = names.getOrPutAssumeCapacity(kv.key); + const name_ip = try mod.intern_pool.getOrPutString(gpa, name_str); + const gop = names.getOrPutAssumeCapacity(name_ip); if (gop.found_existing) { return sema.fail(block, src, "duplicate error '{s}'", .{name_str}); } } - // names must be sorted - Module.ErrorSet.sortNames(&names); - const ty = try Type.Tag.error_set_merged.create(sema.arena, names); + const ty = try mod.errorSetFromUnsortedNames(names.keys()); return sema.addType(ty); }, .Struct => { @@ -19378,7 +19342,7 @@ fn zirReify( return sema.fail(block, src, "duplicate union field {s}", .{field_name}); } - const field_ty = try type_val.toType().copy(new_decl_arena_allocator); + const field_ty = type_val.toType(); gop.value_ptr.* = .{ .ty = field_ty, .abi_align = @intCast(u32, (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?), @@ -19673,7 +19637,7 @@ fn reifyStruct( return sema.fail(block, src, "comptime field without default initialization value", .{}); } - const field_ty = try type_val.toType().copy(new_decl_arena_allocator); + const field_ty = type_val.toType(); gop.value_ptr.* = .{ .ty = field_ty, .abi_align = abi_align, @@ -19751,7 +19715,7 @@ fn reifyStruct( if (backing_int_val.optionalValue(mod)) |payload| { const backing_int_ty = payload.toType(); try sema.checkBackingIntType(block, src, backing_int_ty, fields_bit_sum); - struct_obj.backing_int_ty = try backing_int_ty.copy(new_decl_arena_allocator); + struct_obj.backing_int_ty = backing_int_ty; } else { struct_obj.backing_int_ty = try mod.intType(.unsigned, @intCast(u16, fields_bit_sum)); } @@ -20035,6 +19999,8 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { + const mod = sema.mod; + const ip = &mod.intern_pool; const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; const src = LazySrcLoc.nodeOffset(extra.node); const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; @@ -20050,22 +20016,27 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat if (disjoint: { // Try avoiding resolving inferred error sets if we can - if (!dest_ty.isAnyError() and dest_ty.errorSetNames().len == 0) break :disjoint true; - if (!operand_ty.isAnyError() and operand_ty.errorSetNames().len == 0) break :disjoint true; - if (dest_ty.isAnyError()) break :disjoint false; - if (operand_ty.isAnyError()) break :disjoint false; - for (dest_ty.errorSetNames()) |dest_err_name| - if (operand_ty.errorSetHasField(dest_err_name)) + if (!dest_ty.isAnyError(mod) and dest_ty.errorSetNames(mod).len == 0) break :disjoint true; + if (!operand_ty.isAnyError(mod) and operand_ty.errorSetNames(mod).len == 0) break :disjoint true; + if (dest_ty.isAnyError(mod)) break :disjoint false; + if (operand_ty.isAnyError(mod)) break :disjoint false; + for (dest_ty.errorSetNames(mod)) |dest_err_name| { + if (Type.errorSetHasFieldIp(ip, operand_ty.toIntern(), dest_err_name)) break :disjoint false; + } - if (dest_ty.tag() != .error_set_inferred and operand_ty.tag() != .error_set_inferred) + if (!ip.isInferredErrorSetType(dest_ty.ip_index) and + !ip.isInferredErrorSetType(operand_ty.ip_index)) + { break :disjoint true; + } try sema.resolveInferredErrorSetTy(block, dest_ty_src, dest_ty); try sema.resolveInferredErrorSetTy(block, operand_src, operand_ty); - for (dest_ty.errorSetNames()) |dest_err_name| - if (operand_ty.errorSetHasField(dest_err_name)) + for (dest_ty.errorSetNames(mod)) |dest_err_name| { + if (Type.errorSetHasFieldIp(ip, operand_ty.toIntern(), dest_err_name)) break :disjoint false; + } break :disjoint true; }) { @@ -20085,9 +20056,9 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat } if (maybe_operand_val) |val| { - if (!dest_ty.isAnyError()) { + if (!dest_ty.isAnyError(mod)) { const error_name = val.castTag(.@"error").?.data.name; - if (!dest_ty.errorSetHasField(error_name)) { + if (!dest_ty.errorSetHasField(error_name, mod)) { const msg = msg: { const msg = try sema.errMsg( block, @@ -20107,7 +20078,7 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat } try sema.requireRuntimeBlock(block, src, operand_src); - if (block.wantSafety() and !dest_ty.isAnyError() and sema.mod.backendSupportsFeature(.error_set_has_value)) { + if (block.wantSafety() and !dest_ty.isAnyError(mod) and sema.mod.backendSupportsFeature(.error_set_has_value)) { const err_int_inst = try block.addBitCast(Type.err_int, operand); const ok = try block.addTyOp(.error_set_has_value, dest_ty, err_int_inst); try sema.addSafetyCheck(block, ok, .invalid_error_code); @@ -22862,7 +22833,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A extra_index += body.len; const val = try sema.resolveGenericBody(block, ret_src, body, inst, Type.type, "return type must be comptime-known"); - const ty = try val.toType().copy(sema.arena); + const ty = val.toType(); break :blk ty; } else if (extra.data.bits.has_ret_ty_ref) blk: { const ret_ty_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); @@ -22873,7 +22844,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A }, else => |e| return e, }; - const ty = try ret_ty_tv.val.toType().copy(sema.arena); + const ty = ret_ty_tv.val.toType(); break :blk ty; } else Type.void; @@ -23360,7 +23331,7 @@ fn validateRunTimeType( }, .Array, .Vector => ty = ty.childType(mod), - .ErrorUnion => ty = ty.errorUnionPayload(), + .ErrorUnion => ty = ty.errorUnionPayload(mod), .Struct, .Union => { const resolved_ty = try sema.resolveTypeFields(ty); @@ -23452,7 +23423,7 @@ fn explainWhyTypeIsComptimeInner( try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.optionalChild(mod), type_set); }, .ErrorUnion => { - try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.errorUnionPayload(), type_set); + try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.errorUnionPayload(mod), type_set); }, .Struct => { @@ -24065,7 +24036,9 @@ fn fieldVal( // in `fieldPtr`. This function takes a value and returns a value. const mod = sema.mod; + const gpa = sema.gpa; const arena = sema.arena; + const ip = &mod.intern_pool; const object_src = src; // TODO better source location const object_ty = sema.typeOf(object); @@ -24147,27 +24120,33 @@ fn fieldVal( switch (try child_type.zigTypeTagOrPoison(mod)) { .ErrorSet => { - const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: { - if (payload.data.names.getEntry(field_name)) |entry| { - break :blk entry.key_ptr.*; - } - const msg = msg: { - const msg = try sema.errMsg(block, src, "no error named '{s}' in '{}'", .{ - field_name, child_type.fmt(mod), - }); - errdefer msg.destroy(sema.gpa); - try sema.addDeclaredHereNote(msg, child_type); - break :msg msg; - }; - return sema.failWithOwnedErrorMsg(msg); - } else (try mod.getErrorValue(field_name)).key; + const name = try ip.getOrPutString(gpa, field_name); + switch (ip.indexToKey(child_type.ip_index)) { + .error_set_type => |error_set_type| blk: { + if (error_set_type.nameIndex(ip, name) != null) break :blk; + const msg = msg: { + const msg = try sema.errMsg(block, src, "no error named '{s}' in '{}'", .{ + field_name, child_type.fmt(mod), + }); + errdefer msg.destroy(sema.gpa); + try sema.addDeclaredHereNote(msg, child_type); + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(msg); + }, + .inferred_error_set_type => { + return sema.fail(block, src, "TODO handle inferred error sets here", .{}); + }, + .simple_type => |t| assert(t == .anyerror), + else => unreachable, + } return sema.addConstant( - if (!child_type.isAnyError()) - try child_type.copy(arena) + if (!child_type.isAnyError(mod)) + child_type else - try Type.Tag.error_set_single.create(arena, name), - try Value.Tag.@"error".create(arena, .{ .name = name }), + try mod.singleErrorSetTypeNts(name), + try Value.Tag.@"error".create(arena, .{ .name = ip.stringToSlice(name) }), ); }, .Union => { @@ -24252,6 +24231,8 @@ fn fieldPtr( // in `fieldVal`. This function takes a pointer and returns a pointer. const mod = sema.mod; + const gpa = sema.gpa; + const ip = &mod.intern_pool; const object_ptr_src = src; // TODO better source location const object_ptr_ty = sema.typeOf(object_ptr); const object_ty = switch (object_ptr_ty.zigTypeTag(mod)) { @@ -24362,24 +24343,33 @@ fn fieldPtr( switch (child_type.zigTypeTag(mod)) { .ErrorSet => { - // TODO resolve inferred error sets - const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: { - if (payload.data.names.getEntry(field_name)) |entry| { - break :blk entry.key_ptr.*; - } - return sema.fail(block, src, "no error named '{s}' in '{}'", .{ - field_name, child_type.fmt(mod), - }); - } else (try mod.getErrorValue(field_name)).key; + const name = try ip.getOrPutString(gpa, field_name); + switch (ip.indexToKey(child_type.ip_index)) { + .error_set_type => |error_set_type| blk: { + if (error_set_type.nameIndex(ip, name) != null) { + break :blk; + } + return sema.fail(block, src, "no error named '{s}' in '{}'", .{ + field_name, child_type.fmt(mod), + }); + }, + .inferred_error_set_type => { + return sema.fail(block, src, "TODO handle inferred error sets here", .{}); + }, + .simple_type => |t| assert(t == .anyerror), + else => unreachable, + } var anon_decl = try block.startAnonDecl(); defer anon_decl.deinit(); return sema.analyzeDeclRef(try anon_decl.finish( - if (!child_type.isAnyError()) - try child_type.copy(anon_decl.arena()) + if (!child_type.isAnyError(mod)) + child_type else - try Type.Tag.error_set_single.create(anon_decl.arena(), name), - try Value.Tag.@"error".create(anon_decl.arena(), .{ .name = name }), + try mod.singleErrorSetTypeNts(name), + try Value.Tag.@"error".create(anon_decl.arena(), .{ + .name = ip.stringToSlice(name), + }), 0, // default alignment )); }, @@ -24589,7 +24579,7 @@ fn fieldCallBind( } }; } } else if (first_param_type.zigTypeTag(mod) == .ErrorUnion and - first_param_type.errorUnionPayload().eql(concrete_ty, mod)) + first_param_type.errorUnionPayload(mod).eql(concrete_ty, mod)) { const deref = try sema.analyzeLoad(block, src, object_ptr, src); return .{ .method = .{ @@ -24832,7 +24822,7 @@ fn structFieldPtrByIndex( if (field.is_comptime) { const val = try Value.Tag.comptime_field_ptr.create(sema.arena, .{ - .field_ty = try field.ty.copy(sema.arena), + .field_ty = field.ty, .field_val = try field.default_val.copy(sema.arena), }); return sema.addConstant(ptr_field_ty, val); @@ -26227,7 +26217,7 @@ fn coerceExtra( .none => switch (inst_val.tag()) { .eu_payload => { const payload = try sema.addConstant( - inst_ty.errorUnionPayload(), + inst_ty.errorUnionPayload(mod), inst_val.castTag(.eu_payload).?.data, ); return sema.wrapErrorUnionPayload(block, dest_ty, payload, inst_src) catch |err| switch (err) { @@ -26240,7 +26230,7 @@ fn coerceExtra( else => {}, } const error_set = try sema.addConstant( - inst_ty.errorUnionSet(), + inst_ty.errorUnionSet(mod), inst_val, ); return sema.wrapErrorUnionSet(block, dest_ty, error_set, inst_src); @@ -26342,7 +26332,7 @@ fn coerceExtra( // E!T to T if (inst_ty.zigTypeTag(mod) == .ErrorUnion and - (try sema.coerceInMemoryAllowed(block, inst_ty.errorUnionPayload(), dest_ty, false, target, dest_ty_src, inst_src)) == .ok) + (try sema.coerceInMemoryAllowed(block, inst_ty.errorUnionPayload(mod), dest_ty, false, target, dest_ty_src, inst_src)) == .ok) { try sema.errNote(block, inst_src, msg, "cannot convert error union to payload type", .{}); try sema.errNote(block, inst_src, msg, "consider using 'try', 'catch', or 'if'", .{}); @@ -26393,7 +26383,7 @@ const InMemoryCoercionResult = union(enum) { optional_shape: Pair, optional_child: PairAndChild, from_anyerror, - missing_error: []const []const u8, + missing_error: []const InternPool.NullTerminatedString, /// true if wanted is var args fn_var_args: bool, /// true if wanted is generic @@ -26567,7 +26557,8 @@ const InMemoryCoercionResult = union(enum) { break; }, .missing_error => |missing_errors| { - for (missing_errors) |err| { + for (missing_errors) |err_index| { + const err = mod.intern_pool.stringToSlice(err_index); try sema.errNote(block, src, msg, "'error.{s}' not a member of destination error set", .{err}); } break; @@ -26813,8 +26804,8 @@ fn coerceInMemoryAllowed( // Error Unions if (dest_tag == .ErrorUnion and src_tag == .ErrorUnion) { - const dest_payload = dest_ty.errorUnionPayload(); - const src_payload = src_ty.errorUnionPayload(); + const dest_payload = dest_ty.errorUnionPayload(mod); + const src_payload = src_ty.errorUnionPayload(mod); const child = try sema.coerceInMemoryAllowed(block, dest_payload, src_payload, dest_is_mut, target, dest_src, src_src); if (child != .ok) { return InMemoryCoercionResult{ .error_union_payload = .{ @@ -26823,7 +26814,7 @@ fn coerceInMemoryAllowed( .wanted = dest_payload, } }; } - return try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionSet(), src_ty.errorUnionSet(), dest_is_mut, target, dest_src, src_src); + return try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionSet(mod), src_ty.errorUnionSet(mod), dest_is_mut, target, dest_src, src_src); } // Error Sets @@ -26903,8 +26894,8 @@ fn coerceInMemoryAllowed( if (child != .ok) { return InMemoryCoercionResult{ .optional_child = .{ .child = try child.dupe(sema.arena), - .actual = try src_child_type.copy(sema.arena), - .wanted = try dest_child_type.copy(sema.arena), + .actual = src_child_type, + .wanted = dest_child_type, } }; } @@ -26926,133 +26917,100 @@ fn coerceInMemoryAllowedErrorSets( src_src: LazySrcLoc, ) !InMemoryCoercionResult { const mod = sema.mod; + const gpa = sema.gpa; + const ip = &mod.intern_pool; // Coercion to `anyerror`. Note that this check can return false negatives // in case the error sets did not get resolved. - if (dest_ty.isAnyError()) { + if (dest_ty.isAnyError(mod)) { return .ok; } - if (dest_ty.castTag(.error_set_inferred)) |dst_payload| { - const dst_ies = dst_payload.data; + if (mod.typeToInferredErrorSetIndex(dest_ty).unwrap()) |dst_ies_index| { + const dst_ies = mod.inferredErrorSetPtr(dst_ies_index); // We will make an effort to return `ok` without resolving either error set, to // avoid unnecessary "unable to resolve error set" dependency loop errors. switch (src_ty.ip_index) { - .none => switch (src_ty.tag()) { - .error_set_inferred => { + .anyerror_type => {}, + else => switch (ip.indexToKey(src_ty.ip_index)) { + .inferred_error_set_type => |src_index| { // If both are inferred error sets of functions, and // the dest includes the source function, the coercion is OK. // This check is important because it works without forcing a full resolution // of inferred error sets. - const src_ies = src_ty.castTag(.error_set_inferred).?.data; - - if (dst_ies.inferred_error_sets.contains(src_ies)) { + if (dst_ies.inferred_error_sets.contains(src_index)) { return .ok; } }, - .error_set_single => { - const name = src_ty.castTag(.error_set_single).?.data; - if (dst_ies.errors.contains(name)) return .ok; - }, - .error_set_merged => { - const names = src_ty.castTag(.error_set_merged).?.data.keys(); - for (names) |name| { - if (!dst_ies.errors.contains(name)) break; - } else return .ok; - }, - .error_set => { - const names = src_ty.castTag(.error_set).?.data.names.keys(); - for (names) |name| { + .error_set_type => |error_set_type| { + for (error_set_type.names) |name| { if (!dst_ies.errors.contains(name)) break; } else return .ok; }, else => unreachable, }, - .anyerror_type => {}, - else => switch (mod.intern_pool.indexToKey(src_ty.ip_index)) { - else => @panic("TODO"), - }, } if (dst_ies.func == sema.owner_func) { // We are trying to coerce an error set to the current function's // inferred error set. - try dst_ies.addErrorSet(sema.gpa, src_ty); + try dst_ies.addErrorSet(src_ty, ip, gpa); return .ok; } - try sema.resolveInferredErrorSet(block, dest_src, dst_payload.data); + try sema.resolveInferredErrorSet(block, dest_src, dst_ies_index); // isAnyError might have changed from a false negative to a true positive after resolution. - if (dest_ty.isAnyError()) { + if (dest_ty.isAnyError(mod)) { return .ok; } } - var missing_error_buf = std.ArrayList([]const u8).init(sema.gpa); + var missing_error_buf = std.ArrayList(InternPool.NullTerminatedString).init(gpa); defer missing_error_buf.deinit(); switch (src_ty.ip_index) { - .none => switch (src_ty.tag()) { - .error_set_inferred => { - const src_data = src_ty.castTag(.error_set_inferred).?.data; + .anyerror_type => switch (ip.indexToKey(dest_ty.ip_index)) { + .inferred_error_set_type => unreachable, // Caught by dest_ty.isAnyError(mod) above. + .simple_type => unreachable, // filtered out above + .error_set_type => return .from_anyerror, + else => unreachable, + }, + + else => switch (ip.indexToKey(src_ty.ip_index)) { + .inferred_error_set_type => |src_index| { + const src_data = mod.inferredErrorSetPtr(src_index); - try sema.resolveInferredErrorSet(block, src_src, src_data); + try sema.resolveInferredErrorSet(block, src_src, src_index); // src anyerror status might have changed after the resolution. - if (src_ty.isAnyError()) { - // dest_ty.isAnyError() == true is already checked for at this point. + if (src_ty.isAnyError(mod)) { + // dest_ty.isAnyError(mod) == true is already checked for at this point. return .from_anyerror; } for (src_data.errors.keys()) |key| { - if (!dest_ty.errorSetHasField(key)) { + if (!Type.errorSetHasFieldIp(ip, dest_ty.toIntern(), key)) { try missing_error_buf.append(key); } } if (missing_error_buf.items.len != 0) { return InMemoryCoercionResult{ - .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items), - }; - } - - return .ok; - }, - .error_set_single => { - const name = src_ty.castTag(.error_set_single).?.data; - if (dest_ty.errorSetHasField(name)) { - return .ok; - } - const list = try sema.arena.alloc([]const u8, 1); - list[0] = name; - return InMemoryCoercionResult{ .missing_error = list }; - }, - .error_set_merged => { - const names = src_ty.castTag(.error_set_merged).?.data.keys(); - for (names) |name| { - if (!dest_ty.errorSetHasField(name)) { - try missing_error_buf.append(name); - } - } - - if (missing_error_buf.items.len != 0) { - return InMemoryCoercionResult{ - .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items), + .missing_error = try sema.arena.dupe(InternPool.NullTerminatedString, missing_error_buf.items), }; } return .ok; }, - .error_set => { - const names = src_ty.castTag(.error_set).?.data.names.keys(); - for (names) |name| { - if (!dest_ty.errorSetHasField(name)) { + .error_set_type => |error_set_type| { + for (error_set_type.names) |name| { + if (!Type.errorSetHasFieldIp(ip, dest_ty.toIntern(), name)) { try missing_error_buf.append(name); } } if (missing_error_buf.items.len != 0) { return InMemoryCoercionResult{ - .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items), + .missing_error = try sema.arena.dupe(InternPool.NullTerminatedString, missing_error_buf.items), }; } @@ -27060,18 +27018,6 @@ fn coerceInMemoryAllowedErrorSets( }, else => unreachable, }, - - .anyerror_type => switch (dest_ty.ip_index) { - .none => switch (dest_ty.tag()) { - .error_set_inferred => unreachable, // Caught by dest_ty.isAnyError() above. - .error_set_single, .error_set_merged, .error_set => return .from_anyerror, - else => unreachable, - }, - .anyerror_type => unreachable, // Filtered out above. - else => @panic("TODO"), - }, - - else => @panic("TODO"), } unreachable; @@ -28029,7 +27975,7 @@ fn beginComptimePtrMutation( var parent = try sema.beginComptimePtrMutation(block, src, eu_ptr.container_ptr, eu_ptr.container_ty); switch (parent.pointee) { .direct => |val_ptr| { - const payload_ty = parent.ty.errorUnionPayload(); + const payload_ty = parent.ty.errorUnionPayload(mod); if (val_ptr.ip_index == .none and val_ptr.tag() == .eu_payload) { return ComptimePtrMutationKit{ .decl_ref_mut = parent.decl_ref_mut, @@ -28402,7 +28348,7 @@ fn beginComptimePtrLoad( => blk: { const payload_ptr = ptr_val.cast(Value.Payload.PayloadPtr).?.data; const payload_ty = switch (ptr_val.tag()) { - .eu_payload_ptr => payload_ptr.container_ty.errorUnionPayload(), + .eu_payload_ptr => payload_ptr.container_ty.errorUnionPayload(mod), .opt_payload_ptr => payload_ptr.container_ty.optionalChild(mod), else => unreachable, }; @@ -29301,7 +29247,7 @@ fn refValue(sema: *Sema, block: *Block, ty: Type, val: Value) !Value { var anon_decl = try block.startAnonDecl(); defer anon_decl.deinit(); const decl = try anon_decl.finish( - try ty.copy(anon_decl.arena()), + ty, try val.copy(anon_decl.arena()), 0, // default alignment ); @@ -29387,7 +29333,7 @@ fn analyzeRef( var anon_decl = try block.startAnonDecl(); defer anon_decl.deinit(); return sema.analyzeDeclRef(try anon_decl.finish( - try operand_ty.copy(anon_decl.arena()), + operand_ty, try val.copy(anon_decl.arena()), 0, // default alignment )); @@ -29555,7 +29501,7 @@ fn analyzeIsNonErrComptimeOnly( if (ot == .ErrorSet) return Air.Inst.Ref.bool_false; assert(ot == .ErrorUnion); - const payload_ty = operand_ty.errorUnionPayload(); + const payload_ty = operand_ty.errorUnionPayload(mod); if (payload_ty.zigTypeTag(mod) == .NoReturn) { return Air.Inst.Ref.bool_false; } @@ -29577,23 +29523,28 @@ fn analyzeIsNonErrComptimeOnly( // exception if the error union error set is known to be empty, // we allow the comparison but always make it comptime-known. - const set_ty = operand_ty.errorUnionSet(); + const set_ty = operand_ty.errorUnionSet(mod); switch (set_ty.ip_index) { - .none => switch (set_ty.tag()) { - .error_set_inferred => blk: { + .anyerror_type => {}, + else => switch (mod.intern_pool.indexToKey(set_ty.ip_index)) { + .error_set_type => |error_set_type| { + if (error_set_type.names.len == 0) return Air.Inst.Ref.bool_true; + }, + .inferred_error_set_type => |ies_index| blk: { // If the error set is empty, we must return a comptime true or false. // However we want to avoid unnecessarily resolving an inferred error set // in case it is already non-empty. - const ies = set_ty.castTag(.error_set_inferred).?.data; + const ies = mod.inferredErrorSetPtr(ies_index); if (ies.is_anyerror) break :blk; if (ies.errors.count() != 0) break :blk; if (maybe_operand_val == null) { // Try to avoid resolving inferred error set if possible. if (ies.errors.count() != 0) break :blk; if (ies.is_anyerror) break :blk; - for (ies.inferred_error_sets.keys()) |other_ies| { - if (ies == other_ies) continue; - try sema.resolveInferredErrorSet(block, src, other_ies); + for (ies.inferred_error_sets.keys()) |other_ies_index| { + if (ies_index == other_ies_index) continue; + try sema.resolveInferredErrorSet(block, src, other_ies_index); + const other_ies = mod.inferredErrorSetPtr(other_ies_index); if (other_ies.is_anyerror) { ies.is_anyerror = true; ies.is_resolved = true; @@ -29608,18 +29559,12 @@ fn analyzeIsNonErrComptimeOnly( // so far with this type can't contain errors either. return Air.Inst.Ref.bool_true; } - try sema.resolveInferredErrorSet(block, src, ies); + try sema.resolveInferredErrorSet(block, src, ies_index); if (ies.is_anyerror) break :blk; if (ies.errors.count() == 0) return Air.Inst.Ref.bool_true; } }, - else => if (set_ty.errorSetNames().len == 0) return Air.Inst.Ref.bool_true, - }, - - .anyerror_type => {}, - - else => switch (mod.intern_pool.indexToKey(set_ty.ip_index)) { - else => @panic("TODO"), + else => unreachable, }, } @@ -30516,7 +30461,8 @@ fn wrapErrorUnionPayload( inst: Air.Inst.Ref, inst_src: LazySrcLoc, ) !Air.Inst.Ref { - const dest_payload_ty = dest_ty.errorUnionPayload(); + const mod = sema.mod; + const dest_payload_ty = dest_ty.errorUnionPayload(mod); const coerced = try sema.coerceExtra(block, dest_payload_ty, inst, inst_src, .{ .report_err = false }); if (try sema.resolveMaybeUndefVal(coerced)) |val| { return sema.addConstant(dest_ty, try Value.Tag.eu_payload.create(sema.arena, val)); @@ -30533,51 +30479,41 @@ fn wrapErrorUnionSet( inst: Air.Inst.Ref, inst_src: LazySrcLoc, ) !Air.Inst.Ref { + const mod = sema.mod; + const ip = &mod.intern_pool; const inst_ty = sema.typeOf(inst); - const dest_err_set_ty = dest_ty.errorUnionSet(); + const dest_err_set_ty = dest_ty.errorUnionSet(mod); if (try sema.resolveMaybeUndefVal(inst)) |val| { switch (dest_err_set_ty.ip_index) { .anyerror_type => {}, - - .none => switch (dest_err_set_ty.tag()) { - .error_set_single => ok: { - const expected_name = val.castTag(.@"error").?.data.name; - const n = dest_err_set_ty.castTag(.error_set_single).?.data; - if (mem.eql(u8, expected_name, n)) break :ok; - return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); - }, - .error_set => { + else => switch (ip.indexToKey(dest_err_set_ty.ip_index)) { + .error_set_type => |error_set_type| ok: { const expected_name = val.castTag(.@"error").?.data.name; - const error_set = dest_err_set_ty.castTag(.error_set).?.data; - if (!error_set.names.contains(expected_name)) { - return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); + if (ip.getString(expected_name).unwrap()) |expected_name_interned| { + if (error_set_type.nameIndex(ip, expected_name_interned) != null) + break :ok; } + return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); }, - .error_set_inferred => ok: { + .inferred_error_set_type => |ies_index| ok: { + const ies = mod.inferredErrorSetPtr(ies_index); const expected_name = val.castTag(.@"error").?.data.name; - const ies = dest_err_set_ty.castTag(.error_set_inferred).?.data; // We carefully do this in an order that avoids unnecessarily // resolving the destination error set type. if (ies.is_anyerror) break :ok; - if (ies.errors.contains(expected_name)) break :ok; + + if (ip.getString(expected_name).unwrap()) |expected_name_interned| { + if (ies.errors.contains(expected_name_interned)) break :ok; + } if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, dest_err_set_ty, inst_ty, inst_src, inst_src)) { break :ok; } return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); }, - .error_set_merged => { - const expected_name = val.castTag(.@"error").?.data.name; - const error_set = dest_err_set_ty.castTag(.error_set_merged).?.data; - if (!error_set.contains(expected_name)) { - return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); - } - }, else => unreachable, }, - - else => @panic("TODO"), } return sema.addConstant(dest_ty, val); } @@ -30743,11 +30679,11 @@ fn resolvePeerTypes( continue; } - err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_ty); + err_set_ty = try sema.errorSetMerge(chosen_set_ty, candidate_ty); continue; }, .ErrorUnion => { - const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet(); + const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet(mod); if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_ty, src, src)) { continue; @@ -30757,7 +30693,7 @@ fn resolvePeerTypes( continue; } - err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_ty); + err_set_ty = try sema.errorSetMerge(chosen_set_ty, candidate_ty); continue; }, else => { @@ -30770,7 +30706,7 @@ fn resolvePeerTypes( continue; } - err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_ty); + err_set_ty = try sema.errorSetMerge(chosen_set_ty, candidate_ty); continue; } else { err_set_ty = candidate_ty; @@ -30781,14 +30717,14 @@ fn resolvePeerTypes( .ErrorUnion => switch (chosen_ty_tag) { .ErrorSet => { const chosen_set_ty = err_set_ty orelse chosen_ty; - const candidate_set_ty = candidate_ty.errorUnionSet(); + const candidate_set_ty = candidate_ty.errorUnionSet(mod); if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) { err_set_ty = chosen_set_ty; } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) { err_set_ty = null; } else { - err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty); + err_set_ty = try sema.errorSetMerge(chosen_set_ty, candidate_set_ty); } chosen = candidate; chosen_i = candidate_i + 1; @@ -30796,8 +30732,8 @@ fn resolvePeerTypes( }, .ErrorUnion => { - const chosen_payload_ty = chosen_ty.errorUnionPayload(); - const candidate_payload_ty = candidate_ty.errorUnionPayload(); + const chosen_payload_ty = chosen_ty.errorUnionPayload(mod); + const candidate_payload_ty = candidate_ty.errorUnionPayload(mod); const coerce_chosen = (try sema.coerceInMemoryAllowed(block, chosen_payload_ty, candidate_payload_ty, false, target, src, src)) == .ok; const coerce_candidate = (try sema.coerceInMemoryAllowed(block, candidate_payload_ty, chosen_payload_ty, false, target, src, src)) == .ok; @@ -30811,15 +30747,15 @@ fn resolvePeerTypes( chosen_i = candidate_i + 1; } - const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet(); - const candidate_set_ty = candidate_ty.errorUnionSet(); + const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet(mod); + const candidate_set_ty = candidate_ty.errorUnionSet(mod); if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) { err_set_ty = chosen_set_ty; } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) { err_set_ty = candidate_set_ty; } else { - err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty); + err_set_ty = try sema.errorSetMerge(chosen_set_ty, candidate_set_ty); } continue; } @@ -30827,13 +30763,13 @@ fn resolvePeerTypes( else => { if (err_set_ty) |chosen_set_ty| { - const candidate_set_ty = candidate_ty.errorUnionSet(); + const candidate_set_ty = candidate_ty.errorUnionSet(mod); if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) { err_set_ty = chosen_set_ty; } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) { err_set_ty = null; } else { - err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty); + err_set_ty = try sema.errorSetMerge(chosen_set_ty, candidate_set_ty); } } seen_const = seen_const or chosen_ty.isConstPtr(mod); @@ -30963,7 +30899,7 @@ fn resolvePeerTypes( } }, .ErrorUnion => { - const chosen_ptr_ty = chosen_ty.errorUnionPayload(); + const chosen_ptr_ty = chosen_ty.errorUnionPayload(mod); if (chosen_ptr_ty.zigTypeTag(mod) == .Pointer) { const chosen_info = chosen_ptr_ty.ptrInfo(mod); @@ -31073,7 +31009,7 @@ fn resolvePeerTypes( } }, .ErrorUnion => { - const payload_ty = chosen_ty.errorUnionPayload(); + const payload_ty = chosen_ty.errorUnionPayload(mod); if ((try sema.coerceInMemoryAllowed(block, payload_ty, candidate_ty, false, target, src, src)) == .ok) { continue; } @@ -31090,7 +31026,7 @@ fn resolvePeerTypes( continue; } - err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, chosen_ty); + err_set_ty = try sema.errorSetMerge(chosen_set_ty, chosen_ty); continue; } else { err_set_ty = chosen_ty; @@ -31148,14 +31084,14 @@ fn resolvePeerTypes( else new_ptr_ty; const set_ty = err_set_ty orelse return opt_ptr_ty; - return try Type.errorUnion(sema.arena, set_ty, opt_ptr_ty, mod); + return try mod.errorUnionType(set_ty, opt_ptr_ty); } if (seen_const) { // turn []T => []const T switch (chosen_ty.zigTypeTag(mod)) { .ErrorUnion => { - const ptr_ty = chosen_ty.errorUnionPayload(); + const ptr_ty = chosen_ty.errorUnionPayload(mod); var info = ptr_ty.ptrInfo(mod); info.mutable = false; const new_ptr_ty = try Type.ptr(sema.arena, mod, info); @@ -31163,8 +31099,8 @@ fn resolvePeerTypes( try Type.optional(sema.arena, new_ptr_ty, mod) else new_ptr_ty; - const set_ty = err_set_ty orelse chosen_ty.errorUnionSet(); - return try Type.errorUnion(sema.arena, set_ty, opt_ptr_ty, mod); + const set_ty = err_set_ty orelse chosen_ty.errorUnionSet(mod); + return try mod.errorUnionType(set_ty, opt_ptr_ty); }, .Pointer => { var info = chosen_ty.ptrInfo(mod); @@ -31175,7 +31111,7 @@ fn resolvePeerTypes( else new_ptr_ty; const set_ty = err_set_ty orelse return opt_ptr_ty; - return try Type.errorUnion(sema.arena, set_ty, opt_ptr_ty, mod); + return try mod.errorUnionType(set_ty, opt_ptr_ty); }, else => return chosen_ty, } @@ -31187,16 +31123,16 @@ fn resolvePeerTypes( else => try Type.optional(sema.arena, chosen_ty, mod), }; const set_ty = err_set_ty orelse return opt_ty; - return try Type.errorUnion(sema.arena, set_ty, opt_ty, mod); + return try mod.errorUnionType(set_ty, opt_ty); } if (err_set_ty) |ty| switch (chosen_ty.zigTypeTag(mod)) { .ErrorSet => return ty, .ErrorUnion => { - const payload_ty = chosen_ty.errorUnionPayload(); - return try Type.errorUnion(sema.arena, ty, payload_ty, mod); + const payload_ty = chosen_ty.errorUnionPayload(mod); + return try mod.errorUnionType(ty, payload_ty); }, - else => return try Type.errorUnion(sema.arena, ty, chosen_ty, mod), + else => return try mod.errorUnionType(ty, chosen_ty), }; return chosen_ty; @@ -31279,7 +31215,7 @@ pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void { return sema.resolveTypeLayout(payload_ty); }, .ErrorUnion => { - const payload_ty = ty.errorUnionPayload(); + const payload_ty = ty.errorUnionPayload(mod); return sema.resolveTypeLayout(payload_ty); }, .Fn => { @@ -31465,7 +31401,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi }; try sema.checkBackingIntType(&block, backing_int_src, backing_int_ty, fields_bit_sum); - struct_obj.backing_int_ty = try backing_int_ty.copy(decl_arena_allocator); + struct_obj.backing_int_ty = backing_int_ty; try wip_captures.finalize(); } else { if (fields_bit_sum > std.math.maxInt(u16)) { @@ -31605,18 +31541,6 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { 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 sema.resolveTypeRequiresComptime(ty.errorUnionPayload()), - }, else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { .int_type => false, .ptr_type => |ptr_type| { @@ -31635,6 +31559,8 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { .vector_type => |vector_type| return sema.resolveTypeRequiresComptime(vector_type.child.toType()), .opt_type => |child| return sema.resolveTypeRequiresComptime(child.toType()), .error_union_type => |error_union_type| return sema.resolveTypeRequiresComptime(error_union_type.payload_type.toType()), + .error_set_type, .inferred_error_set_type => false, + .func_type => true, .simple_type => |t| switch (t) { @@ -31780,7 +31706,7 @@ pub fn resolveTypeFully(sema: *Sema, ty: Type) CompileError!void { .Optional => { return sema.resolveTypeFully(ty.optionalChild(mod)); }, - .ErrorUnion => return sema.resolveTypeFully(ty.errorUnionPayload()), + .ErrorUnion => return sema.resolveTypeFully(ty.errorUnionPayload(mod)), .Fn => { const info = mod.typeToFunc(ty).?; if (info.is_generic) { @@ -32048,16 +31974,17 @@ fn resolveInferredErrorSet( sema: *Sema, block: *Block, src: LazySrcLoc, - ies: *Module.Fn.InferredErrorSet, + ies_index: Module.Fn.InferredErrorSet.Index, ) CompileError!void { + const mod = sema.mod; + const ies = mod.inferredErrorSetPtr(ies_index); + if (ies.is_resolved) return; if (ies.func.state == .in_progress) { return sema.fail(block, src, "unable to resolve inferred error set", .{}); } - const mod = sema.mod; - // In order to ensure that all dependencies are properly added to the set, we // need to ensure the function body is analyzed of the inferred error set. // However, in the case of comptime/inline function calls with inferred error sets, @@ -32072,7 +31999,7 @@ fn resolveInferredErrorSet( // so here we can simply skip this case. if (ies_func_info.return_type == .generic_poison_type) { assert(ies_func_info.cc == .Inline); - } else if (ies_func_info.return_type.toType().errorUnionSet().castTag(.error_set_inferred).?.data == ies) { + } else if (mod.typeToInferredErrorSet(ies_func_info.return_type.toType().errorUnionSet(mod)).? == ies) { if (ies_func_info.is_generic) { const msg = msg: { const msg = try sema.errMsg(block, src, "unable to resolve inferred error set of generic function", .{}); @@ -32090,10 +32017,11 @@ fn resolveInferredErrorSet( ies.is_resolved = true; - for (ies.inferred_error_sets.keys()) |other_ies| { - if (ies == other_ies) continue; - try sema.resolveInferredErrorSet(block, src, other_ies); + for (ies.inferred_error_sets.keys()) |other_ies_index| { + if (ies_index == other_ies_index) continue; + try sema.resolveInferredErrorSet(block, src, other_ies_index); + const other_ies = mod.inferredErrorSetPtr(other_ies_index); for (other_ies.errors.keys()) |key| { try ies.errors.put(sema.gpa, key, {}); } @@ -32108,8 +32036,9 @@ fn resolveInferredErrorSetTy( src: LazySrcLoc, ty: Type, ) CompileError!void { - if (ty.castTag(.error_set_inferred)) |inferred| { - try sema.resolveInferredErrorSet(block, src, inferred.data); + const mod = sema.mod; + if (mod.typeToInferredErrorSetIndex(ty).unwrap()) |ies_index| { + try sema.resolveInferredErrorSet(block, src, ies_index); } } @@ -32333,7 +32262,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void } const field = &struct_obj.fields.values()[field_i]; - field.ty = try field_ty.copy(decl_arena_allocator); + field.ty = field_ty; if (field_ty.zigTypeTag(mod) == .Opaque) { const msg = msg: { @@ -32809,7 +32738,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { } gop.value_ptr.* = .{ - .ty = try field_ty.copy(decl_arena_allocator), + .ty = field_ty, .abi_align = 0, }; @@ -33038,13 +32967,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { .empty_struct_type => return Value.empty_struct, .none => switch (ty.tag()) { - .error_set_single, - .error_set, - .error_set_merged, - .error_union, - .error_set_inferred, - => return null, - .inferred_alloc_const => unreachable, .inferred_alloc_mut => unreachable, }, @@ -33062,6 +32984,8 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { .error_union_type, .func_type, .anyframe_type, + .error_set_type, + .inferred_error_set_type, => null, .array_type => |array_type| { @@ -33389,7 +33313,7 @@ fn analyzeComptimeAlloc( defer anon_decl.deinit(); const decl_index = try anon_decl.finish( - try var_type.copy(anon_decl.arena()), + var_type, // There will be stores before the first load, but they may be to sub-elements or // sub-fields. So we need to initialize with undef to allow the mechanism to expand // into fields/elements and have those overridden with stored values. @@ -33600,8 +33524,6 @@ fn typePtrOrOptionalPtrTy(sema: *Sema, ty: Type) !?Type { switch (ty.tag()) { .inferred_alloc_const => unreachable, .inferred_alloc_mut => unreachable, - - else => return null, } } @@ -33616,18 +33538,6 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { 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 sema.typeRequiresComptime(ty.errorUnionPayload()), - }, else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { .int_type => return false, .ptr_type => |ptr_type| { @@ -33649,6 +33559,9 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { .error_union_type => |error_union_type| { return sema.typeRequiresComptime(error_union_type.payload_type.toType()); }, + + .error_set_type, .inferred_error_set_type => false, + .func_type => true, .simple_type => |t| return switch (t) { @@ -34410,3 +34323,23 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { .vector_index = vector_info.vector_index, }); } + +/// Merge lhs with rhs. +/// Asserts that lhs and rhs are both error sets and are resolved. +fn errorSetMerge(sema: *Sema, lhs: Type, rhs: Type) !Type { + const mod = sema.mod; + const arena = sema.arena; + const lhs_names = lhs.errorSetNames(mod); + const rhs_names = rhs.errorSetNames(mod); + var names: Module.Fn.InferredErrorSet.NameMap = .{}; + try names.ensureUnusedCapacity(arena, lhs_names.len); + + for (lhs_names) |name| { + names.putAssumeCapacityNoClobber(name, {}); + } + for (rhs_names) |name| { + try names.put(arena, name, {}); + } + + return mod.errorSetFromUnsortedNames(names.keys()); +} diff --git a/src/TypedValue.zig b/src/TypedValue.zig index ced20ac522..144b7ebf9d 100644 --- a/src/TypedValue.zig +++ b/src/TypedValue.zig @@ -27,13 +27,13 @@ pub const Managed = struct { /// Assumes arena allocation. Does a recursive copy. pub fn copy(self: TypedValue, arena: Allocator) error{OutOfMemory}!TypedValue { return TypedValue{ - .ty = try self.ty.copy(arena), + .ty = self.ty, .val = try self.val.copy(arena), }; } pub fn eql(a: TypedValue, b: TypedValue, mod: *Module) bool { - if (!a.ty.eql(b.ty, mod)) return false; + if (a.ty.ip_index != b.ty.ip_index) return false; return a.val.eql(b.val, a.ty, mod); } @@ -286,7 +286,7 @@ pub fn print( .@"error" => return writer.print("error.{s}", .{val.castTag(.@"error").?.data.name}), .eu_payload => { val = val.castTag(.eu_payload).?.data; - ty = ty.errorUnionPayload(); + ty = ty.errorUnionPayload(mod); }, .opt_payload => { val = val.castTag(.opt_payload).?.data; diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 8b84189e18..c9126747da 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -3065,8 +3065,8 @@ fn errUnionErr( maybe_inst: ?Air.Inst.Index, ) !MCValue { const mod = self.bin_file.options.module.?; - const err_ty = error_union_ty.errorUnionSet(); - const payload_ty = error_union_ty.errorUnionPayload(); + const err_ty = error_union_ty.errorUnionSet(mod); + const payload_ty = error_union_ty.errorUnionPayload(mod); if (err_ty.errorSetIsEmpty(mod)) { return MCValue{ .immediate = 0 }; } @@ -3145,8 +3145,8 @@ fn errUnionPayload( maybe_inst: ?Air.Inst.Index, ) !MCValue { const mod = self.bin_file.options.module.?; - const err_ty = error_union_ty.errorUnionSet(); - const payload_ty = error_union_ty.errorUnionPayload(); + const err_ty = error_union_ty.errorUnionSet(mod); + const payload_ty = error_union_ty.errorUnionPayload(mod); if (err_ty.errorSetIsEmpty(mod)) { return try error_union_bind.resolveToMcv(self); } @@ -3305,8 +3305,8 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const error_union_ty = self.air.getRefType(ty_op.ty); - const error_ty = error_union_ty.errorUnionSet(); - const payload_ty = error_union_ty.errorUnionPayload(); + const error_ty = error_union_ty.errorUnionSet(mod); + const payload_ty = error_union_ty.errorUnionPayload(mod); const operand = try self.resolveInst(ty_op.operand); if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) break :result operand; @@ -3329,8 +3329,8 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const mod = self.bin_file.options.module.?; const error_union_ty = self.air.getRefType(ty_op.ty); - const error_ty = error_union_ty.errorUnionSet(); - const payload_ty = error_union_ty.errorUnionPayload(); + const error_ty = error_union_ty.errorUnionSet(mod); + const payload_ty = error_union_ty.errorUnionPayload(mod); const operand = try self.resolveInst(ty_op.operand); if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) break :result operand; @@ -4893,7 +4893,7 @@ fn isErr( error_union_ty: Type, ) !MCValue { const mod = self.bin_file.options.module.?; - const error_type = error_union_ty.errorUnionSet(); + const error_type = error_union_ty.errorUnionSet(mod); if (error_type.errorSetIsEmpty(mod)) { return MCValue{ .immediate = 0 }; // always false diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index a6a715c75d..fa8646be43 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -2042,8 +2042,8 @@ fn errUnionErr( maybe_inst: ?Air.Inst.Index, ) !MCValue { const mod = self.bin_file.options.module.?; - const err_ty = error_union_ty.errorUnionSet(); - const payload_ty = error_union_ty.errorUnionPayload(); + const err_ty = error_union_ty.errorUnionSet(mod); + const payload_ty = error_union_ty.errorUnionPayload(mod); if (err_ty.errorSetIsEmpty(mod)) { return MCValue{ .immediate = 0 }; } @@ -2119,8 +2119,8 @@ fn errUnionPayload( maybe_inst: ?Air.Inst.Index, ) !MCValue { const mod = self.bin_file.options.module.?; - const err_ty = error_union_ty.errorUnionSet(); - const payload_ty = error_union_ty.errorUnionPayload(); + const err_ty = error_union_ty.errorUnionSet(mod); + const payload_ty = error_union_ty.errorUnionPayload(mod); if (err_ty.errorSetIsEmpty(mod)) { return try error_union_bind.resolveToMcv(self); } @@ -2232,8 +2232,8 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const error_union_ty = self.air.getRefType(ty_op.ty); - const error_ty = error_union_ty.errorUnionSet(); - const payload_ty = error_union_ty.errorUnionPayload(); + const error_ty = error_union_ty.errorUnionSet(mod); + const payload_ty = error_union_ty.errorUnionPayload(mod); const operand = try self.resolveInst(ty_op.operand); if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) break :result operand; @@ -2256,8 +2256,8 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const error_union_ty = self.air.getRefType(ty_op.ty); - const error_ty = error_union_ty.errorUnionSet(); - const payload_ty = error_union_ty.errorUnionPayload(); + const error_ty = error_union_ty.errorUnionSet(mod); + const payload_ty = error_union_ty.errorUnionPayload(mod); const operand = try self.resolveInst(ty_op.operand); if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) break :result operand; @@ -4871,7 +4871,7 @@ fn isErr( error_union_ty: Type, ) !MCValue { const mod = self.bin_file.options.module.?; - const error_type = error_union_ty.errorUnionSet(); + const error_type = error_union_ty.errorUnionSet(mod); if (error_type.errorSetIsEmpty(mod)) { return MCValue{ .immediate = 0 }; // always false diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 072d3ed098..13f129f87b 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -2707,12 +2707,12 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void { } fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { + const mod = self.bin_file.options.module.?; const ty_op = self.air.instructions.items(.data)[inst].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const error_union_ty = self.typeOf(ty_op.operand); - const payload_ty = error_union_ty.errorUnionPayload(); + const payload_ty = error_union_ty.errorUnionPayload(mod); const mcv = try self.resolveInst(ty_op.operand); - const mod = self.bin_file.options.module.?; if (!payload_ty.hasRuntimeBits(mod)) break :result mcv; return self.fail("TODO implement unwrap error union error for non-empty payloads", .{}); @@ -2721,11 +2721,11 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { } fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { + const mod = self.bin_file.options.module.?; const ty_op = self.air.instructions.items(.data)[inst].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const error_union_ty = self.typeOf(ty_op.operand); - const payload_ty = error_union_ty.errorUnionPayload(); - const mod = self.bin_file.options.module.?; + const payload_ty = error_union_ty.errorUnionPayload(mod); if (!payload_ty.hasRuntimeBits(mod)) break :result MCValue.none; return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{}); @@ -2735,12 +2735,12 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { /// E to E!T fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { + const mod = self.bin_file.options.module.?; const ty_op = self.air.instructions.items(.data)[inst].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const error_union_ty = self.air.getRefType(ty_op.ty); - const payload_ty = error_union_ty.errorUnionPayload(); + const payload_ty = error_union_ty.errorUnionPayload(mod); const mcv = try self.resolveInst(ty_op.operand); - const mod = self.bin_file.options.module.?; if (!payload_ty.hasRuntimeBits(mod)) break :result mcv; return self.fail("TODO implement wrap errunion error for non-empty payloads", .{}); @@ -3529,8 +3529,8 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { /// Given an error union, returns the payload fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue { const mod = self.bin_file.options.module.?; - const err_ty = error_union_ty.errorUnionSet(); - const payload_ty = error_union_ty.errorUnionPayload(); + const err_ty = error_union_ty.errorUnionSet(mod); + const payload_ty = error_union_ty.errorUnionPayload(mod); if (err_ty.errorSetIsEmpty(mod)) { return error_union_mcv; } @@ -4168,8 +4168,8 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { const mod = self.bin_file.options.module.?; - const error_type = ty.errorUnionSet(); - const payload_type = ty.errorUnionPayload(); + const error_type = ty.errorUnionSet(mod); + const payload_type = ty.errorUnionPayload(mod); if (!error_type.hasRuntimeBits(mod)) { return MCValue{ .immediate = 0 }; // always false diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index a950264840..2d7e4a8585 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1264,7 +1264,7 @@ fn genFunc(func: *CodeGen) InnerError!void { if (func_type.returns.len != 0 and func.air.instructions.len > 0) { const inst = @intCast(u32, func.air.instructions.len - 1); const last_inst_ty = func.typeOfIndex(inst); - if (!last_inst_ty.hasRuntimeBitsIgnoreComptime(mod) or last_inst_ty.isNoReturn()) { + if (!last_inst_ty.hasRuntimeBitsIgnoreComptime(mod) or last_inst_ty.isNoReturn(mod)) { try func.addTag(.@"unreachable"); } } @@ -1757,7 +1757,7 @@ fn isByRef(ty: Type, mod: *Module) bool { .Int => return ty.intInfo(mod).bits > 64, .Float => return ty.floatBits(target) > 64, .ErrorUnion => { - const pl_ty = ty.errorUnionPayload(); + const pl_ty = ty.errorUnionPayload(mod); if (!pl_ty.hasRuntimeBitsIgnoreComptime(mod)) { return false; } @@ -2256,7 +2256,7 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif const result_value = result_value: { if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod) and !ret_ty.isError(mod)) { break :result_value WValue{ .none = {} }; - } else if (ret_ty.isNoReturn()) { + } else if (ret_ty.isNoReturn(mod)) { try func.addTag(.@"unreachable"); break :result_value WValue{ .none = {} }; } else if (first_param_sret) { @@ -2346,7 +2346,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE const abi_size = ty.abiSize(mod); switch (ty.zigTypeTag(mod)) { .ErrorUnion => { - const pl_ty = ty.errorUnionPayload(); + const pl_ty = ty.errorUnionPayload(mod); if (!pl_ty.hasRuntimeBitsIgnoreComptime(mod)) { return func.store(lhs, rhs, Type.anyerror, 0); } @@ -3111,8 +3111,8 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { else => return WValue{ .imm32 = 0 }, }, .ErrorUnion => { - const error_type = ty.errorUnionSet(); - const payload_type = ty.errorUnionPayload(); + const error_type = ty.errorUnionSet(mod); + const payload_type = ty.errorUnionPayload(mod); if (!payload_type.hasRuntimeBitsIgnoreComptime(mod)) { // We use the error type directly as the type. const is_pl = val.errorUnionIsPayload(); @@ -3916,10 +3916,10 @@ fn airIsErr(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerErro const un_op = func.air.instructions.items(.data)[inst].un_op; const operand = try func.resolveInst(un_op); const err_union_ty = func.typeOf(un_op); - const pl_ty = err_union_ty.errorUnionPayload(); + const pl_ty = err_union_ty.errorUnionPayload(mod); const result = result: { - if (err_union_ty.errorUnionSet().errorSetIsEmpty(mod)) { + if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { switch (opcode) { .i32_ne => break :result WValue{ .imm32 = 0 }, .i32_eq => break :result WValue{ .imm32 = 1 }, @@ -3953,7 +3953,7 @@ fn airUnwrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index, op_is_ptr: boo const operand = try func.resolveInst(ty_op.operand); const op_ty = func.typeOf(ty_op.operand); const err_ty = if (op_is_ptr) op_ty.childType(mod) else op_ty; - const payload_ty = err_ty.errorUnionPayload(); + const payload_ty = err_ty.errorUnionPayload(mod); const result = result: { if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { @@ -3981,10 +3981,10 @@ fn airUnwrapErrUnionError(func: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) const operand = try func.resolveInst(ty_op.operand); const op_ty = func.typeOf(ty_op.operand); const err_ty = if (op_is_ptr) op_ty.childType(mod) else op_ty; - const payload_ty = err_ty.errorUnionPayload(); + const payload_ty = err_ty.errorUnionPayload(mod); const result = result: { - if (err_ty.errorUnionSet().errorSetIsEmpty(mod)) { + if (err_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { break :result WValue{ .imm32 = 0 }; } @@ -4031,7 +4031,7 @@ fn airWrapErrUnionErr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { const operand = try func.resolveInst(ty_op.operand); const err_ty = func.air.getRefType(ty_op.ty); - const pl_ty = err_ty.errorUnionPayload(); + const pl_ty = err_ty.errorUnionPayload(mod); const result = result: { if (!pl_ty.hasRuntimeBitsIgnoreComptime(mod)) { @@ -4044,7 +4044,7 @@ fn airWrapErrUnionErr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { // write 'undefined' to the payload const payload_ptr = try func.buildPointerOffset(err_union, @intCast(u32, errUnionPayloadOffset(pl_ty, mod)), .new); - const len = @intCast(u32, err_ty.errorUnionPayload().abiSize(mod)); + const len = @intCast(u32, err_ty.errorUnionPayload(mod).abiSize(mod)); try func.memset(Type.u8, payload_ptr, .{ .imm32 = len }, .{ .imm32 = 0xaa }); break :result err_union; @@ -5362,7 +5362,7 @@ fn airErrUnionPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!voi const ty_op = func.air.instructions.items(.data)[inst].ty_op; const err_set_ty = func.typeOf(ty_op.operand).childType(mod); - const payload_ty = err_set_ty.errorUnionPayload(); + const payload_ty = err_set_ty.errorUnionPayload(mod); const operand = try func.resolveInst(ty_op.operand); // set error-tag to '0' to annotate error union is non-error @@ -6177,10 +6177,10 @@ fn lowerTry( return func.fail("TODO: lowerTry for pointers", .{}); } - const pl_ty = err_union_ty.errorUnionPayload(); + const pl_ty = err_union_ty.errorUnionPayload(mod); const pl_has_bits = pl_ty.hasRuntimeBitsIgnoreComptime(mod); - if (!err_union_ty.errorUnionSet().errorSetIsEmpty(mod)) { + if (!err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { // Block we can jump out of when error is not set try func.startBlock(.block, wasm.block_empty); @@ -6742,7 +6742,7 @@ fn callIntrinsic( if (!return_type.hasRuntimeBitsIgnoreComptime(mod)) { return WValue.none; - } else if (return_type.isNoReturn()) { + } else if (return_type.isNoReturn(mod)) { try func.addTag(.@"unreachable"); return WValue.none; } else if (want_sret_param) { @@ -6941,20 +6941,21 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { } fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { + const mod = func.bin_file.base.options.module.?; const ty_op = func.air.instructions.items(.data)[inst].ty_op; const operand = try func.resolveInst(ty_op.operand); const error_set_ty = func.air.getRefType(ty_op.ty); const result = try func.allocLocal(Type.bool); - const names = error_set_ty.errorSetNames(); + const names = error_set_ty.errorSetNames(mod); var values = try std.ArrayList(u32).initCapacity(func.gpa, names.len); defer values.deinit(); - const mod = func.bin_file.base.options.module.?; var lowest: ?u32 = null; var highest: ?u32 = null; - for (names) |name| { + for (names) |name_ip| { + const name = mod.intern_pool.stringToSlice(name_ip); const err_int = mod.global_error_set.get(name).?; if (lowest) |*l| { if (err_int < l.*) { diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index e83644269f..77b4e6d425 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -3612,8 +3612,8 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { const mod = self.bin_file.options.module.?; const ty_op = self.air.instructions.items(.data)[inst].ty_op; const err_union_ty = self.typeOf(ty_op.operand); - const err_ty = err_union_ty.errorUnionSet(); - const payload_ty = err_union_ty.errorUnionPayload(); + const err_ty = err_union_ty.errorUnionSet(mod); + const payload_ty = err_union_ty.errorUnionPayload(mod); const operand = try self.resolveInst(ty_op.operand); const result: MCValue = result: { @@ -3671,7 +3671,7 @@ fn genUnwrapErrorUnionPayloadMir( err_union: MCValue, ) !MCValue { const mod = self.bin_file.options.module.?; - const payload_ty = err_union_ty.errorUnionPayload(); + const payload_ty = err_union_ty.errorUnionPayload(mod); const result: MCValue = result: { if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) break :result .none; @@ -3731,8 +3731,8 @@ fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void { defer self.register_manager.unlockReg(dst_lock); const eu_ty = src_ty.childType(mod); - const pl_ty = eu_ty.errorUnionPayload(); - const err_ty = eu_ty.errorUnionSet(); + const pl_ty = eu_ty.errorUnionPayload(mod); + const err_ty = eu_ty.errorUnionSet(mod); const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, mod)); const err_abi_size = @intCast(u32, err_ty.abiSize(mod)); try self.asmRegisterMemory( @@ -3771,7 +3771,7 @@ fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); const eu_ty = src_ty.childType(mod); - const pl_ty = eu_ty.errorUnionPayload(); + const pl_ty = eu_ty.errorUnionPayload(mod); const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, mod)); const dst_abi_size = @intCast(u32, dst_ty.abiSize(mod)); try self.asmRegisterMemory( @@ -3797,8 +3797,8 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { defer self.register_manager.unlockReg(src_lock); const eu_ty = src_ty.childType(mod); - const pl_ty = eu_ty.errorUnionPayload(); - const err_ty = eu_ty.errorUnionSet(); + const pl_ty = eu_ty.errorUnionPayload(mod); + const err_ty = eu_ty.errorUnionSet(mod); const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, mod)); const err_abi_size = @intCast(u32, err_ty.abiSize(mod)); try self.asmMemoryImmediate( @@ -3901,8 +3901,8 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; const eu_ty = self.air.getRefType(ty_op.ty); - const pl_ty = eu_ty.errorUnionPayload(); - const err_ty = eu_ty.errorUnionSet(); + const pl_ty = eu_ty.errorUnionPayload(mod); + const err_ty = eu_ty.errorUnionSet(mod); const operand = try self.resolveInst(ty_op.operand); const result: MCValue = result: { @@ -3924,8 +3924,8 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; const eu_ty = self.air.getRefType(ty_op.ty); - const pl_ty = eu_ty.errorUnionPayload(); - const err_ty = eu_ty.errorUnionSet(); + const pl_ty = eu_ty.errorUnionPayload(mod); + const err_ty = eu_ty.errorUnionSet(mod); const result: MCValue = result: { if (!pl_ty.hasRuntimeBitsIgnoreComptime(mod)) break :result try self.resolveInst(ty_op.operand); @@ -8782,7 +8782,7 @@ fn isNullPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, ty: Type, operand: MCValue) !MCValue { const mod = self.bin_file.options.module.?; - const err_type = ty.errorUnionSet(); + const err_type = ty.errorUnionSet(mod); if (err_type.errorSetIsEmpty(mod)) { return MCValue{ .immediate = 0 }; // always false @@ -8793,7 +8793,7 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, ty: Type, operand: MCValue) ! self.eflags_inst = inst; } - const err_off = errUnionErrorOffset(ty.errorUnionPayload(), mod); + const err_off = errUnionErrorOffset(ty.errorUnionPayload(mod), mod); switch (operand) { .register => |reg| { const eu_lock = self.register_manager.lockReg(reg); diff --git a/src/codegen.zig b/src/codegen.zig index 8e145a3b32..775eb09ab0 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -139,7 +139,7 @@ pub fn generateLazySymbol( return generateLazyFunction(bin_file, src_loc, lazy_sym, code, debug_output); } - if (lazy_sym.ty.isAnyError()) { + if (lazy_sym.ty.isAnyError(mod)) { alignment.* = 4; const err_names = mod.error_name_list.items; mem.writeInt(u32, try code.addManyAsArray(4), @intCast(u32, err_names.len), endian); @@ -670,8 +670,8 @@ pub fn generateSymbol( return Result.ok; }, .ErrorUnion => { - const error_ty = typed_value.ty.errorUnionSet(); - const payload_ty = typed_value.ty.errorUnionPayload(); + const error_ty = typed_value.ty.errorUnionSet(mod); + const payload_ty = typed_value.ty.errorUnionPayload(mod); const is_payload = typed_value.val.errorUnionIsPayload(); if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { @@ -894,7 +894,7 @@ fn lowerParentPtr( }, .eu_payload_ptr => { const eu_payload_ptr = parent_ptr.castTag(.eu_payload_ptr).?.data; - const pl_ty = eu_payload_ptr.container_ty.errorUnionPayload(); + const pl_ty = eu_payload_ptr.container_ty.errorUnionPayload(mod); return lowerParentPtr( bin_file, src_loc, @@ -1249,8 +1249,8 @@ pub fn genTypedValue( } }, .ErrorUnion => { - const error_type = typed_value.ty.errorUnionSet(); - const payload_type = typed_value.ty.errorUnionPayload(); + const error_type = typed_value.ty.errorUnionSet(mod); + const payload_type = typed_value.ty.errorUnionPayload(mod); const is_pl = typed_value.val.errorUnionIsPayload(); if (!payload_type.hasRuntimeBitsIgnoreComptime(mod)) { diff --git a/src/codegen/c.zig b/src/codegen/c.zig index c2a108d68e..c9cc485903 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -465,7 +465,7 @@ pub const Function = struct { }), }, .data = switch (key) { - .tag_name => .{ .tag_name = try data.tag_name.copy(arena) }, + .tag_name => .{ .tag_name = data.tag_name }, .never_tail => .{ .never_tail = data.never_tail }, .never_inline => .{ .never_inline = data.never_inline }, }, @@ -862,8 +862,8 @@ pub const DeclGen = struct { return writer.writeByte('}'); }, .ErrorUnion => { - const payload_ty = ty.errorUnionPayload(); - const error_ty = ty.errorUnionSet(); + const payload_ty = ty.errorUnionPayload(mod); + const error_ty = ty.errorUnionSet(mod); if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { return dg.renderValue(writer, error_ty, val, location); @@ -1252,8 +1252,8 @@ pub const DeclGen = struct { } }, .ErrorUnion => { - const payload_ty = ty.errorUnionPayload(); - const error_ty = ty.errorUnionSet(); + const payload_ty = ty.errorUnionPayload(mod); + const error_ty = ty.errorUnionSet(mod); const error_val = if (val.errorUnionIsPayload()) try mod.intValue(Type.anyerror, 0) else val; if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { @@ -4252,6 +4252,7 @@ fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue { } fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue { + const mod = f.object.dg.module; const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; const extra = f.air.extraData(Air.Block, ty_pl.payload); const body = f.air.extra[extra.end..][0..extra.data.body_len]; @@ -4284,7 +4285,7 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue { try f.object.indent_writer.insertNewline(); // noreturn blocks have no `br` instructions reaching them, so we don't want a label - if (!f.typeOfIndex(inst).isNoReturn()) { + if (!f.typeOfIndex(inst).isNoReturn(mod)) { // label must be followed by an expression, include an empty one. try writer.print("zig_block_{d}:;\n", .{block_id}); } @@ -4322,10 +4323,10 @@ fn lowerTry( const inst_ty = f.typeOfIndex(inst); const liveness_condbr = f.liveness.getCondBr(inst); const writer = f.object.writer(); - const payload_ty = err_union_ty.errorUnionPayload(); + const payload_ty = err_union_ty.errorUnionPayload(mod); const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(mod); - if (!err_union_ty.errorUnionSet().errorSetIsEmpty(mod)) { + if (!err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { try writer.writeAll("if ("); if (!payload_has_bits) { if (is_ptr) @@ -5500,8 +5501,8 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { const operand_is_ptr = operand_ty.zigTypeTag(mod) == .Pointer; const error_union_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty; - const error_ty = error_union_ty.errorUnionSet(); - const payload_ty = error_union_ty.errorUnionPayload(); + const error_ty = error_union_ty.errorUnionSet(mod); + const payload_ty = error_union_ty.errorUnionPayload(mod); const local = try f.allocLocal(inst, inst_ty); if (!payload_ty.hasRuntimeBits(mod) and operand == .local and operand.local == local.new_local) { @@ -5539,7 +5540,7 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu const error_union_ty = if (is_ptr) operand_ty.childType(mod) else operand_ty; const writer = f.object.writer(); - if (!error_union_ty.errorUnionPayload().hasRuntimeBits(mod)) { + if (!error_union_ty.errorUnionPayload(mod).hasRuntimeBits(mod)) { if (!is_ptr) return .none; const local = try f.allocLocal(inst, inst_ty); @@ -5601,9 +5602,9 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { const ty_op = f.air.instructions.items(.data)[inst].ty_op; const inst_ty = f.typeOfIndex(inst); - const payload_ty = inst_ty.errorUnionPayload(); + const payload_ty = inst_ty.errorUnionPayload(mod); const repr_is_err = !payload_ty.hasRuntimeBitsIgnoreComptime(mod); - const err_ty = inst_ty.errorUnionSet(); + const err_ty = inst_ty.errorUnionSet(mod); const err = try f.resolveInst(ty_op.operand); try reap(f, inst, &.{ty_op.operand}); @@ -5642,8 +5643,8 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { const operand = try f.resolveInst(ty_op.operand); const error_union_ty = f.typeOf(ty_op.operand).childType(mod); - const error_ty = error_union_ty.errorUnionSet(); - const payload_ty = error_union_ty.errorUnionPayload(); + const error_ty = error_union_ty.errorUnionSet(mod); + const payload_ty = error_union_ty.errorUnionPayload(mod); // First, set the non-error value. if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { @@ -5691,10 +5692,10 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { const ty_op = f.air.instructions.items(.data)[inst].ty_op; const inst_ty = f.typeOfIndex(inst); - const payload_ty = inst_ty.errorUnionPayload(); + const payload_ty = inst_ty.errorUnionPayload(mod); const payload = try f.resolveInst(ty_op.operand); const repr_is_err = !payload_ty.hasRuntimeBitsIgnoreComptime(mod); - const err_ty = inst_ty.errorUnionSet(); + const err_ty = inst_ty.errorUnionSet(mod); try reap(f, inst, &.{ty_op.operand}); const writer = f.object.writer(); @@ -5729,8 +5730,8 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const const operand_ty = f.typeOf(un_op); const local = try f.allocLocal(inst, Type.bool); const err_union_ty = if (is_ptr) operand_ty.childType(mod) else operand_ty; - const payload_ty = err_union_ty.errorUnionPayload(); - const error_ty = err_union_ty.errorUnionSet(); + const payload_ty = err_union_ty.errorUnionPayload(mod); + const error_ty = err_union_ty.errorUnionSet(mod); try f.writeCValue(writer, local, .Other); try writer.writeAll(" = "); diff --git a/src/codegen/c/type.zig b/src/codegen/c/type.zig index 70426972af..dc1749d42e 100644 --- a/src/codegen/c/type.zig +++ b/src/codegen/c/type.zig @@ -1680,14 +1680,14 @@ pub const CType = extern union { .complete, .parameter, .global => try lookup.typeToIndex(ty, .forward), .payload => unreachable, }) |fwd_idx| { - const payload_ty = ty.errorUnionPayload(); + const payload_ty = ty.errorUnionPayload(mod); if (try lookup.typeToIndex(payload_ty, switch (kind) { .forward, .forward_parameter => .forward, .complete, .parameter => .complete, .global => .global, .payload => unreachable, })) |payload_idx| { - const error_ty = ty.errorUnionSet(); + const error_ty = ty.errorUnionSet(mod); if (payload_idx == Tag.void.toIndex()) { try self.initType(error_ty, kind, lookup); } else if (try lookup.typeToIndex(error_ty, kind)) |error_idx| { diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 0c503edee4..1da3d91b13 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -362,15 +362,11 @@ pub const Object = struct { decl_map: std.AutoHashMapUnmanaged(Module.Decl.Index, *llvm.Value), /// Serves the same purpose as `decl_map` but only used for the `is_named_enum_value` instruction. named_enum_map: std.AutoHashMapUnmanaged(Module.Decl.Index, *llvm.Value), - /// Maps Zig types to LLVM types. The table memory itself is backed by the GPA of - /// the compiler, but the Type/Value memory here is backed by `type_map_arena`. - /// TODO we need to remove entries from this map in response to incremental compilation - /// but I think the frontend won't tell us about types that get deleted because - /// hasRuntimeBits() is false for types. + /// Maps Zig types to LLVM types. The table memory is backed by the GPA of + /// the compiler. + /// TODO when InternPool garbage collection is implemented, this map needs + /// to be garbage collected as well. type_map: TypeMap, - /// The backing memory for `type_map`. Periodically garbage collected after flush(). - /// The code for doing the periodical GC is not yet implemented. - type_map_arena: std.heap.ArenaAllocator, di_type_map: DITypeMap, /// The LLVM global table which holds the names corresponding to Zig errors. /// Note that the values are not added until flushModule, when all errors in @@ -381,12 +377,7 @@ pub const Object = struct { /// name collision. extern_collisions: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void), - pub const TypeMap = std.HashMapUnmanaged( - Type, - *llvm.Type, - Type.HashContext64, - std.hash_map.default_max_load_percentage, - ); + pub const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, *llvm.Type); /// This is an ArrayHashMap as opposed to a HashMap because in `flushModule` we /// want to iterate over it while adding entries to it. @@ -543,7 +534,6 @@ pub const Object = struct { .decl_map = .{}, .named_enum_map = .{}, .type_map = .{}, - .type_map_arena = std.heap.ArenaAllocator.init(gpa), .di_type_map = .{}, .error_name_table = null, .extern_collisions = .{}, @@ -563,7 +553,6 @@ pub const Object = struct { self.decl_map.deinit(gpa); self.named_enum_map.deinit(gpa); self.type_map.deinit(gpa); - self.type_map_arena.deinit(); self.extern_collisions.deinit(gpa); self.* = undefined; } @@ -1462,9 +1451,6 @@ pub const Object = struct { return o.lowerDebugTypeImpl(entry, resolve, di_type); } errdefer assert(o.di_type_map.orderedRemoveContext(ty, .{ .mod = o.module })); - // The Type memory is ephemeral; since we want to store a longer-lived - // reference, we need to copy it here. - gop.key_ptr.* = try ty.copy(o.type_map_arena.allocator()); const entry: Object.DITypeMap.Entry = .{ .key_ptr = gop.key_ptr, .value_ptr = gop.value_ptr, @@ -1868,7 +1854,7 @@ pub const Object = struct { return full_di_ty; }, .ErrorUnion => { - const payload_ty = ty.errorUnionPayload(); + const payload_ty = ty.errorUnionPayload(mod); if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { const err_set_di_ty = try o.lowerDebugType(Type.anyerror, .full); // The recursive call to `lowerDebugType` means we can't use `gop` anymore. @@ -2823,7 +2809,7 @@ pub const DeclGen = struct { .Opaque => { if (t.ip_index == .anyopaque_type) return dg.context.intType(8); - const gop = try dg.object.type_map.getOrPutContext(gpa, t, .{ .mod = mod }); + const gop = try dg.object.type_map.getOrPut(gpa, t.toIntern()); if (gop.found_existing) return gop.value_ptr.*; const opaque_type = mod.intern_pool.indexToKey(t.ip_index).opaque_type; @@ -2869,7 +2855,7 @@ pub const DeclGen = struct { return dg.context.structType(&fields_buf, 3, .False); }, .ErrorUnion => { - const payload_ty = t.errorUnionPayload(); + const payload_ty = t.errorUnionPayload(mod); if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { return try dg.lowerType(Type.anyerror); } @@ -2913,13 +2899,9 @@ pub const DeclGen = struct { }, .ErrorSet => return dg.context.intType(16), .Struct => { - const gop = try dg.object.type_map.getOrPutContext(gpa, t, .{ .mod = mod }); + const gop = try dg.object.type_map.getOrPut(gpa, t.toIntern()); if (gop.found_existing) return gop.value_ptr.*; - // The Type memory is ephemeral; since we want to store a longer-lived - // reference, we need to copy it here. - gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator()); - const struct_type = switch (mod.intern_pool.indexToKey(t.ip_index)) { .anon_struct_type => |tuple| { const llvm_struct_ty = dg.context.structCreateNamed(""); @@ -3041,13 +3023,9 @@ pub const DeclGen = struct { return llvm_struct_ty; }, .Union => { - const gop = try dg.object.type_map.getOrPutContext(gpa, t, .{ .mod = mod }); + const gop = try dg.object.type_map.getOrPut(gpa, t.toIntern()); if (gop.found_existing) return gop.value_ptr.*; - // The Type memory is ephemeral; since we want to store a longer-lived - // reference, we need to copy it here. - gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator()); - const layout = t.unionGetLayout(mod); const union_obj = mod.typeToUnion(t).?; @@ -3571,7 +3549,7 @@ pub const DeclGen = struct { } }, .ErrorUnion => { - const payload_type = tv.ty.errorUnionPayload(); + const payload_type = tv.ty.errorUnionPayload(mod); const is_pl = tv.val.errorUnionIsPayload(); if (!payload_type.hasRuntimeBitsIgnoreComptime(mod)) { @@ -4130,7 +4108,7 @@ pub const DeclGen = struct { const eu_payload_ptr = ptr_val.castTag(.eu_payload_ptr).?.data; const parent_llvm_ptr = try dg.lowerParentPtr(eu_payload_ptr.container_ptr, true); - const payload_ty = eu_payload_ptr.container_ty.errorUnionPayload(); + const payload_ty = eu_payload_ptr.container_ty.errorUnionPayload(mod); if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { // In this case, we represent pointer to error union the same as pointer // to the payload. @@ -5368,7 +5346,7 @@ pub const FuncGen = struct { const inst_ty = self.typeOfIndex(inst); const parent_bb = self.context.createBasicBlock("Block"); - if (inst_ty.isNoReturn()) { + if (inst_ty.isNoReturn(mod)) { try self.genBody(body); return null; } @@ -5490,11 +5468,11 @@ pub const FuncGen = struct { is_unused: bool, ) !?*llvm.Value { const mod = fg.dg.module; - const payload_ty = err_union_ty.errorUnionPayload(); + const payload_ty = err_union_ty.errorUnionPayload(mod); const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(mod); const err_union_llvm_ty = try fg.dg.lowerType(err_union_ty); - if (!err_union_ty.errorUnionSet().errorSetIsEmpty(mod)) { + if (!err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { const is_err = err: { const err_set_ty = try fg.dg.lowerType(Type.anyerror); const zero = err_set_ty.constNull(); @@ -5601,6 +5579,7 @@ pub const FuncGen = struct { } fn airLoop(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { + const mod = self.dg.module; const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; const loop = self.air.extraData(Air.Block, ty_pl.payload); const body = self.air.extra[loop.end..][0..loop.data.body_len]; @@ -5616,7 +5595,7 @@ pub const FuncGen = struct { // would have been emitted already. Also the main loop in genBody can // be while(true) instead of for(body), which will eliminate 1 branch on // a hot path. - if (body.len == 0 or !self.typeOfIndex(body[body.len - 1]).isNoReturn()) { + if (body.len == 0 or !self.typeOfIndex(body[body.len - 1]).isNoReturn(mod)) { _ = self.builder.buildBr(loop_block); } return null; @@ -6674,11 +6653,11 @@ pub const FuncGen = struct { const operand = try self.resolveInst(un_op); const operand_ty = self.typeOf(un_op); const err_union_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty; - const payload_ty = err_union_ty.errorUnionPayload(); + const payload_ty = err_union_ty.errorUnionPayload(mod); const err_set_ty = try self.dg.lowerType(Type.anyerror); const zero = err_set_ty.constNull(); - if (err_union_ty.errorUnionSet().errorSetIsEmpty(mod)) { + if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { const llvm_i1 = self.context.intType(1); switch (op) { .EQ => return llvm_i1.constInt(1, .False), // 0 == 0 @@ -6825,7 +6804,7 @@ pub const FuncGen = struct { const operand = try self.resolveInst(ty_op.operand); const operand_ty = self.typeOf(ty_op.operand); const err_union_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty; - if (err_union_ty.errorUnionSet().errorSetIsEmpty(mod)) { + if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { const err_llvm_ty = try self.dg.lowerType(Type.anyerror); if (operand_is_ptr) { return operand; @@ -6836,7 +6815,7 @@ pub const FuncGen = struct { const err_set_llvm_ty = try self.dg.lowerType(Type.anyerror); - const payload_ty = err_union_ty.errorUnionPayload(); + const payload_ty = err_union_ty.errorUnionPayload(mod); if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { if (!operand_is_ptr) return operand; return self.builder.buildLoad(err_set_llvm_ty, operand, ""); @@ -6859,7 +6838,7 @@ pub const FuncGen = struct { const operand = try self.resolveInst(ty_op.operand); const err_union_ty = self.typeOf(ty_op.operand).childType(mod); - const payload_ty = err_union_ty.errorUnionPayload(); + const payload_ty = err_union_ty.errorUnionPayload(mod); const non_error_val = try self.dg.lowerValue(.{ .ty = Type.anyerror, .val = try mod.intValue(Type.err_int, 0) }); if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { _ = self.builder.buildStore(non_error_val, operand); @@ -6968,7 +6947,7 @@ pub const FuncGen = struct { const mod = self.dg.module; const ty_op = self.air.instructions.items(.data)[inst].ty_op; const err_un_ty = self.typeOfIndex(inst); - const payload_ty = err_un_ty.errorUnionPayload(); + const payload_ty = err_un_ty.errorUnionPayload(mod); const operand = try self.resolveInst(ty_op.operand); if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { return operand; @@ -8787,13 +8766,14 @@ pub const FuncGen = struct { const operand = try self.resolveInst(ty_op.operand); const error_set_ty = self.air.getRefType(ty_op.ty); - const names = error_set_ty.errorSetNames(); + const names = error_set_ty.errorSetNames(mod); const valid_block = self.context.appendBasicBlock(self.llvm_func, "Valid"); const invalid_block = self.context.appendBasicBlock(self.llvm_func, "Invalid"); const end_block = self.context.appendBasicBlock(self.llvm_func, "End"); const switch_instr = self.builder.buildSwitch(operand, invalid_block, @intCast(c_uint, names.len)); - for (names) |name| { + for (names) |name_ip| { + const name = mod.intern_pool.stringToSlice(name_ip); const err_int = mod.global_error_set.get(name).?; const this_tag_int_value = try self.dg.lowerValue(.{ .ty = Type.err_int, @@ -11095,7 +11075,7 @@ fn isByRef(ty: Type, mod: *Module) bool { else => return ty.hasRuntimeBits(mod), }, .ErrorUnion => { - const payload_ty = ty.errorUnionPayload(); + const payload_ty = ty.errorUnionPayload(mod); if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { return false; } diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index eada74e6d4..612ac1f252 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -801,7 +801,7 @@ pub const DeclGen = struct { }, }, .ErrorUnion => { - const payload_ty = ty.errorUnionPayload(); + const payload_ty = ty.errorUnionPayload(mod); const is_pl = val.errorUnionIsPayload(); const error_val = if (!is_pl) val else try mod.intValue(Type.anyerror, 0); @@ -1365,7 +1365,7 @@ pub const DeclGen = struct { .Union => return try self.resolveUnionType(ty, null), .ErrorSet => return try self.intType(.unsigned, 16), .ErrorUnion => { - const payload_ty = ty.errorUnionPayload(); + const payload_ty = ty.errorUnionPayload(mod); const error_ty_ref = try self.resolveType(Type.anyerror, .indirect); const eu_layout = self.errorUnionLayout(payload_ty); @@ -2875,7 +2875,7 @@ pub const DeclGen = struct { const eu_layout = self.errorUnionLayout(payload_ty); - if (!err_union_ty.errorUnionSet().errorSetIsEmpty(mod)) { + if (!err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { const err_id = if (eu_layout.payload_has_bits) try self.extractField(Type.anyerror, err_union_id, eu_layout.errorFieldIndex()) else @@ -2929,12 +2929,12 @@ pub const DeclGen = struct { const err_union_ty = self.typeOf(ty_op.operand); const err_ty_ref = try self.resolveType(Type.anyerror, .direct); - if (err_union_ty.errorUnionSet().errorSetIsEmpty(mod)) { + if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { // No error possible, so just return undefined. return try self.spv.constUndef(err_ty_ref); } - const payload_ty = err_union_ty.errorUnionPayload(); + const payload_ty = err_union_ty.errorUnionPayload(mod); const eu_layout = self.errorUnionLayout(payload_ty); if (!eu_layout.payload_has_bits) { @@ -2948,9 +2948,10 @@ pub const DeclGen = struct { fn airWrapErrUnionErr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { if (self.liveness.isUnused(inst)) return null; + const mod = self.module; const ty_op = self.air.instructions.items(.data)[inst].ty_op; const err_union_ty = self.typeOfIndex(inst); - const payload_ty = err_union_ty.errorUnionPayload(); + const payload_ty = err_union_ty.errorUnionPayload(mod); const operand_id = try self.resolve(ty_op.operand); const eu_layout = self.errorUnionLayout(payload_ty); diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index f4f19f30d0..4d8e865622 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -18,6 +18,7 @@ const LinkBlock = File.LinkBlock; const LinkFn = File.LinkFn; const LinkerLoad = @import("../codegen.zig").LinkerLoad; const Module = @import("../Module.zig"); +const InternPool = @import("../InternPool.zig"); const StringTable = @import("strtab.zig").StringTable; const Type = @import("../type.zig").Type; const Value = @import("../value.zig").Value; @@ -518,9 +519,9 @@ pub const DeclState = struct { ); }, .ErrorUnion => { - const error_ty = ty.errorUnionSet(); - const payload_ty = ty.errorUnionPayload(); - const payload_align = if (payload_ty.isNoReturn()) 0 else payload_ty.abiAlignment(mod); + const error_ty = ty.errorUnionSet(mod); + const payload_ty = ty.errorUnionPayload(mod); + const payload_align = if (payload_ty.isNoReturn(mod)) 0 else payload_ty.abiAlignment(mod); const error_align = Type.anyerror.abiAlignment(mod); const abi_size = ty.abiSize(mod); const payload_off = if (error_align >= payload_align) Type.anyerror.abiSize(mod) else 0; @@ -534,7 +535,7 @@ pub const DeclState = struct { const name = try ty.nameAllocArena(arena, mod); try dbg_info_buffer.writer().print("{s}\x00", .{name}); - if (!payload_ty.isNoReturn()) { + if (!payload_ty.isNoReturn(mod)) { // DW.AT.member try dbg_info_buffer.ensureUnusedCapacity(7); dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member)); @@ -1266,10 +1267,11 @@ pub fn commitDeclState( const symbol = &decl_state.abbrev_table.items[sym_index]; const ty = symbol.type; const deferred: bool = blk: { - if (ty.isAnyError()) break :blk true; - switch (ty.tag()) { - .error_set_inferred => { - if (!ty.castTag(.error_set_inferred).?.data.is_resolved) break :blk true; + if (ty.isAnyError(mod)) break :blk true; + switch (mod.intern_pool.indexToKey(ty.ip_index)) { + .inferred_error_set_type => |ies_index| { + const ies = mod.inferredErrorSetPtr(ies_index); + if (!ies.is_resolved) break :blk true; }, else => {}, } @@ -1290,10 +1292,11 @@ pub fn commitDeclState( const symbol = decl_state.abbrev_table.items[target]; const ty = symbol.type; const deferred: bool = blk: { - if (ty.isAnyError()) break :blk true; - switch (ty.tag()) { - .error_set_inferred => { - if (!ty.castTag(.error_set_inferred).?.data.is_resolved) break :blk true; + if (ty.isAnyError(mod)) break :blk true; + switch (mod.intern_pool.indexToKey(ty.ip_index)) { + .inferred_error_set_type => |ies_index| { + const ies = mod.inferredErrorSetPtr(ies_index); + if (!ies.is_resolved) break :blk true; }, else => {}, } @@ -2529,18 +2532,22 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void { defer arena_alloc.deinit(); const arena = arena_alloc.allocator(); - const error_set = try arena.create(Module.ErrorSet); - const error_ty = try Type.Tag.error_set.create(arena, error_set); - var names = Module.ErrorSet.NameMap{}; - try names.ensureUnusedCapacity(arena, module.global_error_set.count()); - var it = module.global_error_set.keyIterator(); - while (it.next()) |key| { - names.putAssumeCapacityNoClobber(key.*, {}); + // TODO: don't create a zig type for this, just make the dwarf info + // without touching the zig type system. + const names = try arena.alloc(InternPool.NullTerminatedString, module.global_error_set.count()); + { + var it = module.global_error_set.keyIterator(); + var i: usize = 0; + while (it.next()) |key| : (i += 1) { + names[i] = module.intern_pool.getString(key.*).unwrap().?; + } } - error_set.names = names; + std.mem.sort(InternPool.NullTerminatedString, names, {}, InternPool.NullTerminatedString.indexLessThan); + + const error_ty = try module.intern(.{ .error_set_type = .{ .names = names } }); var dbg_info_buffer = std.ArrayList(u8).init(arena); - try addDbgInfoErrorSet(arena, module, error_ty, self.target, &dbg_info_buffer); + try addDbgInfoErrorSet(arena, module, error_ty.toType(), self.target, &dbg_info_buffer); const di_atom_index = try self.createAtom(.di_atom); log.debug("updateDeclDebugInfoAllocation in flushModule", .{}); @@ -2684,8 +2691,9 @@ fn addDbgInfoErrorSet( // DW.AT.const_value, DW.FORM.data8 mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), 0, target_endian); - const error_names = ty.errorSetNames(); - for (error_names) |error_name| { + const error_names = ty.errorSetNames(mod); + for (error_names) |error_name_ip| { + const error_name = mod.intern_pool.stringToSlice(error_name_ip); const kv = mod.getErrorValue(error_name) catch unreachable; // DW.AT.enumerator try dbg_info_buffer.ensureUnusedCapacity(error_name.len + 2 + @sizeOf(u64)); diff --git a/src/print_air.zig b/src/print_air.zig index 8cff417770..0e4f2d16cf 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -370,7 +370,6 @@ const Writer = struct { .none => switch (ty.tag()) { .inferred_alloc_const => try s.writeAll("(inferred_alloc_const)"), .inferred_alloc_mut => try s.writeAll("(inferred_alloc_mut)"), - else => try ty.print(s, w.module), }, else => try ty.print(s, w.module), } 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); diff --git a/src/value.zig b/src/value.zig index 3100496085..4408d10231 100644 --- a/src/value.zig +++ b/src/value.zig @@ -260,7 +260,7 @@ pub const Value = struct { const new_payload = try arena.create(Payload.Ty); new_payload.* = .{ .base = payload.base, - .data = try payload.data.copy(arena), + .data = payload.data, }; return Value{ .ip_index = .none, @@ -281,7 +281,7 @@ pub const Value = struct { .base = payload.base, .data = .{ .container_ptr = try payload.data.container_ptr.copy(arena), - .container_ty = try payload.data.container_ty.copy(arena), + .container_ty = payload.data.container_ty, }, }; return Value{ @@ -296,7 +296,7 @@ pub const Value = struct { .base = payload.base, .data = .{ .field_val = try payload.data.field_val.copy(arena), - .field_ty = try payload.data.field_ty.copy(arena), + .field_ty = payload.data.field_ty, }, }; return Value{ @@ -311,7 +311,7 @@ pub const Value = struct { .base = payload.base, .data = .{ .array_ptr = try payload.data.array_ptr.copy(arena), - .elem_ty = try payload.data.elem_ty.copy(arena), + .elem_ty = payload.data.elem_ty, .index = payload.data.index, }, }; @@ -327,7 +327,7 @@ pub const Value = struct { .base = payload.base, .data = .{ .container_ptr = try payload.data.container_ptr.copy(arena), - .container_ty = try payload.data.container_ty.copy(arena), + .container_ty = payload.data.container_ty, .field_index = payload.data.field_index, }, }; @@ -1870,7 +1870,7 @@ pub const Value = struct { .eu_payload => { const a_payload = a.castTag(.eu_payload).?.data; const b_payload = b.castTag(.eu_payload).?.data; - const payload_ty = ty.errorUnionPayload(); + const payload_ty = ty.errorUnionPayload(mod); return eqlAdvanced(a_payload, payload_ty, b_payload, payload_ty, mod, opt_sema); }, .eu_payload_ptr => { @@ -2163,14 +2163,14 @@ pub const Value = struct { .ErrorUnion => { if (val.tag() == .@"error") { std.hash.autoHash(hasher, false); // error - const sub_ty = ty.errorUnionSet(); + const sub_ty = ty.errorUnionSet(mod); val.hash(sub_ty, hasher, mod); return; } if (val.castTag(.eu_payload)) |payload| { std.hash.autoHash(hasher, true); // payload - const sub_ty = ty.errorUnionPayload(); + const sub_ty = ty.errorUnionPayload(mod); payload.data.hash(sub_ty, hasher, mod); return; } else unreachable; @@ -2272,7 +2272,7 @@ pub const Value = struct { payload.data.hashUncoerced(child_ty, hasher, mod); } else std.hash.autoHash(hasher, std.builtin.TypeId.Null), .ErrorSet, .ErrorUnion => if (val.getError()) |err| hasher.update(err) else { - const pl_ty = ty.errorUnionPayload(); + const pl_ty = ty.errorUnionPayload(mod); val.castTag(.eu_payload).?.data.hashUncoerced(pl_ty, hasher, mod); }, .Enum, .EnumLiteral, .Union => { |
