mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-05-04 00:32:40 +03:00
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:
+1
-1
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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(" = ");
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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));
|
||||
|
||||
@@ -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
@@ -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
@@ -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 => {
|
||||
|
||||
Reference in New Issue
Block a user