ERR/E3: error-tag {} interpolation via an always-linked tag-name table
`{}` on an error-set value printed `<?>` (any_to_string had no error_set
category). Now it renders the tag name (`BadDigit`), reusing the existing
any_to_string dispatch.
Pieces:
- New `error_tag_name_get` IR op (UnaryOp): tag id -> name. Lowered from a new
`error_tag_name(e) -> string #builtin` (std.sx). Handled across inst.zig
(op def), print.zig, interp.zig (comptime: tags.getName), and emit_llvm.zig.
- emit_llvm getOrBuildTagNameArray: an always-linked `[N x {ptr,i64}]` global
of tag names indexed by global tag id (the TagRegistry namespace, slot 0 =
""). error_tag_name_get zext's the u32 tag value and GEPs into it. Built once;
not trace-gated, so it works in release too (per the spec's "tag-name table
always shipped").
- resolveTypeCategoryTags gains an `error_set` category so the
`case error_set:` arm in any_to_string matches; that arm coerces the Any to
u32 (`xx val`) and calls error_tag_name. (cast(type) didn't recover the tag
id for error-set values; the u32 coercion does.)
examples/240-error-tag-interpolation.sx: bound tags + a catch-bound tag print
their names. Regenerated ffi-objc-call-06-sret-return.ir — pure block-renumber
drift from adding one if-arm to the shared any_to_string (verified
semantically identical after collapsing block numbers).
Gates: zig build, zig build test, bash tests/run_examples.sh (277 passed; lone
failure is the user's uncommitted 213-canonical-map pack WIP).
This commit is contained in:
@@ -10271,6 +10271,13 @@ pub const Lowering = struct {
|
||||
.struct_type = ty,
|
||||
} }, .string);
|
||||
}
|
||||
if (std.mem.eql(u8, name, "error_tag_name")) {
|
||||
// error_tag_name(e) → look the error-set value's runtime tag id up
|
||||
// in the always-linked tag-name table. The value IS its u32 tag id.
|
||||
if (c.args.len < 1) return self.builder.constString(self.module.types.internString(""));
|
||||
const e = self.lowerExpr(c.args[0]);
|
||||
return self.builder.emit(.{ .error_tag_name_get = .{ .operand = e } }, .string);
|
||||
}
|
||||
if (std.mem.eql(u8, name, "field_value")) {
|
||||
// field_value(s, i) → field_value_get instruction (structs/unions)
|
||||
// → index_get + box_any (slices/arrays)
|
||||
@@ -10892,7 +10899,7 @@ pub const Lowering = struct {
|
||||
}
|
||||
|
||||
// Dynamic categories: scan TypeTable for matching types
|
||||
const Category = enum { @"struct", @"enum", @"union", slice, array, pointer, vector, optional };
|
||||
const Category = enum { @"struct", @"enum", @"union", slice, array, pointer, vector, optional, error_set };
|
||||
const cat: ?Category = if (std.mem.eql(u8, name, "struct"))
|
||||
.@"struct"
|
||||
else if (std.mem.eql(u8, name, "enum") or std.mem.eql(u8, name, "union"))
|
||||
@@ -10907,6 +10914,8 @@ pub const Lowering = struct {
|
||||
.vector
|
||||
else if (std.mem.eql(u8, name, "optional"))
|
||||
.optional
|
||||
else if (std.mem.eql(u8, name, "error_set"))
|
||||
.error_set
|
||||
else
|
||||
null;
|
||||
|
||||
@@ -10921,6 +10930,7 @@ pub const Lowering = struct {
|
||||
.pointer => info == .pointer or info == .many_pointer,
|
||||
.vector => info == .vector,
|
||||
.optional => info == .optional,
|
||||
.error_set => info == .error_set,
|
||||
};
|
||||
if (matches) {
|
||||
tags.append(self.alloc, @intCast(idx)) catch {};
|
||||
@@ -13797,6 +13807,7 @@ pub const Lowering = struct {
|
||||
if (std.mem.eql(u8, bare_name, "field_count")) return .s64;
|
||||
if (std.mem.eql(u8, bare_name, "field_index")) return .s64;
|
||||
if (std.mem.eql(u8, bare_name, "field_name")) return .string;
|
||||
if (std.mem.eql(u8, bare_name, "error_tag_name")) return .string;
|
||||
if (std.mem.eql(u8, bare_name, "is_flags")) return .bool;
|
||||
if (std.mem.eql(u8, bare_name, "type_of")) return .any;
|
||||
if (std.mem.eql(u8, bare_name, "field_value")) return .any;
|
||||
|
||||
Reference in New Issue
Block a user