diff --git a/src/Sema.zig b/src/Sema.zig index 998efadcef..adc0492446 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -10397,7 +10397,13 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai vals, ), ); - break :v try Value.Tag.decl_ref.create(sema.arena, new_decl); + + const new_decl_val = try Value.Tag.decl_ref.create(sema.arena, new_decl); + const slice_val = try Value.Tag.slice.create(sema.arena, .{ + .ptr = new_decl_val, + .len = try Value.Tag.int_u64.create(sema.arena, vals.len), + }); + break :v try Value.Tag.opt_payload.create(sema.arena, slice_val); } else Value.@"null"; // Construct TypeInfo{ .ErrorSet = errors_val } @@ -12317,7 +12323,31 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I }); return sema.addType(ty); }, - .ErrorSet => return sema.fail(block, src, "TODO: Sema.zirReify for ErrorSet", .{}), + .ErrorSet => { + const payload_val = union_val.val.optionalValue() orelse + return sema.addType(Type.initTag(.anyerror)); + const slice_val = payload_val.castTag(.slice).?.data; + const decl = slice_val.ptr.castTag(.decl_ref).?.data; + try sema.ensureDeclAnalyzed(decl); + const array_val = decl.val.castTag(.array).?.data; + + var names: Module.ErrorSet.NameMap = .{}; + try names.ensureUnusedCapacity(sema.arena, array_val.len); + for (array_val) |elem_val| { + const struct_val = elem_val.castTag(.@"struct").?.data; + // TODO use reflection instead of magic numbers here + // error_set: type, + const name_val = struct_val[0]; + + names.putAssumeCapacityNoClobber( + try name_val.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena), + {}, + ); + } + + const ty = try Type.Tag.error_set_merged.create(sema.arena, names); + return sema.addType(ty); + }, .Enum => return sema.fail(block, src, "TODO: Sema.zirReify for Enum", .{}), .Union => return sema.fail(block, src, "TODO: Sema.zirReify for Union", .{}), .Fn => return sema.fail(block, src, "TODO: Sema.zirReify for Fn", .{}), diff --git a/src/value.zig b/src/value.zig index d576074ba3..e667c566b9 100644 --- a/src/value.zig +++ b/src/value.zig @@ -2506,6 +2506,15 @@ pub const Value = extern union { }; } + /// Value of the optional, null if optional has no payload. + pub fn optionalValue(val: Value) ?Value { + if (val.isNull()) return null; + + // Valid for optional representation to be the direct value + // and not use opt_payload. + return if (val.castTag(.opt_payload)) |p| p.data else val; + } + /// Valid for all types. Asserts the value is not undefined. pub fn isFloat(self: Value) bool { return switch (self.tag()) { diff --git a/test/behavior/type.zig b/test/behavior/type.zig index eea4d7d203..43751ff4b7 100644 --- a/test/behavior/type.zig +++ b/test/behavior/type.zig @@ -240,12 +240,19 @@ fn add(a: i32, b: i32) i32 { } test "Type.ErrorSet" { - if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + try testing.expect(@Type(TypeInfo{ .ErrorSet = null }) == anyerror); // error sets don't compare equal so just check if they compile _ = @Type(@typeInfo(error{})); _ = @Type(@typeInfo(error{A})); _ = @Type(@typeInfo(error{ A, B, C })); + _ = @Type(TypeInfo{ + .ErrorSet = &[_]TypeInfo.Error{ + .{ .name = "A" }, + .{ .name = "B" }, + .{ .name = "C" }, + }, + }); } test "Type.Struct" {