Commit 8f9d857932
src/Sema.zig
@@ -4554,9 +4554,7 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
if (lhs_ty.tag() == .anyerror or rhs_ty.tag() == .anyerror) {
return Air.Inst.Ref.anyerror_type;
}
- // When we support inferred error sets, we'll want to use a data structure that can
- // represent a merged set of errors without forcing them to be resolved here. Until then
- // we re-use the same data structure that is used for explicit error set declarations.
+ // Resolve both error sets now.
var set: std.StringHashMapUnmanaged(void) = .{};
defer set.deinit(sema.gpa);
@@ -4565,6 +4563,12 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
const name = lhs_ty.castTag(.error_set_single).?.data;
try set.put(sema.gpa, name, {});
},
+ .error_set_merged => {
+ const names = lhs_ty.castTag(.error_set_merged).?.data;
+ for (names) |name| {
+ try set.put(sema.gpa, name, {});
+ }
+ },
.error_set => {
const lhs_set = lhs_ty.castTag(.error_set).?.data;
try set.ensureUnusedCapacity(sema.gpa, lhs_set.names_len);
@@ -4579,6 +4583,12 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
const name = rhs_ty.castTag(.error_set_single).?.data;
try set.put(sema.gpa, name, {});
},
+ .error_set_merged => {
+ const names = rhs_ty.castTag(.error_set_merged).?.data;
+ for (names) |name| {
+ try set.put(sema.gpa, name, {});
+ }
+ },
.error_set => {
const rhs_set = rhs_ty.castTag(.error_set).?.data;
try set.ensureUnusedCapacity(sema.gpa, rhs_set.names_len);
@@ -4589,22 +4599,25 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
else => unreachable,
}
- const new_names = try sema.arena.alloc([]const u8, set.count());
+ // TODO do we really want to create a Decl for this?
+ // The reason we do it right now is for memory management.
+ var anon_decl = try block.startAnonDecl();
+ defer anon_decl.deinit();
+
+ const new_names = try anon_decl.arena().alloc([]const u8, set.count());
var it = set.keyIterator();
var i: usize = 0;
while (it.next()) |key| : (i += 1) {
new_names[i] = key.*;
}
- const new_error_set = try sema.arena.create(Module.ErrorSet);
- new_error_set.* = .{
- .owner_decl = sema.owner_decl,
- .node_offset = inst_data.src_node,
- .names_ptr = new_names.ptr,
- .names_len = @intCast(u32, new_names.len),
- };
- const error_set_ty = try Type.Tag.error_set.create(sema.arena, new_error_set);
- return sema.addConstant(Type.type, try Value.Tag.ty.create(sema.arena, error_set_ty));
+ const err_set_ty = try Type.Tag.error_set_merged.create(anon_decl.arena(), new_names);
+ const err_set_decl = try anon_decl.finish(
+ Type.type,
+ try Value.Tag.ty.create(anon_decl.arena(), err_set_ty),
+ );
+ try sema.mod.declareDeclDependency(sema.owner_decl, err_set_decl);
+ return sema.addType(err_set_ty);
}
fn zirEnumLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -14788,6 +14801,7 @@ fn typeHasOnePossibleValue(
.error_set,
.error_set_single,
.error_set_inferred,
+ .error_set_merged,
.@"opaque",
.var_args_param,
.manyptr_u8,
src/type.zig
@@ -61,11 +61,17 @@ pub const Type = extern union {
.c_longdouble,
=> return .Float,
+ .error_set,
+ .error_set_single,
+ .anyerror,
+ .error_set_inferred,
+ .error_set_merged,
+ => return .ErrorSet,
+
.c_void, .@"opaque" => return .Opaque,
.bool => return .Bool,
.void => return .Void,
.type => return .Type,
- .error_set, .error_set_single, .anyerror, .error_set_inferred => return .ErrorSet,
.comptime_int => return .ComptimeInt,
.comptime_float => return .ComptimeFloat,
.noreturn => return .NoReturn,
@@ -608,6 +614,9 @@ pub const Type = extern union {
return true;
},
.ErrorSet => {
+ // TODO: revisit the language specification for how to evaluate equality
+ // for error set types.
+
if (a.tag() == .anyerror and b.tag() == .anyerror) {
return true;
}
@@ -892,6 +901,14 @@ pub const Type = extern union {
.payload = try payload.payload.copy(allocator),
});
},
+ .error_set_merged => {
+ const names = self.castTag(.error_set_merged).?.data;
+ const duped_names = try allocator.alloc([]const u8, names.len);
+ for (duped_names) |*name, i| {
+ name.* = try allocator.dupe(u8, names[i]);
+ }
+ 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),
@@ -1185,6 +1202,16 @@ pub const Type = extern union {
const func = ty.castTag(.error_set_inferred).?.data.func;
return writer.print("(inferred error set of {s})", .{func.owner_decl.name});
},
+ .error_set_merged => {
+ const names = ty.castTag(.error_set_merged).?.data;
+ try writer.writeAll("error{");
+ for (names) |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});
@@ -1365,6 +1392,7 @@ pub const Type = extern union {
.error_set,
.error_set_single,
.error_set_inferred,
+ .error_set_merged,
.@"opaque",
.generic_poison,
.array_u8,
@@ -1525,6 +1553,7 @@ pub const Type = extern union {
.error_set,
.error_set_single,
.error_set_inferred,
+ .error_set_merged,
.manyptr_u8,
.manyptr_const_u8,
.atomic_order,
@@ -1783,6 +1812,7 @@ pub const Type = extern union {
.anyerror_void_error_union,
.anyerror,
.error_set_inferred,
+ .error_set_merged,
=> return 2, // TODO revisit this when we have the concept of the error tag type
.array, .array_sentinel => return self.elemType().abiAlignment(target),
@@ -2021,6 +2051,7 @@ pub const Type = extern union {
.anyerror_void_error_union,
.anyerror,
.error_set_inferred,
+ .error_set_merged,
=> return 2, // TODO revisit this when we have the concept of the error tag type
.int_signed, .int_unsigned => {
@@ -2199,6 +2230,7 @@ pub const Type = extern union {
.anyerror_void_error_union,
.anyerror,
.error_set_inferred,
+ .error_set_merged,
=> return 16, // TODO revisit this when we have the concept of the error tag type
.int_signed, .int_unsigned => self.cast(Payload.Bits).?.data,
@@ -2961,7 +2993,7 @@ pub const Type = extern union {
return .{ .signedness = .unsigned, .bits = smallestUnsignedBits(field_count - 1) };
},
- .error_set, .error_set_single, .anyerror, .error_set_inferred => {
+ .error_set, .error_set_single, .anyerror, .error_set_inferred, .error_set_merged => {
// TODO revisit this when error sets support custom int types
return .{ .signedness = .unsigned, .bits = 16 };
},
@@ -3250,6 +3282,7 @@ pub const Type = extern union {
.error_set,
.error_set_single,
.error_set_inferred,
+ .error_set_merged,
.@"opaque",
.var_args_param,
.manyptr_u8,
@@ -3882,6 +3915,7 @@ pub const Type = extern union {
error_set_single,
/// The type is the inferred error set of a specific function.
error_set_inferred,
+ error_set_merged,
empty_struct,
@"opaque",
@"struct",
@@ -3986,6 +4020,7 @@ pub const Type = extern union {
.error_set => Payload.ErrorSet,
.error_set_inferred => Payload.ErrorSetInferred,
+ .error_set_merged => Payload.ErrorSetMerged,
.array, .vector => Payload.Array,
.array_sentinel => Payload.ArraySentinel,
@@ -4090,6 +4125,13 @@ pub const Type = extern union {
data: *Module.ErrorSet,
};
+ pub const ErrorSetMerged = struct {
+ pub const base_tag = Tag.error_set_merged;
+
+ base: Payload = Payload{ .tag = base_tag },
+ data: []const []const u8,
+ };
+
pub const ErrorSetInferred = struct {
pub const base_tag = Tag.error_set_inferred;
@@ -4125,6 +4167,12 @@ pub const Type = extern union {
try self.map.put(gpa, entry.key_ptr.*, {});
}
},
+ .error_set_merged => {
+ const names = err_set_ty.castTag(.error_set_merged).?.data;
+ for (names) |name| {
+ try self.map.put(gpa, name, {});
+ }
+ },
.anyerror => {
self.is_anyerror = true;
},