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.
This commit is contained in:
Andrew Kelley
2023-05-20 12:09:07 -07:00
parent 7bf91fc79a
commit 9ff514b6a3
21 changed files with 1187 additions and 1574 deletions
+1 -1
View File
@@ -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,
+160 -16
View File
@@ -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`.
@@ -1355,6 +1409,12 @@ pub const Tag = enum(u8) {
aggregate,
};
/// 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 {
@@ -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,
},
};
}
+1 -1
View File
@@ -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();
+1 -1
View File
@@ -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;
+94 -75
View File
@@ -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);
+377 -444
View File
@@ -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,
},
try sema.resolveInferredErrorSet(block, src_src, src_data);
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_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),
.missing_error = try sema.arena.dupe(InternPool.NullTerminatedString, 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)) {
.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),
};
}
return .ok;
},
.error_set => {
const names = src_ty.castTag(.error_set).?.data.names.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),
};
}
@@ -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: {
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 n = dest_err_set_ty.castTag(.error_set_single).?.data;
if (mem.eql(u8, expected_name, n)) break :ok;
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_error_set_type => |ies_index| ok: {
const ies = mod.inferredErrorSetPtr(ies_index);
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);
}
},
.error_set_inferred => ok: {
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());
}
+3 -3
View File
@@ -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;
+9 -9
View File
@@ -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
+9 -9
View File
@@ -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
+10 -10
View File
@@ -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
+21 -20
View File
@@ -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.*) {
+14 -14
View File
@@ -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);
+6 -6
View File
@@ -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)) {
+20 -19
View File
@@ -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(" = ");
+2 -2
View File
@@ -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| {
+27 -47
View File
@@ -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;
}
+7 -6
View File
@@ -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);
+31 -23
View File
@@ -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));
-1
View File
@@ -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),
}
+385 -858
View File
@@ -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
.error_union => {
// Optionals and error unions are not packed so their bitsize
// includes padding bits.
return (try abiSizeAdvanced(ty, mod, strat)).scalar * 8;
},
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,
},
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(),
.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,
.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;
},
.usize,
.isize,
=> return target.ptrBitWidth(),
// TODO revisit this when we have the concept of the error tag type
.error_set_type, .inferred_error_set_type => return 16,
.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),
.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,
.bool => return 1,
.void => return 0,
.usize,
.isize,
=> return target.ptrBitWidth(),
// TODO revisit this when we have the concept of the error tag type
.anyerror => return 16,
.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),
.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,
.bool => return 1,
.void => return 0,
.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);
},
// TODO revisit this when we have the concept of the error tag type
.anyerror => return 16,
.anon_struct_type => {
if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty);
.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;
},
.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());
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,
}
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);
return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
},
.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());
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;
}
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,
},
};
}
switch (ty.tag()) {
.error_set_single => {
const data = ty.castTag(.error_set_single).?.data;
return std.mem.eql(u8, data, 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,
},
.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);
},
.error_set => {
const data = ty.castTag(.error_set).?.data;
return data.names.contains(name);
},
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);
+9 -9
View File
@@ -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 => {