Skip to content

feat(t27b): plain enums as integer tags (Closes #6146) - #6254

Merged
gHashTag merged 2 commits into
masterfrom
claude/t27b-enums
Oct 4, 2026
Merged

gHashTag merged 2 commits into
masterfrom
claude/t27b-enums

Conversation

@gHashTag

@gHashTag gHashTag commented Oct 4, 2026

Copy link
Copy Markdown
Owner

Closes #6146. Stacked on #6249 (slices), which is stacked on #6247 (arrays).

What

  • enum E { .. } and const E = enum(T) { .. }, with and without explicit values. The tag type is mirrored from t27c's Zig backend:
    • enum(T) uses T;
    • no tag type but some explicit value uses i32;
    • otherwise the smallest unsigned type, as Zig picks it.
  • Enum values: E.v, E::v, and .v wherever an E is expected (args, returns, typed locals, struct fields, module constants, assert_eq, @as(E, .v)).
  • == and != compare tags. Ordering is accepted only where t27c writes @intFromEnum(a) < @intFromEnum(b) (one side E.v).
  • @intFromEnum, plus @as(T, x) in general.
  • @enumFromInt:
    • At runtime it range-checks and traps invalid enum value (TrapKind::EnumTag), as Zig's safety check does.
    • A constant that is no tag is rejected (a Zig compile error).
  • Clean rejects, each with its own construct:
    • EnumDecl(method), EnumDecl(non-exhaustive), EnumDecl(union) (for union(enum));
    • ExprSwitch (t27b has no switch yet);
    • ExprBinary(<) on enum for two enum values;
    • ExprEnumValue for .v with no result type;
    • a non-contiguous runtime @enumFromInt;
    • a runtime @intFromEnum of an auto-tagged (u2) enum used as a value (allowed in comparisons and where a wider integer is wanted).
  • No interpreter fallback and no skipped tests. The new run test asserts JIT == interpreter, including both EnumTag trap sites.

Corpus (t27b corpus specs, macOS arm64)

before after
pass 162 (938 tests) 165 (973 tests)
pass_vacuous 278 278
fail 2 2 (same files: build_verify.t27, viewport.t27)
rejected 763 760
JIT/interpreter mismatch 0 0
  • EnumDecl was the 📜 Canon Update: AGENTS_ALPHABET + AGENT_T_SKILL #1 first blocker (109 files) and is now gone from the list.
  • New top first blockers: BenchBlock 116, type f64 107, type f32 69, type ?T 47, std.mem.Allocator 44, type [N]T 39.
  • New passes, with the reference result:
    • AsmSectionKind_from_i8.t27: reference 8/8.
    • HirBusPort_axi4_lite_slave.t27: reference 23/23.
    • server/api.t27: the reference does not compile it, because an unused struct names an undeclared type. Zig catches that at AstGen; t27b lays out structs lazily, which predates this PR.
  • No new FAILs.

Reference (t27c Zig backend) bugs found

  • const D: Dir = .east; is emitted as const D: Dir;, so the value is dropped and the file fails with "variables must be initialized".
  • In a test block, var x: u8 = 1; x = f(x); is emitted with const x = f(x);, so zig fails with "redeclaration of local variable".

🤖 Generated with Claude Code

enum / enum(T) declarations with and without explicit values lower to
integer tags. E.v, E::v and .v (with a result type), == and != on tags,
ordering only where t27c writes @intFromEnum(a) < @intFromEnum(b),
@intFromEnum, @enumFromInt (runtime: traps "invalid enum value", like
Zig's safety check), @as(T, x), enum params, returns, fields, locals and
module constants.

Clean rejects with their own construct: EnumDecl(method),
EnumDecl(non-exhaustive), EnumDecl(union), ExprSwitch, ExprEnumValue.

corpus specs: pass 162 -> 165, pass_vacuous 278 -> 278, fail 2 -> 2,
rejected 763 -> 760, mismatch 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@gHashTag
gHashTag changed the base branch from claude/t27b-slices to master October 4, 2026 20:40
@gHashTag
gHashTag merged commit bc472e7 into master Oct 4, 2026
31 of 34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

t27b: lower plain enums to integer tags (first rejection in 89 specs)

1 participant