ERR/E1.1 (slice 1): error-set type + global tag registry + decl registration
First sema/types step. Implemented in the IR layer (ir/types.zig +
type_bridge.zig + lower.zig), NOT src/sema.zig — lowering doesn't consume
sema; the frontend Type is LSP-only. Mirrors how enums are handled.
- ir/types.zig: new `.error_set` TypeInfo kind (ErrorSetInfo {name, tags:
[]u32}; identity = name, like enum) with a u32 runtime layout (size/align
4, LLVM i32) per the locked error-slot ABI. New TagRegistry on TypeTable
(global tag pool: name -> u32, monotonic, id 0 reserved for "no error").
internTag/getTagName/errorSetType helpers; `.error_set` arms in all 7
exhaustive switches + findByName.
- emit_llvm: toLLVMTypeInfo -> i32. print: writeType -> set name.
- type_bridge: resolveInlineErrorSet (mirrors resolveInlineUnion) +
.error_set_decl arm.
- lower.zig: registerErrorSetDecl (rejects empty `error { }` with a
diagnostic) wired into both top-level decl switches + the block-local one.
- tests: ir/types.test (TagRegistry 0-reserved + identity; errorSetType u32
layout + named display + dedup; sorted storage) and ir/type_bridge.test
(decl -> type + tag interning + re-resolve dedup).
End-to-end: `Foo :: error { A, B }` + main compiles + runs (exit 0) — first
ERR syntax to survive the full pipeline; empty set rejects with a diagnostic.
Inferred bare `!`, error.X value, and == typing deferred to slice 2 / E1.2.
zig build, zig build test, and 254/254 examples green.
This commit is contained in:
@@ -194,3 +194,62 @@ test "pack type: formatTypeName" {
|
||||
const empty = table.packType(&.{});
|
||||
try std.testing.expectEqualStrings("pack()", table.formatTypeName(arena.allocator(), empty));
|
||||
}
|
||||
|
||||
// ── ERR E1.1 (Slice 1) — error sets + tag registry ──
|
||||
|
||||
test "TagRegistry interns tags, id 0 reserved, global identity" {
|
||||
const alloc = std.testing.allocator;
|
||||
var table = TypeTable.init(alloc);
|
||||
defer table.deinit();
|
||||
|
||||
const bad = table.internTag("BadDigit");
|
||||
const over = table.internTag("Overflow");
|
||||
const bad_again = table.internTag("BadDigit");
|
||||
|
||||
try std.testing.expect(bad >= 1); // id 0 reserved for "no error"
|
||||
try std.testing.expect(bad != over); // distinct names → distinct ids
|
||||
try std.testing.expectEqual(bad, bad_again); // same name → same id (global-flat)
|
||||
try std.testing.expectEqualStrings("BadDigit", table.getTagName(bad));
|
||||
try std.testing.expectEqualStrings("Overflow", table.getTagName(over));
|
||||
try std.testing.expectEqualStrings("", table.getTagName(0)); // reserved slot
|
||||
}
|
||||
|
||||
test "errorSetType: u32 layout, named display, dedup by name" {
|
||||
const alloc = std.testing.allocator;
|
||||
var table = TypeTable.init(alloc);
|
||||
defer table.deinit();
|
||||
|
||||
const name = table.internString("ParseErr");
|
||||
const tags = [_]u32{ table.internTag("BadDigit"), table.internTag("Overflow"), table.internTag("Empty") };
|
||||
const set = table.errorSetType(name, &tags);
|
||||
|
||||
// u32 runtime layout (the error channel's tag value).
|
||||
try std.testing.expectEqual(@as(u32, 4), table.sizeOf(set));
|
||||
try std.testing.expectEqual(@as(usize, 4), table.typeSizeBytes(set));
|
||||
try std.testing.expectEqual(@as(usize, 4), table.typeAlignBytes(set));
|
||||
// Displays by name; resolvable by name.
|
||||
try std.testing.expectEqualStrings("ParseErr", table.typeName(set));
|
||||
try std.testing.expectEqual(set, table.findByName(name).?);
|
||||
// Info shape.
|
||||
const info = table.get(set);
|
||||
try std.testing.expect(info == .error_set);
|
||||
try std.testing.expectEqual(@as(usize, 3), info.error_set.tags.len);
|
||||
// Identity is the name → re-constructing the same set dedups.
|
||||
try std.testing.expectEqual(set, table.errorSetType(name, &tags));
|
||||
}
|
||||
|
||||
test "errorSetType: tags stored sorted by global id" {
|
||||
const alloc = std.testing.allocator;
|
||||
var table = TypeTable.init(alloc);
|
||||
defer table.deinit();
|
||||
|
||||
const name = table.internString("E");
|
||||
const c = table.internTag("C");
|
||||
const a = table.internTag("A");
|
||||
const b = table.internTag("B");
|
||||
// Pass out of order; errorSetType sorts for canonical storage.
|
||||
const set = table.errorSetType(name, &[_]u32{ c, a, b });
|
||||
const stored = table.get(set).error_set.tags;
|
||||
try std.testing.expectEqual(@as(usize, 3), stored.len);
|
||||
try std.testing.expect(stored[0] <= stored[1] and stored[1] <= stored[2]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user