stage2: reify error sets

This commit is contained in:
Mitchell Hashimoto 2022-03-01 17:09:03 -08:00 committed by Andrew Kelley
parent 65943010c7
commit 7deadf4301
3 changed files with 49 additions and 3 deletions

View File

@ -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", .{}),

View File

@ -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()) {

View File

@ -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" {