aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2023-05-20 12:09:07 -0700
committerAndrew Kelley <andrew@ziglang.org>2023-06-10 20:47:53 -0700
commit9ff514b6a35b7201f45f8bff31c61b4f8cfa7a7a (patch)
treedda74acc00690d1b3d31fd6e43d7ec0aa4acc882 /src
parent7bf91fc79ac9e4eae575baf3a2ca9549bc3bf6c2 (diff)
downloadzig-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.zig2
-rw-r--r--src/InternPool.zig176
-rw-r--r--src/Liveness.zig2
-rw-r--r--src/Liveness/Verify.zig2
-rw-r--r--src/Module.zig169
-rw-r--r--src/Sema.zig821
-rw-r--r--src/TypedValue.zig6
-rw-r--r--src/arch/aarch64/CodeGen.zig18
-rw-r--r--src/arch/arm/CodeGen.zig18
-rw-r--r--src/arch/sparc64/CodeGen.zig20
-rw-r--r--src/arch/wasm/CodeGen.zig41
-rw-r--r--src/arch/x86_64/CodeGen.zig28
-rw-r--r--src/codegen.zig12
-rw-r--r--src/codegen/c.zig39
-rw-r--r--src/codegen/c/type.zig4
-rw-r--r--src/codegen/llvm.zig74
-rw-r--r--src/codegen/spirv.zig13
-rw-r--r--src/link/Dwarf.zig54
-rw-r--r--src/print_air.zig1
-rw-r--r--src/type.zig1251
-rw-r--r--src/value.zig18
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 => {